diff --git a/dist/epicenter.js b/dist/epicenter.js index 9d738415..bb8363e6 100644 --- a/dist/epicenter.js +++ b/dist/epicenter.js @@ -584,6 +584,13 @@ AuthManager.prototype = $.extend(AuthManager.prototype, { /** * Helper method to check if you're currently logged in + * + * **Example** + * + * var amILoggedIn = authMgr.isLoggedIn(); + * + * **Parameters** + * @param {none} none * @return {Boolean} true if you're logged in */ isLoggedIn: function () { @@ -2010,8 +2017,8 @@ var Strategy = classFrom(IdentityStrategy, { var filter = injectFiltersFromSession(this.options.filter, userSession); var me = this; return runService.query(filter, { - // startrecord: 0, //TODO: Uncomment when EPICENTER-2569 is fixed - // endrecord: 0, + startrecord: 0, + endrecord: 0, sort: 'created', direction: 'desc' }).then(function (runs) { @@ -2103,8 +2110,8 @@ module.exports = classFrom(Base, { var filter = $.extend(true, { trashed: false }, sessionFilter, { model: runopts.model }); var me = this; return runService.query(filter, { - // startrecord: 0, //TODO: Uncomment when EPICENTER-2569 is fixed - // endrecord: 0, + startrecord: 0, + endrecord: 0, sort: 'created', direction: 'desc' }).then(function (runs) { @@ -2665,13 +2672,13 @@ module.exports = classFrom(Base, { var runopts = runService.getCurrentConfig(); var filter = injectFiltersFromSession({ saved: false, - trashed: false, //TODO: change to '!=true' once EPICENTER-2500 is fixed, + trashed: false, model: runopts.model, }, userSession); var me = this; var outputModifiers = { - // startrecord: 0, //TODO: Uncomment when EPICENTER-2569 is fixed - // endrecord: 0, + startrecord: 0, + endrecord: 0, sort: 'created', direction: 'desc' }; @@ -5158,6 +5165,10 @@ module.exports = function (config) { /** * Removes specified runid from memory * + * **Example** + * + * rs.removeFromMemory('bb589677-d476-4971-a68e-0c58d191e450'); + * * See [details on run persistence](../../../run_persistence/#runs-in-memory) * @param {String} [runID] id of run to remove * @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`). @@ -7724,4 +7735,4 @@ module.exports = (function () { }()); },{"./query-util":53}]},{},[4]) -//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIm5vZGVfbW9kdWxlcy9icm93c2VyLXBhY2svX3ByZWx1ZGUuanMiLCJub2RlX21vZHVsZXMvQmFzZTY0L2Jhc2U2NC5qcyIsIm5vZGVfbW9kdWxlcy9vYmplY3QtYXNzaWduL2luZGV4LmpzIiwic3JjL2FwaS12ZXJzaW9uLmpzb24iLCJzcmMvYXBwLmpzIiwic3JjL2Vudi1sb2FkLmpzIiwic3JjL21hbmFnZXJzL2F1dGgtbWFuYWdlci5qcyIsInNyYy9tYW5hZ2Vycy9jaGFubmVsLW1hbmFnZXIuanMiLCJzcmMvbWFuYWdlcnMvZXBpY2VudGVyLWNoYW5uZWwtbWFuYWdlci5qcyIsInNyYy9tYW5hZ2Vycy9rZXktbmFtZXMuanMiLCJzcmMvbWFuYWdlcnMvcnVuLW1hbmFnZXIuanMiLCJzcmMvbWFuYWdlcnMvcnVuLXN0cmF0ZWdpZXMvY29uZGl0aW9uYWwtY3JlYXRpb24tc3RyYXRlZ3kuanMiLCJzcmMvbWFuYWdlcnMvcnVuLXN0cmF0ZWdpZXMvZGVwcmVjYXRlZC9uZXctaWYtaW5pdGlhbGl6ZWQtc3RyYXRlZ3kuanMiLCJzcmMvbWFuYWdlcnMvcnVuLXN0cmF0ZWdpZXMvZGVwcmVjYXRlZC9uZXctaWYtcGVyc2lzdGVkLXN0cmF0ZWd5LmpzIiwic3JjL21hbmFnZXJzL3J1bi1zdHJhdGVnaWVzL2luZGV4LmpzIiwic3JjL21hbmFnZXJzL3J1bi1zdHJhdGVnaWVzL211bHRpcGxheWVyLXN0cmF0ZWd5LmpzIiwic3JjL21hbmFnZXJzL3J1bi1zdHJhdGVnaWVzL25vbmUtc3RyYXRlZ3kuanMiLCJzcmMvbWFuYWdlcnMvcnVuLXN0cmF0ZWdpZXMvcmV1c2UtYWNyb3NzLXNlc3Npb25zLmpzIiwic3JjL21hbmFnZXJzL3J1bi1zdHJhdGVnaWVzL3JldXNlLWxhc3QtaW5pdGlhbGl6ZWQuanMiLCJzcmMvbWFuYWdlcnMvcnVuLXN0cmF0ZWdpZXMvcmV1c2UtbmV2ZXIuanMiLCJzcmMvbWFuYWdlcnMvcnVuLXN0cmF0ZWdpZXMvcmV1c2UtcGVyLXNlc3Npb24uanMiLCJzcmMvbWFuYWdlcnMvc2F2ZWQtcnVucy1tYW5hZ2VyLmpzIiwic3JjL21hbmFnZXJzL3NjZW5hcmlvLW1hbmFnZXIuanMiLCJzcmMvbWFuYWdlcnMvc2NlbmFyaW8tc3RyYXRlZ2llcy9iYXNlbGluZS1zdHJhdGVneS5qcyIsInNyYy9tYW5hZ2Vycy9zY2VuYXJpby1zdHJhdGVnaWVzL3JldXNlLWxhc3QtdW5zYXZlZC5qcyIsInNyYy9tYW5hZ2Vycy9zcGVjaWFsLW9wZXJhdGlvbnMuanMiLCJzcmMvbWFuYWdlcnMvc3RyYXRlZ3ktdXRpbHMuanMiLCJzcmMvbWFuYWdlcnMvd29ybGQtbWFuYWdlci5qcyIsInNyYy9zZXJ2aWNlL2FkbWluLWZpbGUtc2VydmljZS5qcyIsInNyYy9zZXJ2aWNlL2Fzc2V0LWFwaS1hZGFwdGVyLmpzIiwic3JjL3NlcnZpY2UvYXV0aC1hcGktc2VydmljZS5qcyIsInNyYy9zZXJ2aWNlL2NoYW5uZWwtc2VydmljZS5qcyIsInNyYy9zZXJ2aWNlL2NvbmZpZ3VyYXRpb24tc2VydmljZS5qcyIsInNyYy9zZXJ2aWNlL2RhdGEtYXBpLXNlcnZpY2UuanMiLCJzcmMvc2VydmljZS9ncm91cC1hcGktc2VydmljZS5qcyIsInNyYy9zZXJ2aWNlL2ludHJvc3BlY3Rpb24tYXBpLXNlcnZpY2UuanMiLCJzcmMvc2VydmljZS9tZW1iZXItYXBpLWFkYXB0ZXIuanMiLCJzcmMvc2VydmljZS9wcmVzZW5jZS1hcGktc2VydmljZS5qcyIsInNyYy9zZXJ2aWNlL3J1bi1hcGktc2VydmljZS5qcyIsInNyYy9zZXJ2aWNlL3NlcnZpY2UtdXRpbHMuanMiLCJzcmMvc2VydmljZS9zdGF0ZS1hcGktYWRhcHRlci5qcyIsInNyYy9zZXJ2aWNlL3VybC1jb25maWctc2VydmljZS5qcyIsInNyYy9zZXJ2aWNlL3VzZXItYXBpLWFkYXB0ZXIuanMiLCJzcmMvc2VydmljZS92YXJpYWJsZXMtYXBpLXNlcnZpY2UuanMiLCJzcmMvc2VydmljZS93b3JsZC1hcGktYWRhcHRlci5qcyIsInNyYy9zdG9yZS9jb29raWUtc3RvcmUuanMiLCJzcmMvc3RvcmUvc2Vzc2lvbi1tYW5hZ2VyLmpzIiwic3JjL3N0b3JlL3N0b3JlLWZhY3RvcnkuanMiLCJzcmMvdHJhbnNwb3J0L2FqYXgtaHR0cC10cmFuc3BvcnQuanMiLCJzcmMvdHJhbnNwb3J0L2h0dHAtdHJhbnNwb3J0LWZhY3RvcnkuanMiLCJzcmMvdXRpbC9pbmhlcml0LmpzIiwic3JjL3V0aWwvb2JqZWN0LXV0aWwuanMiLCJzcmMvdXRpbC9vcHRpb24tdXRpbHMuanMiLCJzcmMvdXRpbC9xdWVyeS11dGlsLmpzIiwic3JjL3V0aWwvcnVuLXV0aWwuanMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7QUNBQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzdEQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDbkZBO0FBQ0E7QUFDQTtBQUNBOzs7QUNIQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7Ozs7QUN2RUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNoQkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDclpBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDaFFBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDcmFBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNMQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUMxT0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ2hGQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNwQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDdkNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDbkhBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzNFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUMzQkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDL0RBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDeEZBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUM3QkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUN4Q0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUMxSkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDMU9BO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDckNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUM5REE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ1JBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDeENBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDaEtBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUM5TUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDMVhBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3hIQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ2pQQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUN4RUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDaFNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3hFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNwSUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzVMQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzVOQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzVsQkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDdkNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDdkpBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3BJQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDM0pBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDdEtBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUM1dkJBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ2hKQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDbklBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDVkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzNHQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNOQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3ZEQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDakJBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUN6Q0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDL0dBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBIiwiZmlsZSI6ImdlbmVyYXRlZC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzQ29udGVudCI6WyIoZnVuY3Rpb24gZSh0LG4scil7ZnVuY3Rpb24gcyhvLHUpe2lmKCFuW29dKXtpZighdFtvXSl7dmFyIGE9dHlwZW9mIHJlcXVpcmU9PVwiZnVuY3Rpb25cIiYmcmVxdWlyZTtpZighdSYmYSlyZXR1cm4gYShvLCEwKTtpZihpKXJldHVybiBpKG8sITApO3ZhciBmPW5ldyBFcnJvcihcIkNhbm5vdCBmaW5kIG1vZHVsZSAnXCIrbytcIidcIik7dGhyb3cgZi5jb2RlPVwiTU9EVUxFX05PVF9GT1VORFwiLGZ9dmFyIGw9bltvXT17ZXhwb3J0czp7fX07dFtvXVswXS5jYWxsKGwuZXhwb3J0cyxmdW5jdGlvbihlKXt2YXIgbj10W29dWzFdW2VdO3JldHVybiBzKG4/bjplKX0sbCxsLmV4cG9ydHMsZSx0LG4scil9cmV0dXJuIG5bb10uZXhwb3J0c312YXIgaT10eXBlb2YgcmVxdWlyZT09XCJmdW5jdGlvblwiJiZyZXF1aXJlO2Zvcih2YXIgbz0wO288ci5sZW5ndGg7bysrKXMocltvXSk7cmV0dXJuIHN9KSIsIjsoZnVuY3Rpb24gKCkge1xuXG4gIHZhciBvYmplY3QgPSB0eXBlb2YgZXhwb3J0cyAhPSAndW5kZWZpbmVkJyA/IGV4cG9ydHMgOiBzZWxmOyAvLyAjODogd2ViIHdvcmtlcnNcbiAgdmFyIGNoYXJzID0gJ0FCQ0RFRkdISUpLTE1OT1BRUlNUVVZXWFlaYWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXowMTIzNDU2Nzg5Ky89JztcblxuICBmdW5jdGlvbiBJbnZhbGlkQ2hhcmFjdGVyRXJyb3IobWVzc2FnZSkge1xuICAgIHRoaXMubWVzc2FnZSA9IG1lc3NhZ2U7XG4gIH1cbiAgSW52YWxpZENoYXJhY3RlckVycm9yLnByb3RvdHlwZSA9IG5ldyBFcnJvcjtcbiAgSW52YWxpZENoYXJhY3RlckVycm9yLnByb3RvdHlwZS5uYW1lID0gJ0ludmFsaWRDaGFyYWN0ZXJFcnJvcic7XG5cbiAgLy8gZW5jb2RlclxuICAvLyBbaHR0cHM6Ly9naXN0LmdpdGh1Yi5jb20vOTk5MTY2XSBieSBbaHR0cHM6Ly9naXRodWIuY29tL25pZ25hZ11cbiAgb2JqZWN0LmJ0b2EgfHwgKFxuICBvYmplY3QuYnRvYSA9IGZ1bmN0aW9uIChpbnB1dCkge1xuICAgIHZhciBzdHIgPSBTdHJpbmcoaW5wdXQpO1xuICAgIGZvciAoXG4gICAgICAvLyBpbml0aWFsaXplIHJlc3VsdCBhbmQgY291bnRlclxuICAgICAgdmFyIGJsb2NrLCBjaGFyQ29kZSwgaWR4ID0gMCwgbWFwID0gY2hhcnMsIG91dHB1dCA9ICcnO1xuICAgICAgLy8gaWYgdGhlIG5leHQgc3RyIGluZGV4IGRvZXMgbm90IGV4aXN0OlxuICAgICAgLy8gICBjaGFuZ2UgdGhlIG1hcHBpbmcgdGFibGUgdG8gXCI9XCJcbiAgICAgIC8vICAgY2hlY2sgaWYgZCBoYXMgbm8gZnJhY3Rpb25hbCBkaWdpdHNcbiAgICAgIHN0ci5jaGFyQXQoaWR4IHwgMCkgfHwgKG1hcCA9ICc9JywgaWR4ICUgMSk7XG4gICAgICAvLyBcIjggLSBpZHggJSAxICogOFwiIGdlbmVyYXRlcyB0aGUgc2VxdWVuY2UgMiwgNCwgNiwgOFxuICAgICAgb3V0cHV0ICs9IG1hcC5jaGFyQXQoNjMgJiBibG9jayA+PiA4IC0gaWR4ICUgMSAqIDgpXG4gICAgKSB7XG4gICAgICBjaGFyQ29kZSA9IHN0ci5jaGFyQ29kZUF0KGlkeCArPSAzLzQpO1xuICAgICAgaWYgKGNoYXJDb2RlID4gMHhGRikge1xuICAgICAgICB0aHJvdyBuZXcgSW52YWxpZENoYXJhY3RlckVycm9yKFwiJ2J0b2EnIGZhaWxlZDogVGhlIHN0cmluZyB0byBiZSBlbmNvZGVkIGNvbnRhaW5zIGNoYXJhY3RlcnMgb3V0c2lkZSBvZiB0aGUgTGF0aW4xIHJhbmdlLlwiKTtcbiAgICAgIH1cbiAgICAgIGJsb2NrID0gYmxvY2sgPDwgOCB8IGNoYXJDb2RlO1xuICAgIH1cbiAgICByZXR1cm4gb3V0cHV0O1xuICB9KTtcblxuICAvLyBkZWNvZGVyXG4gIC8vIFtodHRwczovL2dpc3QuZ2l0aHViLmNvbS8xMDIwMzk2XSBieSBbaHR0cHM6Ly9naXRodWIuY29tL2F0a11cbiAgb2JqZWN0LmF0b2IgfHwgKFxuICBvYmplY3QuYXRvYiA9IGZ1bmN0aW9uIChpbnB1dCkge1xuICAgIHZhciBzdHIgPSBTdHJpbmcoaW5wdXQpLnJlcGxhY2UoLz0rJC8sICcnKTtcbiAgICBpZiAoc3RyLmxlbmd0aCAlIDQgPT0gMSkge1xuICAgICAgdGhyb3cgbmV3IEludmFsaWRDaGFyYWN0ZXJFcnJvcihcIidhdG9iJyBmYWlsZWQ6IFRoZSBzdHJpbmcgdG8gYmUgZGVjb2RlZCBpcyBub3QgY29ycmVjdGx5IGVuY29kZWQuXCIpO1xuICAgIH1cbiAgICBmb3IgKFxuICAgICAgLy8gaW5pdGlhbGl6ZSByZXN1bHQgYW5kIGNvdW50ZXJzXG4gICAgICB2YXIgYmMgPSAwLCBicywgYnVmZmVyLCBpZHggPSAwLCBvdXRwdXQgPSAnJztcbiAgICAgIC8vIGdldCBuZXh0IGNoYXJhY3RlclxuICAgICAgYnVmZmVyID0gc3RyLmNoYXJBdChpZHgrKyk7XG4gICAgICAvLyBjaGFyYWN0ZXIgZm91bmQgaW4gdGFibGU/IGluaXRpYWxpemUgYml0IHN0b3JhZ2UgYW5kIGFkZCBpdHMgYXNjaWkgdmFsdWU7XG4gICAgICB+YnVmZmVyICYmIChicyA9IGJjICUgNCA/IGJzICogNjQgKyBidWZmZXIgOiBidWZmZXIsXG4gICAgICAgIC8vIGFuZCBpZiBub3QgZmlyc3Qgb2YgZWFjaCA0IGNoYXJhY3RlcnMsXG4gICAgICAgIC8vIGNvbnZlcnQgdGhlIGZpcnN0IDggYml0cyB0byBvbmUgYXNjaWkgY2hhcmFjdGVyXG4gICAgICAgIGJjKysgJSA0KSA/IG91dHB1dCArPSBTdHJpbmcuZnJvbUNoYXJDb2RlKDI1NSAmIGJzID4+ICgtMiAqIGJjICYgNikpIDogMFxuICAgICkge1xuICAgICAgLy8gdHJ5IHRvIGZpbmQgY2hhcmFjdGVyIGluIHRhYmxlICgwLTYzLCBub3QgZm91bmQgPT4gLTEpXG4gICAgICBidWZmZXIgPSBjaGFycy5pbmRleE9mKGJ1ZmZlcik7XG4gICAgfVxuICAgIHJldHVybiBvdXRwdXQ7XG4gIH0pO1xuXG59KCkpO1xuIiwiJ3VzZSBzdHJpY3QnO1xuLyogZXNsaW50LWRpc2FibGUgbm8tdW51c2VkLXZhcnMgKi9cbnZhciBoYXNPd25Qcm9wZXJ0eSA9IE9iamVjdC5wcm90b3R5cGUuaGFzT3duUHJvcGVydHk7XG52YXIgcHJvcElzRW51bWVyYWJsZSA9IE9iamVjdC5wcm90b3R5cGUucHJvcGVydHlJc0VudW1lcmFibGU7XG5cbmZ1bmN0aW9uIHRvT2JqZWN0KHZhbCkge1xuXHRpZiAodmFsID09PSBudWxsIHx8IHZhbCA9PT0gdW5kZWZpbmVkKSB7XG5cdFx0dGhyb3cgbmV3IFR5cGVFcnJvcignT2JqZWN0LmFzc2lnbiBjYW5ub3QgYmUgY2FsbGVkIHdpdGggbnVsbCBvciB1bmRlZmluZWQnKTtcblx0fVxuXG5cdHJldHVybiBPYmplY3QodmFsKTtcbn1cblxuZnVuY3Rpb24gc2hvdWxkVXNlTmF0aXZlKCkge1xuXHR0cnkge1xuXHRcdGlmICghT2JqZWN0LmFzc2lnbikge1xuXHRcdFx0cmV0dXJuIGZhbHNlO1xuXHRcdH1cblxuXHRcdC8vIERldGVjdCBidWdneSBwcm9wZXJ0eSBlbnVtZXJhdGlvbiBvcmRlciBpbiBvbGRlciBWOCB2ZXJzaW9ucy5cblxuXHRcdC8vIGh0dHBzOi8vYnVncy5jaHJvbWl1bS5vcmcvcC92OC9pc3N1ZXMvZGV0YWlsP2lkPTQxMThcblx0XHR2YXIgdGVzdDEgPSBuZXcgU3RyaW5nKCdhYmMnKTsgIC8vIGVzbGludC1kaXNhYmxlLWxpbmVcblx0XHR0ZXN0MVs1XSA9ICdkZSc7XG5cdFx0aWYgKE9iamVjdC5nZXRPd25Qcm9wZXJ0eU5hbWVzKHRlc3QxKVswXSA9PT0gJzUnKSB7XG5cdFx0XHRyZXR1cm4gZmFsc2U7XG5cdFx0fVxuXG5cdFx0Ly8gaHR0cHM6Ly9idWdzLmNocm9taXVtLm9yZy9wL3Y4L2lzc3Vlcy9kZXRhaWw/aWQ9MzA1NlxuXHRcdHZhciB0ZXN0MiA9IHt9O1xuXHRcdGZvciAodmFyIGkgPSAwOyBpIDwgMTA7IGkrKykge1xuXHRcdFx0dGVzdDJbJ18nICsgU3RyaW5nLmZyb21DaGFyQ29kZShpKV0gPSBpO1xuXHRcdH1cblx0XHR2YXIgb3JkZXIyID0gT2JqZWN0LmdldE93blByb3BlcnR5TmFtZXModGVzdDIpLm1hcChmdW5jdGlvbiAobikge1xuXHRcdFx0cmV0dXJuIHRlc3QyW25dO1xuXHRcdH0pO1xuXHRcdGlmIChvcmRlcjIuam9pbignJykgIT09ICcwMTIzNDU2Nzg5Jykge1xuXHRcdFx0cmV0dXJuIGZhbHNlO1xuXHRcdH1cblxuXHRcdC8vIGh0dHBzOi8vYnVncy5jaHJvbWl1bS5vcmcvcC92OC9pc3N1ZXMvZGV0YWlsP2lkPTMwNTZcblx0XHR2YXIgdGVzdDMgPSB7fTtcblx0XHQnYWJjZGVmZ2hpamtsbW5vcHFyc3QnLnNwbGl0KCcnKS5mb3JFYWNoKGZ1bmN0aW9uIChsZXR0ZXIpIHtcblx0XHRcdHRlc3QzW2xldHRlcl0gPSBsZXR0ZXI7XG5cdFx0fSk7XG5cdFx0aWYgKE9iamVjdC5rZXlzKE9iamVjdC5hc3NpZ24oe30sIHRlc3QzKSkuam9pbignJykgIT09XG5cdFx0XHRcdCdhYmNkZWZnaGlqa2xtbm9wcXJzdCcpIHtcblx0XHRcdHJldHVybiBmYWxzZTtcblx0XHR9XG5cblx0XHRyZXR1cm4gdHJ1ZTtcblx0fSBjYXRjaCAoZSkge1xuXHRcdC8vIFdlIGRvbid0IGV4cGVjdCBhbnkgb2YgdGhlIGFib3ZlIHRvIHRocm93LCBidXQgYmV0dGVyIHRvIGJlIHNhZmUuXG5cdFx0cmV0dXJuIGZhbHNlO1xuXHR9XG59XG5cbm1vZHVsZS5leHBvcnRzID0gc2hvdWxkVXNlTmF0aXZlKCkgPyBPYmplY3QuYXNzaWduIDogZnVuY3Rpb24gKHRhcmdldCwgc291cmNlKSB7XG5cdHZhciBmcm9tO1xuXHR2YXIgdG8gPSB0b09iamVjdCh0YXJnZXQpO1xuXHR2YXIgc3ltYm9scztcblxuXHRmb3IgKHZhciBzID0gMTsgcyA8IGFyZ3VtZW50cy5sZW5ndGg7IHMrKykge1xuXHRcdGZyb20gPSBPYmplY3QoYXJndW1lbnRzW3NdKTtcblxuXHRcdGZvciAodmFyIGtleSBpbiBmcm9tKSB7XG5cdFx0XHRpZiAoaGFzT3duUHJvcGVydHkuY2FsbChmcm9tLCBrZXkpKSB7XG5cdFx0XHRcdHRvW2tleV0gPSBmcm9tW2tleV07XG5cdFx0XHR9XG5cdFx0fVxuXG5cdFx0aWYgKE9iamVjdC5nZXRPd25Qcm9wZXJ0eVN5bWJvbHMpIHtcblx0XHRcdHN5bWJvbHMgPSBPYmplY3QuZ2V0T3duUHJvcGVydHlTeW1ib2xzKGZyb20pO1xuXHRcdFx0Zm9yICh2YXIgaSA9IDA7IGkgPCBzeW1ib2xzLmxlbmd0aDsgaSsrKSB7XG5cdFx0XHRcdGlmIChwcm9wSXNFbnVtZXJhYmxlLmNhbGwoZnJvbSwgc3ltYm9sc1tpXSkpIHtcblx0XHRcdFx0XHR0b1tzeW1ib2xzW2ldXSA9IGZyb21bc3ltYm9sc1tpXV07XG5cdFx0XHRcdH1cblx0XHRcdH1cblx0XHR9XG5cdH1cblxuXHRyZXR1cm4gdG87XG59O1xuIiwibW9kdWxlLmV4cG9ydHM9e1xuICAgIFwidmVyc2lvblwiOiBcInYyXCJcbn1cbiIsIi8qKlxuICogRXBpY2VudGVyIEphdmFzY3JpcHQgbGlicmFyaWVzXG4gKiB2PCU9IHZlcnNpb24gJT5cbiAqIGh0dHBzOi8vZ2l0aHViLmNvbS9mb3Jpby9lcGljZW50ZXItanMtbGlic1xuICovXG5cbnZhciBGID0ge1xuICAgIF9wcml2YXRlOiB7fSwgLy9uZWVkIHRoaXMgaG9vayBub3cgYmVjYXVzZSB0ZXN0cyBleHBlY3QgZXZlcnl0aGluZyB0byBiZSBnbG9iYWwuIERlbGV0ZSBvbmNlIHRlc3RzIGFyZSBicm93c2VyaWZpZWRcbiAgICB1dGlsOiB7fSxcbiAgICBmYWN0b3J5OiB7fSxcbiAgICB0cmFuc3BvcnQ6IHt9LFxuICAgIHN0b3JlOiB7fSxcbiAgICBzZXJ2aWNlOiB7fSxcbiAgICBtYW5hZ2VyOiB7XG4gICAgICAgIHN0cmF0ZWd5OiB7fVxuICAgIH0sXG5cbn07XG5cbkYubG9hZCA9IHJlcXVpcmUoJy4vZW52LWxvYWQnKTtcblxuaWYgKCFnbG9iYWwuU0tJUF9FTlZfTE9BRCkge1xuICAgIEYubG9hZCgpO1xufVxuXG5GLnV0aWwucXVlcnkgPSByZXF1aXJlKCcuL3V0aWwvcXVlcnktdXRpbCcpO1xuRi51dGlsLnJ1biA9IHJlcXVpcmUoJy4vdXRpbC9ydW4tdXRpbCcpO1xuRi51dGlsLmNsYXNzRnJvbSA9IHJlcXVpcmUoJy4vdXRpbC9pbmhlcml0Jyk7XG5GLl9wcml2YXRlLnN0cmF0ZWd5dXRpbHMgPSByZXF1aXJlKCcuL21hbmFnZXJzL3N0cmF0ZWd5LXV0aWxzJyk7XG5cbkYuZmFjdG9yeS5UcmFuc3BvcnQgPSByZXF1aXJlKCcuL3RyYW5zcG9ydC9odHRwLXRyYW5zcG9ydC1mYWN0b3J5Jyk7XG5GLnRyYW5zcG9ydC5BamF4ID0gcmVxdWlyZSgnLi90cmFuc3BvcnQvYWpheC1odHRwLXRyYW5zcG9ydCcpO1xuXG5GLnNlcnZpY2UuVVJMID0gcmVxdWlyZSgnLi9zZXJ2aWNlL3VybC1jb25maWctc2VydmljZScpO1xuRi5zZXJ2aWNlLkNvbmZpZyA9IHJlcXVpcmUoJy4vc2VydmljZS9jb25maWd1cmF0aW9uLXNlcnZpY2UnKTtcbkYuc2VydmljZS5SdW4gPSByZXF1aXJlKCcuL3NlcnZpY2UvcnVuLWFwaS1zZXJ2aWNlJyk7XG5GLnNlcnZpY2UuRmlsZSA9IHJlcXVpcmUoJy4vc2VydmljZS9hZG1pbi1maWxlLXNlcnZpY2UnKTtcbkYuc2VydmljZS5WYXJpYWJsZXMgPSByZXF1aXJlKCcuL3NlcnZpY2UvdmFyaWFibGVzLWFwaS1zZXJ2aWNlJyk7XG5GLnNlcnZpY2UuRGF0YSA9IHJlcXVpcmUoJy4vc2VydmljZS9kYXRhLWFwaS1zZXJ2aWNlJyk7XG5GLnNlcnZpY2UuQXV0aCA9IHJlcXVpcmUoJy4vc2VydmljZS9hdXRoLWFwaS1zZXJ2aWNlJyk7XG5GLnNlcnZpY2UuV29ybGQgPSByZXF1aXJlKCcuL3NlcnZpY2Uvd29ybGQtYXBpLWFkYXB0ZXInKTtcbkYuc2VydmljZS5TdGF0ZSA9IHJlcXVpcmUoJy4vc2VydmljZS9zdGF0ZS1hcGktYWRhcHRlcicpO1xuRi5zZXJ2aWNlLlVzZXIgPSByZXF1aXJlKCcuL3NlcnZpY2UvdXNlci1hcGktYWRhcHRlcicpO1xuRi5zZXJ2aWNlLk1lbWJlciA9IHJlcXVpcmUoJy4vc2VydmljZS9tZW1iZXItYXBpLWFkYXB0ZXInKTtcbkYuc2VydmljZS5Bc3NldCA9IHJlcXVpcmUoJy4vc2VydmljZS9hc3NldC1hcGktYWRhcHRlcicpO1xuRi5zZXJ2aWNlLkdyb3VwID0gcmVxdWlyZSgnLi9zZXJ2aWNlL2dyb3VwLWFwaS1zZXJ2aWNlJyk7XG5GLnNlcnZpY2UuSW50cm9zcGVjdCA9IHJlcXVpcmUoJy4vc2VydmljZS9pbnRyb3NwZWN0aW9uLWFwaS1zZXJ2aWNlJyk7XG5GLnNlcnZpY2UuUHJlc2VuY2UgPSByZXF1aXJlKCcuL3NlcnZpY2UvcHJlc2VuY2UtYXBpLXNlcnZpY2UnKTtcblxuRi5zdG9yZS5Db29raWUgPSByZXF1aXJlKCcuL3N0b3JlL2Nvb2tpZS1zdG9yZScpO1xuRi5mYWN0b3J5LlN0b3JlID0gcmVxdWlyZSgnLi9zdG9yZS9zdG9yZS1mYWN0b3J5Jyk7XG5cbkYubWFuYWdlci5TY2VuYXJpb01hbmFnZXIgPSByZXF1aXJlKCcuL21hbmFnZXJzL3NjZW5hcmlvLW1hbmFnZXInKTtcbkYubWFuYWdlci5SdW5NYW5hZ2VyID0gcmVxdWlyZSgnLi9tYW5hZ2Vycy9ydW4tbWFuYWdlcicpO1xuRi5tYW5hZ2VyLkF1dGhNYW5hZ2VyID0gcmVxdWlyZSgnLi9tYW5hZ2Vycy9hdXRoLW1hbmFnZXInKTtcbkYubWFuYWdlci5Xb3JsZE1hbmFnZXIgPSByZXF1aXJlKCcuL21hbmFnZXJzL3dvcmxkLW1hbmFnZXInKTtcbkYubWFuYWdlci5TYXZlZFJ1bnNNYW5hZ2VyID0gcmVxdWlyZSgnLi9tYW5hZ2Vycy9zYXZlZC1ydW5zLW1hbmFnZXInKTtcblxudmFyIHN0cmF0ZWdpZXMgPSByZXF1aXJlKCcuL21hbmFnZXJzL3J1bi1zdHJhdGVnaWVzJyk7XG5GLm1hbmFnZXIuc3RyYXRlZ3kgPSBzdHJhdGVnaWVzLmxpc3Q7IC8vVE9ETzogdGhpcyBpcyBub3QgcmVhbGx5IGEgbWFuYWdlciBzbyBuYW1lc3BhY2UgdGhpcyBiZXR0ZXJcblxuRi5tYW5hZ2VyLkNoYW5uZWxNYW5hZ2VyID0gcmVxdWlyZSgnLi9tYW5hZ2Vycy9lcGljZW50ZXItY2hhbm5lbC1tYW5hZ2VyJyk7XG5GLnNlcnZpY2UuQ2hhbm5lbCA9IHJlcXVpcmUoJy4vc2VydmljZS9jaGFubmVsLXNlcnZpY2UnKTtcblxuRi52ZXJzaW9uID0gJzwlPSB2ZXJzaW9uICU+JztcbkYuYXBpID0gcmVxdWlyZSgnLi9hcGktdmVyc2lvbi5qc29uJyk7XG5cbkYuY29uc3RhbnRzID0gcmVxdWlyZSgnLi9tYW5hZ2Vycy9rZXktbmFtZXMnKTtcblxuZ2xvYmFsLkYgPSBGO1xubW9kdWxlLmV4cG9ydHMgPSBGO1xuIiwiJ3VzZSBzdHJpY3QnO1xuXG52YXIgVVJMQ29uZmlnU2VydmljZSA9IHJlcXVpcmUoJy4vc2VydmljZS91cmwtY29uZmlnLXNlcnZpY2UnKTtcblxudmFyIGVudkxvYWQgPSBmdW5jdGlvbiAoY2FsbGJhY2spIHtcbiAgICB2YXIgdXJsU2VydmljZSA9IG5ldyBVUkxDb25maWdTZXJ2aWNlKCk7XG4gICAgdmFyIGluZm9VcmwgPSB1cmxTZXJ2aWNlLmdldEFQSVBhdGgoJ2NvbmZpZycpO1xuICAgIHZhciBlbnZQcm9taXNlID0gJC5hamF4KHsgdXJsOiBpbmZvVXJsLCBhc3luYzogZmFsc2UgfSk7XG4gICAgZW52UHJvbWlzZSA9IGVudlByb21pc2UudGhlbihmdW5jdGlvbiAocmVzKSB7XG4gICAgICAgIHZhciBvdmVycmlkZXMgPSByZXMuYXBpO1xuICAgICAgICBVUkxDb25maWdTZXJ2aWNlLmRlZmF1bHRzID0gJC5leHRlbmQoVVJMQ29uZmlnU2VydmljZS5kZWZhdWx0cywgb3ZlcnJpZGVzKTtcbiAgICB9KTtcbiAgICByZXR1cm4gZW52UHJvbWlzZS50aGVuKGNhbGxiYWNrKS5mYWlsKGNhbGxiYWNrKTtcbn07XG5cbm1vZHVsZS5leHBvcnRzID0gZW52TG9hZDtcbiIsIi8qKlxuKiAjIyBBdXRob3JpemF0aW9uIE1hbmFnZXJcbipcbiogVGhlIEF1dGhvcml6YXRpb24gTWFuYWdlciBwcm92aWRlcyBhbiBlYXN5IHdheSB0byBtYW5hZ2UgdXNlciBhdXRoZW50aWNhdGlvbiAobG9nZ2luZyBpbiBhbmQgb3V0KSBhbmQgYXV0aG9yaXphdGlvbiAoa2VlcGluZyB0cmFjayBvZiB0b2tlbnMsIHNlc3Npb25zLCBhbmQgZ3JvdXBzKSBmb3IgcHJvamVjdHMuXG4qXG4qIFRoZSBBdXRob3JpemF0aW9uIE1hbmFnZXIgaXMgbW9zdCB1c2VmdWwgZm9yIFt0ZWFtIHByb2plY3RzXSguLi8uLi8uLi9nbG9zc2FyeS8jdGVhbSkgd2l0aCBhbiBhY2Nlc3MgbGV2ZWwgb2YgW0F1dGhlbnRpY2F0ZWRdKC4uLy4uLy4uL2dsb3NzYXJ5LyNhY2Nlc3MpLiBUaGVzZSBwcm9qZWN0cyBhcmUgYWNjZXNzZWQgYnkgW2VuZCB1c2Vyc10oLi4vLi4vLi4vZ2xvc3NhcnkvI3VzZXJzKSB3aG8gYXJlIG1lbWJlcnMgb2Ygb25lIG9yIG1vcmUgW2dyb3Vwc10oLi4vLi4vLi4vZ2xvc3NhcnkvI2dyb3VwcykuXG4qXG4qICMjIyMgVXNpbmcgdGhlIEF1dGhvcml6YXRpb24gTWFuYWdlclxuKlxuKiBUbyB1c2UgdGhlIEF1dGhvcml6YXRpb24gTWFuYWdlciwgaW5zdGFudGlhdGUgaXQuIFRoZW4sIG1ha2UgY2FsbHMgdG8gYW55IG9mIHRoZSBtZXRob2RzIHlvdSBuZWVkOlxuKlxuKiAgICAgICB2YXIgYXV0aE1nciA9IG5ldyBGLm1hbmFnZXIuQXV0aE1hbmFnZXIoe1xuKiAgICAgICAgICAgYWNjb3VudDogJ2FjbWUtc2ltdWxhdGlvbnMnLFxuKiAgICAgICAgICAgdXNlck5hbWU6ICdlbmR1c2VyMScsXG4qICAgICAgICAgICBwYXNzd29yZDogJ3Bhc3N3MHJkJ1xuKiAgICAgICB9KTtcbiogICAgICAgYXV0aE1nci5sb2dpbigpLnRoZW4oZnVuY3Rpb24gKCkge1xuKiAgICAgICAgICAgYXV0aE1nci5nZXRDdXJyZW50VXNlclNlc3Npb25JbmZvKCk7XG4qICAgICAgIH0pO1xuKlxuKlxuKiBUaGUgYG9wdGlvbnNgIG9iamVjdCBwYXNzZWQgdG8gdGhlIGBGLm1hbmFnZXIuQXV0aE1hbmFnZXIoKWAgY2FsbCBjYW4gaW5jbHVkZTpcbipcbiogICAqIGBhY2NvdW50YDogVGhlIGFjY291bnQgaWQgZm9yIHRoaXMgYHVzZXJOYW1lYC4gSW4gdGhlIEVwaWNlbnRlciBVSSwgdGhpcyBpcyB0aGUgKipUZWFtIElEKiogKGZvciB0ZWFtIHByb2plY3RzKSBvciB0aGUgKipVc2VyIElEKiogKGZvciBwZXJzb25hbCBwcm9qZWN0cykuXG4qICAgKiBgdXNlck5hbWVgOiBFbWFpbCBvciB1c2VybmFtZSB0byB1c2UgZm9yIGxvZ2dpbmcgaW4uXG4qICAgKiBgcGFzc3dvcmRgOiBQYXNzd29yZCBmb3Igc3BlY2lmaWVkIGB1c2VyTmFtZWAuXG4qICAgKiBgcHJvamVjdGA6IFRoZSAqKlByb2plY3QgSUQqKiBmb3IgdGhlIHByb2plY3QgdG8gbG9nIHRoaXMgdXNlciBpbnRvLiBPcHRpb25hbC5cbiogICAqIGBncm91cElkYDogSWQgb2YgdGhlIGdyb3VwIHRvIHdoaWNoIGB1c2VyTmFtZWAgYmVsb25ncy4gUmVxdWlyZWQgZm9yIGVuZCB1c2VycyBpZiB0aGUgYHByb2plY3RgIGlzIHNwZWNpZmllZC5cbipcbiogSWYgeW91IHByZWZlciBzdGFydGluZyBmcm9tIGEgdGVtcGxhdGUsIHRoZSBFcGljZW50ZXIgSlMgTGlicyBbTG9naW4gQ29tcG9uZW50XSguLi8uLi8jY29tcG9uZW50cykgdXNlcyB0aGUgQXV0aG9yaXphdGlvbiBNYW5hZ2VyIGFzIHdlbGwuIFRoaXMgc2FtcGxlIEhUTUwgcGFnZSAoYW5kIGFzc29jaWF0ZWQgQ1NTIGFuZCBKUyBmaWxlcykgcHJvdmlkZXMgYSBsb2dpbiBmb3JtIGZvciB0ZWFtIG1lbWJlcnMgYW5kIGVuZCB1c2VycyBvZiB5b3VyIHByb2plY3QuIEl0IGFsc28gaW5jbHVkZXMgYSBncm91cCBzZWxlY3RvciBmb3IgZW5kIHVzZXJzIHRoYXQgYXJlIG1lbWJlcnMgb2YgbXVsdGlwbGUgZ3JvdXBzLlxuKi9cblxuJ3VzZSBzdHJpY3QnO1xudmFyIEF1dGhBZGFwdGVyID0gcmVxdWlyZSgnLi4vc2VydmljZS9hdXRoLWFwaS1zZXJ2aWNlJyk7XG52YXIgTWVtYmVyQWRhcHRlciA9IHJlcXVpcmUoJy4uL3NlcnZpY2UvbWVtYmVyLWFwaS1hZGFwdGVyJyk7XG52YXIgR3JvdXBTZXJ2aWNlID0gcmVxdWlyZSgnLi4vc2VydmljZS9ncm91cC1hcGktc2VydmljZScpO1xudmFyIFNlc3Npb25NYW5hZ2VyID0gcmVxdWlyZSgnLi4vc3RvcmUvc2Vzc2lvbi1tYW5hZ2VyJyk7XG52YXIgX3BpY2sgPSByZXF1aXJlKCcuLi91dGlsL29iamVjdC11dGlsJykuX3BpY2s7XG52YXIgb2JqZWN0QXNzaWduID0gcmVxdWlyZSgnb2JqZWN0LWFzc2lnbicpO1xuXG52YXIgYXRvYiA9IHdpbmRvdy5hdG9iIHx8IHJlcXVpcmUoJ0Jhc2U2NCcpLmF0b2I7XG5cbnZhciBkZWZhdWx0cyA9IHtcbiAgICByZXF1aXJlc0dyb3VwOiB0cnVlXG59O1xuXG5mdW5jdGlvbiBBdXRoTWFuYWdlcihvcHRpb25zKSB7XG4gICAgb3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LCBkZWZhdWx0cywgb3B0aW9ucyk7XG4gICAgdGhpcy5zZXNzaW9uTWFuYWdlciA9IG5ldyBTZXNzaW9uTWFuYWdlcihvcHRpb25zKTtcbiAgICB0aGlzLm9wdGlvbnMgPSB0aGlzLnNlc3Npb25NYW5hZ2VyLmdldE1lcmdlZE9wdGlvbnMoKTtcblxuICAgIHRoaXMuYXV0aEFkYXB0ZXIgPSBuZXcgQXV0aEFkYXB0ZXIodGhpcy5vcHRpb25zKTtcbn1cblxudmFyIF9maW5kVXNlckluR3JvdXAgPSBmdW5jdGlvbiAobWVtYmVycywgaWQpIHtcbiAgICBmb3IgKHZhciBqID0gMDsgaiA8IG1lbWJlcnMubGVuZ3RoOyBqKyspIHtcbiAgICAgICAgaWYgKG1lbWJlcnNbal0udXNlcklkID09PSBpZCkge1xuICAgICAgICAgICAgcmV0dXJuIG1lbWJlcnNbal07XG4gICAgICAgIH1cbiAgICB9XG4gICAgcmV0dXJuIG51bGw7XG59O1xuXG5BdXRoTWFuYWdlci5wcm90b3R5cGUgPSAkLmV4dGVuZChBdXRoTWFuYWdlci5wcm90b3R5cGUsIHtcblxuICAgIC8qKlxuICAgICogTG9ncyB1c2VyIGluLlxuICAgICpcbiAgICAqICoqRXhhbXBsZSoqXG4gICAgKlxuICAgICogICAgICAgYXV0aE1nci5sb2dpbih7XG4gICAgKiAgICAgICAgICAgYWNjb3VudDogJ2FjbWUtc2ltdWxhdGlvbnMnLFxuICAgICogICAgICAgICAgIHByb2plY3Q6ICdzdXBwbHktY2hhaW4tZ2FtZScsXG4gICAgKiAgICAgICAgICAgdXNlck5hbWU6ICdlbmR1c2VyMScsXG4gICAgKiAgICAgICAgICAgcGFzc3dvcmQ6ICdwYXNzdzByZCdcbiAgICAqICAgICAgIH0pXG4gICAgKiAgICAgICAgICAgLnRoZW4oZnVuY3Rpb24oc3RhdHVzT2JqKSB7XG4gICAgKiAgICAgICAgICAgICAgIC8vIGlmIGVuZHVzZXIxIGJlbG9uZ3MgdG8gZXhhY3RseSBvbmUgZ3JvdXBcbiAgICAqICAgICAgICAgICAgICAgLy8gKG9yIGlmIHRoZSBsb2dpbigpIGNhbGwgaXMgbW9kaWZpZWQgdG8gaW5jbHVkZSB0aGUgZ3JvdXAgaWQpXG4gICAgKiAgICAgICAgICAgICAgIC8vIGNvbnRpbnVlIGhlcmVcbiAgICAqICAgICAgICAgICB9KVxuICAgICogICAgICAgICAgIC5mYWlsKGZ1bmN0aW9uKHN0YXR1c09iaikge1xuICAgICogICAgICAgICAgICAgICAvLyBpZiBlbmR1c2VyMSBiZWxvbmdzIHRvIG11bHRpcGxlIGdyb3VwcyxcbiAgICAqICAgICAgICAgICAgICAgLy8gdGhlIGxvZ2luKCkgY2FsbCBmYWlsc1xuICAgICogICAgICAgICAgICAgICAvLyBhbmQgcmV0dXJucyBhbGwgZ3JvdXBzIG9mIHdoaWNoIHRoZSB1c2VyIGlzIGEgbWVtYmVyXG4gICAgKiAgICAgICAgICAgICAgIGZvciAodmFyIGk9MDsgaSA8IHN0YXR1c09iai51c2VyR3JvdXBzLmxlbmd0aDsgaSsrKSB7XG4gICAgKiAgICAgICAgICAgICAgICAgICBjb25zb2xlLmxvZyhzdGF0dXNPYmoudXNlckdyb3Vwc1tpXS5uYW1lLCBzdGF0dXNPYmoudXNlckdyb3Vwc1tpXS5ncm91cElkKTtcbiAgICAqICAgICAgICAgICAgICAgfVxuICAgICogICAgICAgICAgIH0pO1xuICAgICpcbiAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgKlxuICAgICogQHBhcmFtIHtPYmplY3R9IG9wdGlvbnMgKE9wdGlvbmFsKSBPdmVycmlkZXMgZm9yIGNvbmZpZ3VyYXRpb24gb3B0aW9ucy4gSWYgbm90IHBhc3NlZCBpbiB3aGVuIGNyZWF0aW5nIGFuIGluc3RhbmNlIG9mIHRoZSBtYW5hZ2VyIChgRi5tYW5hZ2VyLkF1dGhNYW5hZ2VyKClgKSwgdGhlc2Ugb3B0aW9ucyBzaG91bGQgaW5jbHVkZTpcbiAgICAqIEBwYXJhbSB7c3RyaW5nfSBvcHRpb25zLmFjY291bnQgVGhlIGFjY291bnQgaWQgZm9yIHRoaXMgYHVzZXJOYW1lYC4gSW4gdGhlIEVwaWNlbnRlciBVSSwgdGhpcyBpcyB0aGUgKipUZWFtIElEKiogKGZvciB0ZWFtIHByb2plY3RzKSBvciB0aGUgKipVc2VyIElEKiogKGZvciBwZXJzb25hbCBwcm9qZWN0cykuXG4gICAgKiBAcGFyYW0ge3N0cmluZ30gb3B0aW9ucy51c2VyTmFtZSBFbWFpbCBvciB1c2VybmFtZSB0byB1c2UgZm9yIGxvZ2dpbmcgaW4uXG4gICAgKiBAcGFyYW0ge3N0cmluZ30gb3B0aW9ucy5wYXNzd29yZCBQYXNzd29yZCBmb3Igc3BlY2lmaWVkIGB1c2VyTmFtZWAuXG4gICAgKiBAcGFyYW0ge3N0cmluZ30gb3B0aW9ucy5wcm9qZWN0IChPcHRpb25hbCkgVGhlICoqUHJvamVjdCBJRCoqIGZvciB0aGUgcHJvamVjdCB0byBsb2cgdGhpcyB1c2VyIGludG8uXG4gICAgKiBAcGFyYW0ge3N0cmluZ30gb3B0aW9ucy5ncm91cElkIFRoZSBpZCBvZiB0aGUgZ3JvdXAgdG8gd2hpY2ggYHVzZXJOYW1lYCBiZWxvbmdzLiBSZXF1aXJlZCBmb3IgW2VuZCB1c2Vyc10oLi4vLi4vLi4vZ2xvc3NhcnkvI3VzZXJzKSBpZiB0aGUgYHByb2plY3RgIGlzIHNwZWNpZmllZCBhbmQgaWYgdGhlIGVuZCB1c2VycyBhcmUgbWVtYmVycyBvZiBtdWx0aXBsZSBbZ3JvdXBzXSguLi8uLi8uLi9nbG9zc2FyeS8jZ3JvdXBzKSwgb3RoZXJ3aXNlIG9wdGlvbmFsLlxuICAgICogQHJldHVybiB7UHJvbWlzZX1cbiAgICAqL1xuICAgIGxvZ2luOiBmdW5jdGlvbiAob3B0aW9ucykge1xuICAgICAgICB2YXIgbWUgPSB0aGlzO1xuICAgICAgICB2YXIgJGQgPSAkLkRlZmVycmVkKCk7XG4gICAgICAgIHZhciBzZXNzaW9uTWFuYWdlciA9IHRoaXMuc2Vzc2lvbk1hbmFnZXI7XG4gICAgICAgIHZhciBhZGFwdGVyT3B0aW9ucyA9IHNlc3Npb25NYW5hZ2VyLmdldE1lcmdlZE9wdGlvbnMoeyBzdWNjZXNzOiAkLm5vb3AsIGVycm9yOiAkLm5vb3AgfSwgb3B0aW9ucyk7XG4gICAgICAgIHZhciBvdXRTdWNjZXNzID0gYWRhcHRlck9wdGlvbnMuc3VjY2VzcztcbiAgICAgICAgdmFyIG91dEVycm9yID0gYWRhcHRlck9wdGlvbnMuZXJyb3I7XG4gICAgICAgIHZhciBncm91cElkID0gYWRhcHRlck9wdGlvbnMuZ3JvdXBJZDtcblxuICAgICAgICB2YXIgZGVjb2RlVG9rZW4gPSBmdW5jdGlvbiAodG9rZW4pIHtcbiAgICAgICAgICAgIHZhciBlbmNvZGVkID0gdG9rZW4uc3BsaXQoJy4nKVsxXTtcbiAgICAgICAgICAgIHdoaWxlIChlbmNvZGVkLmxlbmd0aCAlIDQgIT09IDApIHsgLy9lc2xpbnQtZGlzYWJsZS1saW5lXG4gICAgICAgICAgICAgICAgZW5jb2RlZCArPSAnPSc7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICByZXR1cm4gSlNPTi5wYXJzZShhdG9iKGVuY29kZWQpKTtcbiAgICAgICAgfTtcblxuICAgICAgICB2YXIgaGFuZGxlR3JvdXBFcnJvciA9IGZ1bmN0aW9uIChtZXNzYWdlLCBzdGF0dXNDb2RlLCBkYXRhLCB0eXBlKSB7XG4gICAgICAgICAgICAvLyBsb2dvdXQgdGhlIHVzZXIgc2luY2UgaXQncyBpbiBhbiBpbnZhbGlkIHN0YXRlIHdpdGggbm8gZ3JvdXAgc2VsZWN0ZWRcbiAgICAgICAgICAgIG1lLmxvZ291dCgpLnRoZW4oZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgICAgIHZhciBlcnJvciA9ICQuZXh0ZW5kKHRydWUsIHt9LCBkYXRhLCB7IHN0YXR1c1RleHQ6IG1lc3NhZ2UsIHN0YXR1czogc3RhdHVzQ29kZSwgdHlwZTogdHlwZSB9KTtcbiAgICAgICAgICAgICAgICAkZC5yZWplY3QoZXJyb3IpO1xuICAgICAgICAgICAgfSk7XG4gICAgICAgIH07XG5cbiAgICAgICAgdmFyIGhhbmRsZVN1Y2Nlc3MgPSBmdW5jdGlvbiAocmVzcG9uc2UpIHtcbiAgICAgICAgICAgIHZhciB0b2tlbiA9IHJlc3BvbnNlLmFjY2Vzc190b2tlbjtcbiAgICAgICAgICAgIHZhciB1c2VySW5mbyA9IGRlY29kZVRva2VuKHRva2VuKTtcbiAgICAgICAgICAgIHZhciBvbGRHcm91cHMgPSBzZXNzaW9uTWFuYWdlci5nZXRTZXNzaW9uKGFkYXB0ZXJPcHRpb25zKS5ncm91cHMgfHwge307XG4gICAgICAgICAgICB2YXIgdXNlckdyb3VwT3B0cyA9ICQuZXh0ZW5kKHRydWUsIHt9LCBhZGFwdGVyT3B0aW9ucywgeyBzdWNjZXNzOiAkLm5vb3AgfSk7XG4gICAgICAgICAgICB2YXIgZGF0YSA9IHsgYXV0aDogcmVzcG9uc2UsIHVzZXI6IHVzZXJJbmZvIH07XG4gICAgICAgICAgICB2YXIgcHJvamVjdCA9IGFkYXB0ZXJPcHRpb25zLnByb2plY3Q7XG4gICAgICAgICAgICB2YXIgaXNUZWFtTWVtYmVyID0gdXNlckluZm8ucGFyZW50X2FjY291bnRfaWQgPT09IG51bGw7XG4gICAgICAgICAgICB2YXIgcmVxdWlyZXNHcm91cCA9IGFkYXB0ZXJPcHRpb25zLnJlcXVpcmVzR3JvdXAgJiYgcHJvamVjdDtcblxuICAgICAgICAgICAgdmFyIHVzZXJOYW1lID0gKHVzZXJJbmZvLnVzZXJfbmFtZSB8fCAnJykuc3BsaXQoJy8nKVswXTsgLy9vZiBmb3JtIDx1c2VyPi88dGVhbT5cbiAgICAgICAgICAgIHZhciBzZXNzaW9uSW5mbyA9IHtcbiAgICAgICAgICAgICAgICBhdXRoX3Rva2VuOiB0b2tlbixcbiAgICAgICAgICAgICAgICBhY2NvdW50OiBhZGFwdGVyT3B0aW9ucy5hY2NvdW50LFxuICAgICAgICAgICAgICAgIHByb2plY3Q6IHByb2plY3QsXG4gICAgICAgICAgICAgICAgdXNlcklkOiB1c2VySW5mby51c2VyX2lkLFxuICAgICAgICAgICAgICAgIGdyb3Vwczogb2xkR3JvdXBzLFxuICAgICAgICAgICAgICAgIGlzVGVhbU1lbWJlcjogaXNUZWFtTWVtYmVyLFxuICAgICAgICAgICAgICAgIHVzZXJOYW1lOiB1c2VyTmFtZSxcbiAgICAgICAgICAgIH07XG4gICAgICAgICAgICAvLyBUaGUgZ3JvdXAgaXMgbm90IHJlcXVpcmVkIGlmIHRoZSB1c2VyIGlzIG5vdCBsb2dnaW5nIGludG8gYSBwcm9qZWN0XG4gICAgICAgICAgICBpZiAoIXJlcXVpcmVzR3JvdXApIHtcbiAgICAgICAgICAgICAgICBzZXNzaW9uTWFuYWdlci5zYXZlU2Vzc2lvbihzZXNzaW9uSW5mbyk7XG4gICAgICAgICAgICAgICAgb3V0U3VjY2Vzcy5hcHBseSh0aGlzLCBbZGF0YV0pO1xuICAgICAgICAgICAgICAgICRkLnJlc29sdmUoZGF0YSk7XG4gICAgICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICB2YXIgaGFuZGxlR3JvdXBMaXN0ID0gZnVuY3Rpb24gKGdyb3VwTGlzdCkge1xuICAgICAgICAgICAgICAgIGRhdGEudXNlckdyb3VwcyA9IGdyb3VwTGlzdDtcblxuICAgICAgICAgICAgICAgIHZhciBncm91cCA9IG51bGw7XG4gICAgICAgICAgICAgICAgaWYgKGdyb3VwTGlzdC5sZW5ndGggPT09IDApIHtcbiAgICAgICAgICAgICAgICAgICAgaGFuZGxlR3JvdXBFcnJvcignVGhlIHVzZXIgaGFzIG5vIGdyb3VwcyBhc3NvY2lhdGVkIGluIHRoaXMgYWNjb3VudCcsIDQwMywgZGF0YSwgJ05PX0dST1VQUycpO1xuICAgICAgICAgICAgICAgICAgICByZXR1cm47XG4gICAgICAgICAgICAgICAgfSBlbHNlIGlmIChncm91cExpc3QubGVuZ3RoID09PSAxKSB7XG4gICAgICAgICAgICAgICAgICAgIC8vIFNlbGVjdCB0aGUgb25seSBncm91cFxuICAgICAgICAgICAgICAgICAgICBncm91cCA9IGdyb3VwTGlzdFswXTtcbiAgICAgICAgICAgICAgICB9IGVsc2UgaWYgKGdyb3VwTGlzdC5sZW5ndGggPiAxKSB7XG4gICAgICAgICAgICAgICAgICAgIGlmIChncm91cElkKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICB2YXIgZmlsdGVyZWRHcm91cHMgPSAkLmdyZXAoZ3JvdXBMaXN0LCBmdW5jdGlvbiAocmVzR3JvdXApIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICByZXR1cm4gcmVzR3JvdXAuZ3JvdXBJZCA9PT0gZ3JvdXBJZDtcbiAgICAgICAgICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICAgICAgICAgICAgZ3JvdXAgPSBmaWx0ZXJlZEdyb3Vwcy5sZW5ndGggPT09IDEgPyBmaWx0ZXJlZEdyb3Vwc1swXSA6IG51bGw7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICBpZiAoZ3JvdXApIHtcbiAgICAgICAgICAgICAgICAgICAgLy8gQSB0ZWFtIG1lbWJlciBkb2VzIG5vdCBnZXQgdGhlIGdyb3VwIG1lbWJlcnMgYmVjYXVzZSBpcyBjYWxsaW5nIHRoZSBHcm91cCBBUElcbiAgICAgICAgICAgICAgICAgICAgLy8gYnV0IGl0J3MgYXV0b21hdGljYWxseSBhIGZhYyB1c2VyXG4gICAgICAgICAgICAgICAgICAgIHZhciBpc0ZhYyA9IGlzVGVhbU1lbWJlciA/IHRydWUgOiBfZmluZFVzZXJJbkdyb3VwKGdyb3VwLm1lbWJlcnMsIHVzZXJJbmZvLnVzZXJfaWQpLnJvbGUgPT09ICdmYWNpbGl0YXRvcic7XG4gICAgICAgICAgICAgICAgICAgIHZhciBncm91cERhdGEgPSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBncm91cElkOiBncm91cC5ncm91cElkLFxuICAgICAgICAgICAgICAgICAgICAgICAgZ3JvdXBOYW1lOiBncm91cC5uYW1lLFxuICAgICAgICAgICAgICAgICAgICAgICAgaXNGYWM6IGlzRmFjXG4gICAgICAgICAgICAgICAgICAgIH07XG4gICAgICAgICAgICAgICAgICAgIHZhciBzZXNzaW9uSW5mb1dpdGhHcm91cCA9IG9iamVjdEFzc2lnbih7fSwgc2Vzc2lvbkluZm8sIGdyb3VwRGF0YSk7XG4gICAgICAgICAgICAgICAgICAgIHNlc3Npb25JbmZvLmdyb3Vwc1twcm9qZWN0XSA9IGdyb3VwRGF0YTtcbiAgICAgICAgICAgICAgICAgICAgbWUuc2Vzc2lvbk1hbmFnZXIuc2F2ZVNlc3Npb24oc2Vzc2lvbkluZm9XaXRoR3JvdXAsIGFkYXB0ZXJPcHRpb25zKTtcbiAgICAgICAgICAgICAgICAgICAgb3V0U3VjY2Vzcy5hcHBseSh0aGlzLCBbZGF0YV0pO1xuICAgICAgICAgICAgICAgICAgICAkZC5yZXNvbHZlKGRhdGEpO1xuICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgIGhhbmRsZUdyb3VwRXJyb3IoJ1RoaXMgdXNlciBpcyBhc3NvY2lhdGVkIHdpdGggbW9yZSB0aGFuIG9uZSBncm91cC4gUGxlYXNlIHNwZWNpZnkgYSBncm91cCBpZCB0byBsb2cgaW50byBhbmQgdHJ5IGFnYWluJywgNDAzLCBkYXRhLCAnTVVMVElQTEVfR1JPVVBTJyk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfTtcblxuICAgICAgICAgICAgaWYgKCFpc1RlYW1NZW1iZXIpIHtcbiAgICAgICAgICAgICAgICBtZS5nZXRVc2VyR3JvdXBzKHsgdXNlcklkOiB1c2VySW5mby51c2VyX2lkLCB0b2tlbjogdG9rZW4gfSwgdXNlckdyb3VwT3B0cylcbiAgICAgICAgICAgICAgICAgICAgLnRoZW4oaGFuZGxlR3JvdXBMaXN0LCAkZC5yZWplY3QpO1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICB2YXIgb3B0cyA9IG9iamVjdEFzc2lnbih7fSwgdXNlckdyb3VwT3B0cywgeyB0b2tlbjogdG9rZW4gfSk7XG4gICAgICAgICAgICAgICAgdmFyIGdyb3VwU2VydmljZSA9IG5ldyBHcm91cFNlcnZpY2Uob3B0cyk7XG4gICAgICAgICAgICAgICAgZ3JvdXBTZXJ2aWNlLmdldEdyb3Vwcyh7IGFjY291bnQ6IGFkYXB0ZXJPcHRpb25zLmFjY291bnQsIHByb2plY3Q6IHByb2plY3QgfSlcbiAgICAgICAgICAgICAgICAgICAgLnRoZW4oZnVuY3Rpb24gKGdyb3Vwcykge1xuICAgICAgICAgICAgICAgICAgICAgICAgLy8gR3JvdXAgQVBJIHJldHVybnMgaWQgaW5zdGVhZCBvZiBncm91cElkXG4gICAgICAgICAgICAgICAgICAgICAgICBncm91cHMuZm9yRWFjaChmdW5jdGlvbiAoZ3JvdXApIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBncm91cC5ncm91cElkID0gZ3JvdXAuaWQ7XG4gICAgICAgICAgICAgICAgICAgICAgICB9KTtcblxuICAgICAgICAgICAgICAgICAgICAgICAgaWYgKGdyb3Vwcy5sZW5ndGgpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBoYW5kbGVHcm91cExpc3QoZ3JvdXBzKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgLy9laXRoZXIgaXQncyBhIHByaXZhdGUgcHJvamVjdCBvciB0aGVyZSBhcmUgbm8gZ3JvdXBzXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgc2Vzc2lvbk1hbmFnZXIuc2F2ZVNlc3Npb24oc2Vzc2lvbkluZm8pO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIG91dFN1Y2Nlc3MuYXBwbHkodGhpcywgW2RhdGFdKTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAkZC5yZXNvbHZlKGRhdGEpO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgfSwgJGQucmVqZWN0KTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfTtcblxuICAgICAgICBhZGFwdGVyT3B0aW9ucy5zdWNjZXNzID0gaGFuZGxlU3VjY2VzcztcbiAgICAgICAgYWRhcHRlck9wdGlvbnMuZXJyb3IgPSBmdW5jdGlvbiAocmVzcG9uc2UpIHtcbiAgICAgICAgICAgIGlmIChhZGFwdGVyT3B0aW9ucy5hY2NvdW50KSB7XG4gICAgICAgICAgICAgICAgLy8gVHJ5IHRvIGxvZ2luIGFzIGEgc3lzdGVtIHVzZXJcbiAgICAgICAgICAgICAgICBhZGFwdGVyT3B0aW9ucy5hY2NvdW50ID0gbnVsbDtcbiAgICAgICAgICAgICAgICBhZGFwdGVyT3B0aW9ucy5lcnJvciA9IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgICAgICAgICAgb3V0RXJyb3IuYXBwbHkodGhpcywgYXJndW1lbnRzKTtcbiAgICAgICAgICAgICAgICAgICAgJGQucmVqZWN0KHJlc3BvbnNlKTtcbiAgICAgICAgICAgICAgICB9O1xuXG4gICAgICAgICAgICAgICAgbWUuYXV0aEFkYXB0ZXIubG9naW4oYWRhcHRlck9wdGlvbnMpO1xuICAgICAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgb3V0RXJyb3IuYXBwbHkodGhpcywgYXJndW1lbnRzKTtcbiAgICAgICAgICAgICRkLnJlamVjdChyZXNwb25zZSk7XG4gICAgICAgIH07XG5cbiAgICAgICAgdGhpcy5hdXRoQWRhcHRlci5sb2dpbihhZGFwdGVyT3B0aW9ucyk7XG4gICAgICAgIHJldHVybiAkZC5wcm9taXNlKCk7XG4gICAgfSxcblxuICAgIC8qKlxuICAgICogTG9ncyB1c2VyIG91dCBieSBjbGVhcmluZyBhbGwgc2Vzc2lvbiBpbmZvcm1hdGlvbi5cbiAgICAqXG4gICAgKiAqKkV4YW1wbGUqKlxuICAgICpcbiAgICAqICAgICAgIGF1dGhNZ3IubG9nb3V0KCk7XG4gICAgKlxuICAgICogKipQYXJhbWV0ZXJzKipcbiAgICAqXG4gICAgKiBAcGFyYW0ge09iamVjdH0gb3B0aW9ucyAoT3B0aW9uYWwpIE92ZXJyaWRlcyBmb3IgY29uZmlndXJhdGlvbiBvcHRpb25zLlxuICAgICogQHJldHVybiB7UHJvbWlzZX1cbiAgICAqL1xuICAgIGxvZ291dDogZnVuY3Rpb24gKG9wdGlvbnMpIHtcbiAgICAgICAgdmFyIG1lID0gdGhpcztcbiAgICAgICAgdmFyIGFkYXB0ZXJPcHRpb25zID0gdGhpcy5zZXNzaW9uTWFuYWdlci5nZXRNZXJnZWRPcHRpb25zKG9wdGlvbnMpO1xuXG4gICAgICAgIHZhciByZW1vdmVDb29raWVGbiA9IGZ1bmN0aW9uIChyZXNwb25zZSkge1xuICAgICAgICAgICAgbWUuc2Vzc2lvbk1hbmFnZXIucmVtb3ZlU2Vzc2lvbigpO1xuICAgICAgICB9O1xuXG4gICAgICAgIHJldHVybiB0aGlzLmF1dGhBZGFwdGVyLmxvZ291dChhZGFwdGVyT3B0aW9ucykudGhlbihyZW1vdmVDb29raWVGbik7XG4gICAgfSxcblxuICAgIC8qKlxuICAgICAqIFJldHVybnMgdGhlIGV4aXN0aW5nIHVzZXIgYWNjZXNzIHRva2VuIGlmIHRoZSB1c2VyIGlzIGFscmVhZHkgbG9nZ2VkIGluLiBPdGhlcndpc2UsIGxvZ3MgdGhlIHVzZXIgaW4sIGNyZWF0aW5nIGEgbmV3IHVzZXIgYWNjZXNzIHRva2VuLCBhbmQgcmV0dXJucyB0aGUgbmV3IHRva2VuLiAoU2VlIFttb3JlIGJhY2tncm91bmQgb24gYWNjZXNzIHRva2Vuc10oLi4vLi4vLi4vcHJvamVjdF9hY2Nlc3MvKSkuXG4gICAgICpcbiAgICAgKiAqKkV4YW1wbGUqKlxuICAgICAqXG4gICAgICogICAgICBhdXRoTWdyLmdldFRva2VuKClcbiAgICAgKiAgICAgICAgICAudGhlbihmdW5jdGlvbiAodG9rZW4pIHtcbiAgICAgKiAgICAgICAgICAgICAgY29uc29sZS5sb2coJ015IHRva2VuIGlzICcsIHRva2VuKTtcbiAgICAgKiAgICAgICAgICB9KTtcbiAgICAgKlxuICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICogQHBhcmFtIHtPYmplY3R9IG9wdGlvbnMgKE9wdGlvbmFsKSBPdmVycmlkZXMgZm9yIGNvbmZpZ3VyYXRpb24gb3B0aW9ucy5cbiAgICAgKiBAcmV0dXJuIHtQcm9taXNlfVxuICAgICAqL1xuICAgIGdldFRva2VuOiBmdW5jdGlvbiAob3B0aW9ucykge1xuICAgICAgICB2YXIgaHR0cE9wdGlvbnMgPSB0aGlzLnNlc3Npb25NYW5hZ2VyLmdldE1lcmdlZE9wdGlvbnMob3B0aW9ucyk7XG5cbiAgICAgICAgdmFyIHNlc3Npb24gPSB0aGlzLnNlc3Npb25NYW5hZ2VyLmdldFNlc3Npb24oaHR0cE9wdGlvbnMpO1xuICAgICAgICB2YXIgJGQgPSAkLkRlZmVycmVkKCk7XG4gICAgICAgIGlmIChzZXNzaW9uLmF1dGhfdG9rZW4pIHtcbiAgICAgICAgICAgICRkLnJlc29sdmUoc2Vzc2lvbi5hdXRoX3Rva2VuKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIHRoaXMubG9naW4oaHR0cE9wdGlvbnMpLnRoZW4oJGQucmVzb2x2ZSk7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuICRkLnByb21pc2UoKTtcbiAgICB9LFxuXG4gICAgLyoqXG4gICAgICogUmV0dXJucyBhbiBhcnJheSBvZiBncm91cCByZWNvcmRzLCBvbmUgZm9yIGVhY2ggZ3JvdXAgb2Ygd2hpY2ggdGhlIGN1cnJlbnQgdXNlciBpcyBhIG1lbWJlci4gRWFjaCBncm91cCByZWNvcmQgaW5jbHVkZXMgdGhlIGdyb3VwIGBuYW1lYCwgYGFjY291bnRgLCBgcHJvamVjdGAsIGFuZCBgZ3JvdXBJZGAuXG4gICAgICpcbiAgICAgKiBJZiBzb21lIGVuZCB1c2VycyBpbiB5b3VyIHByb2plY3QgYXJlIG1lbWJlcnMgb2YgbXVsdGlwbGUgZ3JvdXBzLCB0aGlzIGlzIGEgdXNlZnVsIG1ldGhvZCB0byBjYWxsIG9uIHlvdXIgcHJvamVjdCdzIGxvZ2luIHBhZ2UuIFdoZW4gdGhlIHVzZXIgYXR0ZW1wdHMgdG8gbG9nIGluLCB5b3UgY2FuIHVzZSB0aGlzIHRvIGRpc3BsYXkgdGhlIGdyb3VwcyBvZiB3aGljaCB0aGUgdXNlciBpcyBtZW1iZXIsIGFuZCBoYXZlIHRoZSB1c2VyIHNlbGVjdCB0aGUgY29ycmVjdCBncm91cCB0byBsb2cgaW4gdG8gZm9yIHRoaXMgc2Vzc2lvbi5cbiAgICAgKlxuICAgICAqICoqRXhhbXBsZSoqXG4gICAgICpcbiAgICAgKiAgICAgIC8vIGdldCBncm91cHMgZm9yIGN1cnJlbnQgdXNlclxuICAgICAqICAgICAgdmFyIHNlc3Npb25PYmogPSBhdXRoTWdyLmdldEN1cnJlbnRVc2VyU2Vzc2lvbkluZm8oKTtcbiAgICAgKiAgICAgIGF1dGhNZ3IuZ2V0VXNlckdyb3Vwcyh7IHVzZXJJZDogc2Vzc2lvbk9iai51c2VySWQsIHRva2VuOiBzZXNzaW9uT2JqLmF1dGhfdG9rZW4gfSlcbiAgICAgKiAgICAgICAgICAudGhlbihmdW5jdGlvbiAoZ3JvdXBzKSB7XG4gICAgICogICAgICAgICAgICAgIGZvciAodmFyIGk9MDsgaSA8IGdyb3Vwcy5sZW5ndGg7IGkrKylcbiAgICAgKiAgICAgICAgICAgICAgICAgIHsgY29uc29sZS5sb2coZ3JvdXBzW2ldLm5hbWUpOyB9XG4gICAgICogICAgICAgICAgfSk7XG4gICAgICpcbiAgICAgKiAgICAgIC8vIGdldCBncm91cHMgZm9yIHBhcnRpY3VsYXIgdXNlclxuICAgICAqICAgICAgYXV0aE1nci5nZXRVc2VyR3JvdXBzKHt1c2VySWQ6ICdiMWMxOWRkYS0yZDJlLTQ3NzctYWQ1ZC0zOTI5ZjE3ZTg2ZDMnLCB0b2tlbjogc2F2ZWRQcm9qQWNjZXNzVG9rZW4gfSk7XG4gICAgICpcbiAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAqIEBwYXJhbSB7T2JqZWN0fSBwYXJhbXMgT2JqZWN0IHdpdGggYSB1c2VySWQgYW5kIHRva2VuIHByb3BlcnRpZXMuXG4gICAgICogQHBhcmFtIHtTdHJpbmd9IHBhcmFtcy51c2VySWQgVGhlIHVzZXJJZC4gSWYgbG9va2luZyB1cCBncm91cHMgZm9yIHRoZSBjdXJyZW50bHkgbG9nZ2VkIGluIHVzZXIsIHRoaXMgaXMgaW4gdGhlIHNlc3Npb24gaW5mb3JtYXRpb24uIE90aGVyd2lzZSwgcGFzcyBhIHN0cmluZy5cbiAgICAgKiBAcGFyYW0ge1N0cmluZ30gcGFyYW1zLnRva2VuIFRoZSBhdXRob3JpemF0aW9uIGNyZWRlbnRpYWxzIChhY2Nlc3MgdG9rZW4pIHRvIHVzZSBmb3IgY2hlY2tpbmcgdGhlIGdyb3VwcyBmb3IgdGhpcyB1c2VyLiBJZiBsb29raW5nIHVwIGdyb3VwcyBmb3IgdGhlIGN1cnJlbnRseSBsb2dnZWQgaW4gdXNlciwgdGhpcyBpcyBpbiB0aGUgc2Vzc2lvbiBpbmZvcm1hdGlvbi4gQSB0ZWFtIG1lbWJlcidzIHRva2VuIG9yIGEgcHJvamVjdCBhY2Nlc3MgdG9rZW4gY2FuIGFjY2VzcyBhbGwgdGhlIGdyb3VwcyBmb3IgYWxsIGVuZCB1c2VycyBpbiB0aGUgdGVhbSBvciBwcm9qZWN0LlxuICAgICAqIEBwYXJhbSB7T2JqZWN0fSBvcHRpb25zIChPcHRpb25hbCkgT3ZlcnJpZGVzIGZvciBjb25maWd1cmF0aW9uIG9wdGlvbnMuXG4gICAgICogQHJldHVybiB7UHJvbWlzZX1cbiAgICAgKi9cbiAgICBnZXRVc2VyR3JvdXBzOiBmdW5jdGlvbiAocGFyYW1zLCBvcHRpb25zKSB7XG4gICAgICAgIHZhciBhZGFwdGVyT3B0aW9ucyA9IHRoaXMuc2Vzc2lvbk1hbmFnZXIuZ2V0TWVyZ2VkT3B0aW9ucyh7IHN1Y2Nlc3M6ICQubm9vcCB9LCBvcHRpb25zKTtcbiAgICAgICAgdmFyICRkID0gJC5EZWZlcnJlZCgpO1xuICAgICAgICB2YXIgb3V0U3VjY2VzcyA9IGFkYXB0ZXJPcHRpb25zLnN1Y2Nlc3M7XG5cbiAgICAgICAgYWRhcHRlck9wdGlvbnMuc3VjY2VzcyA9IGZ1bmN0aW9uIChtZW1iZXJJbmZvKSB7XG4gICAgICAgICAgICAvLyBUaGUgbWVtYmVyIEFQSSBpcyBhdCB0aGUgYWNjb3VudCBzY29wZSwgd2UgZmlsdGVyIGJ5IHByb2plY3RcbiAgICAgICAgICAgIGlmIChhZGFwdGVyT3B0aW9ucy5wcm9qZWN0KSB7XG4gICAgICAgICAgICAgICAgbWVtYmVySW5mbyA9ICQuZ3JlcChtZW1iZXJJbmZvLCBmdW5jdGlvbiAoZ3JvdXApIHtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIGdyb3VwLnByb2plY3QgPT09IGFkYXB0ZXJPcHRpb25zLnByb2plY3Q7XG4gICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIG91dFN1Y2Nlc3MuYXBwbHkodGhpcywgW21lbWJlckluZm9dKTtcbiAgICAgICAgICAgICRkLnJlc29sdmUobWVtYmVySW5mbyk7XG4gICAgICAgIH07XG5cbiAgICAgICAgdmFyIG1lbWJlckFkYXB0ZXIgPSBuZXcgTWVtYmVyQWRhcHRlcih7IHRva2VuOiBwYXJhbXMudG9rZW4sIHNlcnZlcjogYWRhcHRlck9wdGlvbnMuc2VydmVyIH0pO1xuICAgICAgICBtZW1iZXJBZGFwdGVyLmdldEdyb3Vwc0ZvclVzZXIocGFyYW1zLCBhZGFwdGVyT3B0aW9ucykuZmFpbCgkZC5yZWplY3QpO1xuICAgICAgICByZXR1cm4gJGQucHJvbWlzZSgpO1xuICAgIH0sXG5cbiAgICAvKipcbiAgICAgKiBIZWxwZXIgbWV0aG9kIHRvIGNoZWNrIGlmIHlvdSdyZSBjdXJyZW50bHkgbG9nZ2VkIGluXG4gICAgICogQHJldHVybiB7Qm9vbGVhbn0gdHJ1ZSBpZiB5b3UncmUgbG9nZ2VkIGluXG4gICAgICovXG4gICAgaXNMb2dnZWRJbjogZnVuY3Rpb24gKCkge1xuICAgICAgICB2YXIgc2Vzc2lvbiA9IHRoaXMuZ2V0Q3VycmVudFVzZXJTZXNzaW9uSW5mbygpO1xuICAgICAgICByZXR1cm4gISEoc2Vzc2lvbiAmJiBzZXNzaW9uLnVzZXJJZCk7XG4gICAgfSxcblxuICAgIC8qKlxuICAgICAqIFJldHVybnMgc2Vzc2lvbiBpbmZvcm1hdGlvbiBmb3IgdGhlIGN1cnJlbnQgdXNlciwgaW5jbHVkaW5nIHRoZSBgdXNlcklkYCwgYGFjY291bnRgLCBgcHJvamVjdGAsIGBncm91cElkYCwgYGdyb3VwTmFtZWAsIGBpc0ZhY2AgKHdoZXRoZXIgdGhlIGVuZCB1c2VyIGlzIGEgZmFjaWxpdGF0b3Igb2YgdGhpcyBncm91cCksIGFuZCBgYXV0aF90b2tlbmAgKHVzZXIgYWNjZXNzIHRva2VuKS5cbiAgICAgKlxuICAgICAqICpJbXBvcnRhbnQqOiBUaGlzIG1ldGhvZCBpcyBzeW5jaHJvbm91cy4gVGhlIHNlc3Npb24gaW5mb3JtYXRpb24gaXMgcmV0dXJuZWQgaW1tZWRpYXRlbHkgaW4gYW4gb2JqZWN0OyBubyBjYWxsYmFja3Mgb3IgcHJvbWlzZXMgYXJlIG5lZWRlZC5cbiAgICAgKlxuICAgICAqIFNlc3Npb24gaW5mb3JtYXRpb24gaXMgc3RvcmVkIGluIGEgY29va2llIGluIHRoZSBicm93c2VyLlxuICAgICAqXG4gICAgICogKipFeGFtcGxlKipcbiAgICAgKlxuICAgICAqICAgICAgdmFyIHNlc3Npb25PYmogPSBhdXRoTWdyLmdldEN1cnJlbnRVc2VyU2Vzc2lvbkluZm8oKTtcbiAgICAgKlxuICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICogQHBhcmFtIHtPYmplY3R9IG9wdGlvbnMgKE9wdGlvbmFsKSBPdmVycmlkZXMgZm9yIGNvbmZpZ3VyYXRpb24gb3B0aW9ucy5cbiAgICAgKiBAcmV0dXJuIHtPYmplY3R9IHNlc3Npb24gaW5mb3JtYXRpb25cbiAgICAgKi9cbiAgICBnZXRDdXJyZW50VXNlclNlc3Npb25JbmZvOiBmdW5jdGlvbiAob3B0aW9ucykge1xuICAgICAgICB2YXIgYWRhcHRlck9wdGlvbnMgPSB0aGlzLnNlc3Npb25NYW5hZ2VyLmdldE1lcmdlZE9wdGlvbnMoeyBzdWNjZXNzOiAkLm5vb3AgfSwgb3B0aW9ucyk7XG4gICAgICAgIHJldHVybiB0aGlzLnNlc3Npb25NYW5hZ2VyLmdldFNlc3Npb24oYWRhcHRlck9wdGlvbnMpO1xuICAgIH0sXG5cbiAgICAvKlxuICAgICAqIEFkZHMgb25lIG9yIG1vcmUgZ3JvdXBzIHRvIHRoZSBjdXJyZW50IHNlc3Npb24uIFxuICAgICAqXG4gICAgICogVGhpcyBtZXRob2QgYXNzdW1lcyB0aGF0IHRoZSBwcm9qZWN0IGFuZCBncm91cCBleGlzdCBhbmQgdGhlIHVzZXIgc3BlY2lmaWVkIGluIHRoZSBzZXNzaW9uIGlzIHBhcnQgb2YgdGhpcyBwcm9qZWN0IGFuZCBncm91cC5cbiAgICAgKlxuICAgICAqIFJldHVybnMgdGhlIG5ldyBzZXNzaW9uIG9iamVjdC5cbiAgICAgKlxuICAgICAqICoqRXhhbXBsZSoqXG4gICAgICpcbiAgICAgKiAgICAgIGF1dGhNZ3IuYWRkR3JvdXBzKHsgcHJvamVjdDogJ2hlbGxvLXdvcmxkJywgZ3JvdXBOYW1lOiAnZ3JvdXBOYW1lJywgZ3JvdXBJZDogJ2dyb3VwSWQnIH0pO1xuICAgICAqICAgICAgYXV0aE1nci5hZGRHcm91cHMoW3sgcHJvamVjdDogJ2hlbGxvLXdvcmxkJywgZ3JvdXBOYW1lOiAnZ3JvdXBOYW1lJywgZ3JvdXBJZDogJ2dyb3VwSWQnIH0sIHsgcHJvamVjdDogJ2hlbGxvLXdvcmxkJywgZ3JvdXBOYW1lOiAnLi4uJyB9XSk7XG4gICAgICpcbiAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAqIEBwYXJhbSB7b2JqZWN0fGFycmF5fSBncm91cHMgKFJlcXVpcmVkKSBUaGUgZ3JvdXAgb2JqZWN0IG11c3QgY29udGFpbiB0aGUgYHByb2plY3RgICgqKlByb2plY3QgSUQqKikgYW5kIGBncm91cE5hbWVgIHByb3BlcnRpZXMuIElmIHBhc3NpbmcgYW4gYXJyYXkgb2Ygc3VjaCBvYmplY3RzLCBhbGwgb2YgdGhlIG9iamVjdHMgbXVzdCBjb250YWluICpkaWZmZXJlbnQqIGBwcm9qZWN0YCAoKipQcm9qZWN0IElEKiopIHZhbHVlczogYWx0aG91Z2ggZW5kIHVzZXJzIG1heSBiZSBsb2dnZWQgaW4gdG8gbXVsdGlwbGUgcHJvamVjdHMgYXQgb25jZSwgdGhleSBtYXkgb25seSBiZSBsb2dnZWQgaW4gdG8gb25lIGdyb3VwIHBlciBwcm9qZWN0IGF0IGEgdGltZS5cbiAgICAgKiBAcGFyYW0ge3N0cmluZ30gZ3JvdXAuaXNGYWMgKG9wdGlvbmFsKSBEZWZhdWx0cyB0byBgZmFsc2VgLiBTZXQgdG8gYHRydWVgIGlmIHRoZSB1c2VyIGluIHRoZSBzZXNzaW9uIHNob3VsZCBiZSBhIGZhY2lsaXRhdG9yIGluIHRoaXMgZ3JvdXAuXG4gICAgICogQHBhcmFtIHtzdHJpbmd9IGdyb3VwLmdyb3VwSWQgKG9wdGlvbmFsKSBEZWZhdWx0cyB0byB1bmRlZmluZWQuIE5lZWRlZCBtb3N0bHkgZm9yIHRoZSBNZW1iZXJzIEFQSS5cbiAgICAgKiBAcmV0dXJuIHtPYmplY3R9IHNlc3Npb24gaW5mb3JtYXRpb25cbiAgICAqL1xuICAgIGFkZEdyb3VwczogZnVuY3Rpb24gKGdyb3Vwcykge1xuICAgICAgICB2YXIgc2Vzc2lvbiA9IHRoaXMuZ2V0Q3VycmVudFVzZXJTZXNzaW9uSW5mbygpO1xuICAgICAgICB2YXIgaXNBcnJheSA9IEFycmF5LmlzQXJyYXkoZ3JvdXBzKTtcbiAgICAgICAgZ3JvdXBzID0gaXNBcnJheSA/IGdyb3VwcyA6IFtncm91cHNdO1xuXG4gICAgICAgICQuZWFjaChncm91cHMsIGZ1bmN0aW9uIChpbmRleCwgZ3JvdXApIHtcbiAgICAgICAgICAgIHZhciBleHRlbmRlZEdyb3VwID0gJC5leHRlbmQoe30sIHsgaXNGYWM6IGZhbHNlIH0sIGdyb3VwKTtcbiAgICAgICAgICAgIHZhciBwcm9qZWN0ID0gZXh0ZW5kZWRHcm91cC5wcm9qZWN0O1xuICAgICAgICAgICAgdmFyIHZhbGlkUHJvcHMgPSBbJ2dyb3VwTmFtZScsICdncm91cElkJywgJ2lzRmFjJ107XG4gICAgICAgICAgICBpZiAoIXByb2plY3QgfHwgIWV4dGVuZGVkR3JvdXAuZ3JvdXBOYW1lKSB7XG4gICAgICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdObyBwcm9qZWN0IG9yIGdyb3VwTmFtZSBzcGVjaWZpZWQuJyk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICAvLyBmaWx0ZXIgb2JqZWN0XG4gICAgICAgICAgICBleHRlbmRlZEdyb3VwID0gX3BpY2soZXh0ZW5kZWRHcm91cCwgdmFsaWRQcm9wcyk7XG4gICAgICAgICAgICBzZXNzaW9uLmdyb3Vwc1twcm9qZWN0XSA9IGV4dGVuZGVkR3JvdXA7XG4gICAgICAgIH0pO1xuICAgICAgICB0aGlzLnNlc3Npb25NYW5hZ2VyLnNhdmVTZXNzaW9uKHNlc3Npb24pO1xuICAgICAgICByZXR1cm4gc2Vzc2lvbjtcbiAgICB9XG59KTtcblxubW9kdWxlLmV4cG9ydHMgPSBBdXRoTWFuYWdlcjtcbiIsIid1c2Ugc3RyaWN0JztcblxuLyoqXG4gKiAjIyBDaGFubmVsIE1hbmFnZXJcbiAqXG4gKiBUaGVyZSBhcmUgdHdvIG1haW4gdXNlIGNhc2VzIGZvciB0aGUgY2hhbm5lbDogZXZlbnQgbm90aWZpY2F0aW9ucyBhbmQgY2hhdCBtZXNzYWdlcy5cbiAqXG4gKiBJZiB5b3UgYXJlIGRldmVsb3Bpbmcgd2l0aCBFcGljZW50ZXIuanMsIHlvdSBzaG91bGQgdXNlIHRoZSBbRXBpY2VudGVyIENoYW5uZWwgTWFuYWdlcl0oLi4vZXBpY2VudGVyLWNoYW5uZWwtbWFuYWdlci8pIHJhdGhlciB0aGFuIHRoaXMgbW9yZSBnZW5lcmljIENoYW5uZWwgTWFuYWdlci4gKFRoZSBFcGljZW50ZXIgQ2hhbm5lbCBNYW5hZ2VyIGlzIGEgd3JhcHBlciB0aGF0IGluc3RhbnRpYXRlcyBhIENoYW5uZWwgTWFuYWdlciB3aXRoIEVwaWNlbnRlci1zcGVjaWZpYyBkZWZhdWx0cy4pIFRoZSBFcGljZW50ZXIgQ2hhbm5lbCBNYW5hZ2VyIGRvY3VtZW50YXRpb24gYWxzbyBoYXMgbW9yZSBbYmFja2dyb3VuZF0oLi4vZXBpY2VudGVyLWNoYW5uZWwtbWFuYWdlci8jYmFja2dyb3VuZCkgaW5mb3JtYXRpb24gb24gY2hhbm5lbHMgYW5kIHRoZWlyIHVzZS4gXG4gKlxuICogSG93ZXZlciwgeW91IGNhbiB3b3JrIGRpcmVjdGx5IHdpdGggdGhlIENoYW5uZWwgTWFuYWdlciBpZiB5b3UgbGlrZS4gKFRoaXMgbWlnaHQgYmUgdXNlZnVsIGlmIHlvdSBhcmUgd29ya2luZyB0aHJvdWdoIE5vZGUuanMsIGZvciBleGFtcGxlLCBgcmVxdWlyZSgnbWFuYWdlci9jaGFubmVsLW1hbmFnZXInKWAuKVxuICpcbiAqIFRoZSBDaGFubmVsIE1hbmFnZXIgaXMgYSB3cmFwcGVyIGFyb3VuZCB0aGUgZGVmYXVsdCBbY29tZXRkIEphdmFTY3JpcHQgbGlicmFyeV0oaHR0cDovL2RvY3MuY29tZXRkLm9yZy8yL3JlZmVyZW5jZS9qYXZhc2NyaXB0Lmh0bWwpLCBgJC5jb21ldGRgLiBJdCBwcm92aWRlcyBhIGZldyBuaWNlIGZlYXR1cmVzIHRoYXQgYCQuY29tZXRkYCBkb2Vzbid0LCBpbmNsdWRpbmc6XG4gKlxuICogKiBBdXRvbWF0aWMgcmUtc3Vic2NyaXB0aW9uIHRvIGNoYW5uZWxzIGlmIHlvdSBsb3NlIHlvdXIgY29ubmVjdGlvblxuICogKiBPbmxpbmUgLyBPZmZsaW5lIG5vdGlmaWNhdGlvbnNcbiAqICogJ0V2ZW50cycgZm9yIGNvbWV0ZCBub3RpZmljYXRpb25zIChpbnN0ZWFkIG9mIGhhdmluZyB0byBsaXN0ZW4gb24gc3BlY2lmaWMgbWV0YSBjaGFubmVscylcbiAqXG4gKiBZb3UnbGwgbmVlZCB0byBpbmNsdWRlIHRoZSBgZXBpY2VudGVyLW11bHRpcGxheWVyLWRlcGVuZGVuY2llcy5qc2AgbGlicmFyeSBpbiBhZGRpdGlvbiB0byB0aGUgYGVwaWNlbnRlci5qc2AgbGlicmFyeSBpbiB5b3VyIHByb2plY3QgdG8gdXNlIHRoZSBDaGFubmVsIE1hbmFnZXIuIChTZWUgW0luY2x1ZGluZyBFcGljZW50ZXIuanNdKC4uLy4uLyNpbmNsdWRlKS4pXG4gKlxuICogVG8gdXNlIHRoZSBDaGFubmVsIE1hbmFnZXIgaW4gY2xpZW50LXNpZGUgSmF2YVNjcmlwdCwgaW5zdGFudGlhdGUgdGhlIFtFcGljZW50ZXIgQ2hhbm5lbCBNYW5hZ2VyXSguLi9lcGljZW50ZXItY2hhbm5lbC1tYW5hZ2VyLyksIGdldCBhIHBhcnRpY3VsYXIgY2hhbm5lbCAtLSB0aGF0IGlzLCBhbiBpbnN0YW5jZSBvZiBhIFtDaGFubmVsIFNlcnZpY2VdKC4uL2NoYW5uZWwtc2VydmljZS8pIC0tIHRoZW4gdXNlIHRoZSBjaGFubmVsJ3MgYHN1YnNjcmliZSgpYCBhbmQgYHB1Ymxpc2goKWAgbWV0aG9kcyB0byBzdWJzY3JpYmUgdG8gdG9waWNzIG9yIHB1Ymxpc2ggZGF0YSB0byB0b3BpY3MuXG4gKlxuICogICAgICB2YXIgY20gPSBuZXcgRi5tYW5hZ2VyLkNoYW5uZWxNYW5hZ2VyKCk7XG4gKiAgICAgIHZhciBnYyA9IGNtLmdldEdyb3VwQ2hhbm5lbCgpO1xuICogICAgICAvLyBiZWNhdXNlIHdlIHVzZWQgYW4gRXBpY2VudGVyIENoYW5uZWwgTWFuYWdlciB0byBnZXQgdGhlIGdyb3VwIGNoYW5uZWwsXG4gKiAgICAgIC8vIHN1YnNjcmliZSgpIGFuZCBwdWJsaXNoKCkgaGVyZSBkZWZhdWx0IHRvIHRoZSBiYXNlIHRvcGljIGZvciB0aGUgZ3JvdXA7XG4gKiAgICAgIGdjLnN1YnNjcmliZSgnJywgZnVuY3Rpb24oZGF0YSkgeyBjb25zb2xlLmxvZyhkYXRhKTsgfSk7XG4gKiAgICAgIGdjLnB1Ymxpc2goJycsIHsgbWVzc2FnZTogJ2EgbmV3IG1lc3NhZ2UgdG8gdGhlIGdyb3VwJyB9KTtcbiAqXG4gKiBUaGUgcGFyYW1ldGVycyBmb3IgaW5zdGFudGlhdGluZyBhIENoYW5uZWwgTWFuYWdlciBpbmNsdWRlOlxuICpcbiAqICogYG9wdGlvbnNgIFRoZSBvcHRpb25zIG9iamVjdCB0byBjb25maWd1cmUgdGhlIENoYW5uZWwgTWFuYWdlci4gQmVzaWRlcyB0aGUgY29tbW9uIG9wdGlvbnMgbGlzdGVkIGhlcmUsIHNlZSBodHRwOi8vZG9jcy5jb21ldGQub3JnL3JlZmVyZW5jZS9qYXZhc2NyaXB0Lmh0bWwgZm9yIG90aGVyIHN1cHBvcnRlZCBvcHRpb25zLlxuICogKiBgb3B0aW9ucy51cmxgIFRoZSBDb21ldGQgZW5kcG9pbnQgVVJMLlxuICogKiBgb3B0aW9ucy53ZWJzb2NrZXRFbmFibGVkYCBXaGV0aGVyIHdlYnNvY2tldCBzdXBwb3J0IGlzIGFjdGl2ZSAoYm9vbGVhbikuXG4gKiAqIGBvcHRpb25zLmNoYW5uZWxgIE90aGVyIGRlZmF1bHRzIHRvIHBhc3Mgb24gdG8gaW5zdGFuY2VzIG9mIHRoZSB1bmRlcmx5aW5nIENoYW5uZWwgU2VydmljZS4gU2VlIFtDaGFubmVsIFNlcnZpY2VdKC4uL2NoYW5uZWwtc2VydmljZS8pIGZvciBkZXRhaWxzLlxuICpcbiAqL1xuXG52YXIgQ2hhbm5lbCA9IHJlcXVpcmUoJy4uL3NlcnZpY2UvY2hhbm5lbC1zZXJ2aWNlJyk7XG52YXIgU2Vzc2lvbk1hbmFnZXIgPSByZXF1aXJlKCcuLi9zdG9yZS9zZXNzaW9uLW1hbmFnZXInKTtcblxudmFyIENoYW5uZWxNYW5hZ2VyID0gZnVuY3Rpb24gKG9wdGlvbnMpIHtcbiAgICBpZiAoISQuY29tZXRkKSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcignQ29tZXRkIGxpYnJhcnkgbm90IGZvdW5kLiBQbGVhc2UgaW5jbHVkZSBlcGljZW50ZXItbXVsdGlwbGF5ZXItZGVwZW5kZW5jaWVzLmpzJyk7XG4gICAgfVxuICAgIGlmICghb3B0aW9ucyB8fCAhb3B0aW9ucy51cmwpIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdQbGVhc2UgcHJvdmlkZSBhbiB1cmwgZm9yIHRoZSBjb21ldGQgc2VydmVyJyk7XG4gICAgfVxuXG4gICAgdmFyIGRlZmF1bHRzID0ge1xuICAgICAgICAvKipcbiAgICAgICAgICogVGhlIENvbWV0ZCBlbmRwb2ludCBVUkwuXG4gICAgICAgICAqIEB0eXBlIHtzdHJpbmd9XG4gICAgICAgICAqL1xuICAgICAgICB1cmw6ICcnLFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBUaGUgbG9nIGxldmVsIGZvciB0aGUgY2hhbm5lbCAobG9ncyB0byBjb25zb2xlKS5cbiAgICAgICAgICogQHR5cGUge3N0cmluZ31cbiAgICAgICAgICovXG4gICAgICAgIGxvZ0xldmVsOiAnaW5mbycsXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIFdoZXRoZXIgd2Vic29ja2V0IHN1cHBvcnQgaXMgYWN0aXZlLiBEZWZhdWx0cyB0byBgdHJ1ZWAuXG4gICAgICAgICAqIEB0eXBlIHtib29sZWFufVxuICAgICAgICAgKi9cbiAgICAgICAgd2Vic29ja2V0RW5hYmxlZDogdHJ1ZSxcblxuICAgICAgICAvKipcbiAgICAgICAgICogV2hldGhlciB0aGUgQUNLIGV4dGVuc2lvbiBpcyBlbmFibGVkLiBEZWZhdWx0cyB0byBgdHJ1ZWAuIFNlZSBbaHR0cHM6Ly9kb2NzLmNvbWV0ZC5vcmcvY3VycmVudC9yZWZlcmVuY2UvI19leHRlbnNpb25zX2Fja25vd2xlZGdlXShodHRwczovL2RvY3MuY29tZXRkLm9yZy9jdXJyZW50L3JlZmVyZW5jZS8jX2V4dGVuc2lvbnNfYWNrbm93bGVkZ2UpIGZvciBtb3JlIGluZm8uXG4gICAgICAgICAqIEB0eXBlIHtib29sZWFufVxuICAgICAgICAgKi9cbiAgICAgICAgYWNrRW5hYmxlZDogdHJ1ZSxcblxuICAgICAgICAvKipcbiAgICAgICAgICogSWYgZmFsc2UgZWFjaCBpbnN0YW5jZSBvZiBDaGFubmVsIHdpbGwgaGF2ZSBhIHNlcGFyYXRlIGNvbWV0ZCBjb25uZWN0aW9uIHRvIHNlcnZlciwgd2hpY2ggY291bGQgYmUgbm9pc3kuIFNldCB0byB0cnVlIHRvIHJlLXVzZSB0aGUgc2FtZSBjb25uZWN0aW9uIGFjcm9zcyBpbnN0YW5jZXMuXG4gICAgICAgICAqIEB0eXBlIHtib29sZWFufVxuICAgICAgICAgKi9cbiAgICAgICAgc2hhcmVDb25uZWN0aW9uOiBmYWxzZSxcblxuICAgICAgICAvKipcbiAgICAgICAgICogT3RoZXIgZGVmYXVsdHMgdG8gcGFzcyBvbiB0byBpbnN0YW5jZXMgb2YgdGhlIHVuZGVybHlpbmcgW0NoYW5uZWwgU2VydmljZV0oLi4vY2hhbm5lbC1zZXJ2aWNlLyksIHdoaWNoIGFyZSBjcmVhdGVkIHRocm91Z2ggYGdldENoYW5uZWwoKWAuXG4gICAgICAgICAqIEB0eXBlIHtvYmplY3R9XG4gICAgICAgICAqL1xuICAgICAgICBjaGFubmVsOiB7XG5cbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgICogT3B0aW9ucyB0byBwYXNzIHRvIHRoZSBjaGFubmVsIGhhbmRzaGFrZS5cbiAgICAgICAgICpcbiAgICAgICAgICogRm9yIGV4YW1wbGUsIHRoZSBbRXBpY2VudGVyIENoYW5uZWwgTWFuYWdlcl0oLi4vZXBpY2VudGVyLWNoYW5uZWwtbWFuYWdlci8pIHBhc3NlcyBgZXh0YCBhbmQgYXV0aG9yaXphdGlvbiBpbmZvcm1hdGlvbi4gTW9yZSBpbmZvcm1hdGlvbiBvbiBwb3NzaWJsZSBvcHRpb25zIGlzIGluIHRoZSBkZXRhaWxzIG9mIHRoZSB1bmRlcmx5aW5nIFtQdXNoIENoYW5uZWwgQVBJXSguLi8uLi8uLi9yZXN0X2FwaXMvbXVsdGlwbGF5ZXIvY2hhbm5lbC8pLlxuICAgICAgICAgKlxuICAgICAgICAgKiBAdHlwZSB7b2JqZWN0fVxuICAgICAgICAgKi9cbiAgICAgICAgaGFuZHNoYWtlOiB1bmRlZmluZWRcbiAgICB9O1xuICAgIHRoaXMuc2Vzc2lvbk1hbmFnZXIgPSBuZXcgU2Vzc2lvbk1hbmFnZXIoKTtcbiAgICB2YXIgZGVmYXVsdENvbWV0T3B0aW9ucyA9IHRoaXMuc2Vzc2lvbk1hbmFnZXIuZ2V0TWVyZ2VkT3B0aW9ucyhkZWZhdWx0cywgb3B0aW9ucyk7XG4gICAgdGhpcy5jdXJyZW50U3Vic2NyaXB0aW9ucyA9IFtdO1xuICAgIHRoaXMub3B0aW9ucyA9IGRlZmF1bHRDb21ldE9wdGlvbnM7XG5cbiAgICBpZiAoZGVmYXVsdENvbWV0T3B0aW9ucy5zaGFyZUNvbm5lY3Rpb24gJiYgQ2hhbm5lbE1hbmFnZXIucHJvdG90eXBlLl9jb21ldGQpIHtcbiAgICAgICAgdGhpcy5jb21ldGQgPSBDaGFubmVsTWFuYWdlci5wcm90b3R5cGUuX2NvbWV0ZDtcbiAgICAgICAgcmV0dXJuIHRoaXM7XG4gICAgfVxuICAgIHZhciBjb21ldGQgPSBuZXcgJC5Db21ldEQoKTtcbiAgICBDaGFubmVsTWFuYWdlci5wcm90b3R5cGUuX2NvbWV0ZCA9IGNvbWV0ZDtcblxuICAgIGNvbWV0ZC53ZWJzb2NrZXRFbmFibGVkID0gZGVmYXVsdENvbWV0T3B0aW9ucy53ZWJzb2NrZXRFbmFibGVkO1xuICAgIGNvbWV0ZC5hY2tFbmFibGVkID0gZGVmYXVsdENvbWV0T3B0aW9ucy5hY2tFbmFibGVkO1xuXG4gICAgdGhpcy5pc0Nvbm5lY3RlZCA9IGZhbHNlO1xuICAgIHZhciBjb25uZWN0aW9uQnJva2VuID0gZnVuY3Rpb24gKG1lc3NhZ2UpIHtcbiAgICAgICAgJCh0aGlzKS50cmlnZ2VyKCdkaXNjb25uZWN0JywgbWVzc2FnZSk7XG4gICAgfTtcbiAgICB2YXIgY29ubmVjdGlvblN1Y2NlZWRlZCA9IGZ1bmN0aW9uIChtZXNzYWdlKSB7XG4gICAgICAgICQodGhpcykudHJpZ2dlcignY29ubmVjdCcsIG1lc3NhZ2UpO1xuICAgIH07XG4gICAgdmFyIG1lID0gdGhpcztcblxuICAgIGNvbWV0ZC5jb25maWd1cmUoZGVmYXVsdENvbWV0T3B0aW9ucyk7XG5cbiAgICBjb21ldGQuYWRkTGlzdGVuZXIoJy9tZXRhL2Nvbm5lY3QnLCBmdW5jdGlvbiAobWVzc2FnZSkge1xuICAgICAgICB2YXIgd2FzQ29ubmVjdGVkID0gdGhpcy5pc0Nvbm5lY3RlZDtcbiAgICAgICAgdGhpcy5pc0Nvbm5lY3RlZCA9IChtZXNzYWdlLnN1Y2Nlc3NmdWwgPT09IHRydWUpO1xuICAgICAgICBpZiAoIXdhc0Nvbm5lY3RlZCAmJiB0aGlzLmlzQ29ubmVjdGVkKSB7IC8vQ29ubmVjdGluZyBmb3IgdGhlIGZpcnN0IHRpbWVcbiAgICAgICAgICAgIGNvbm5lY3Rpb25TdWNjZWVkZWQuY2FsbCh0aGlzLCBtZXNzYWdlKTtcbiAgICAgICAgfSBlbHNlIGlmICh3YXNDb25uZWN0ZWQgJiYgIXRoaXMuaXNDb25uZWN0ZWQpIHsgLy9Pbmx5IHRocm93IGRpc2Nvbm5lY3RlZCBtZXNzYWdlIGZybyB0aGUgZmlyc3QgZGlzY29ubmVjdCwgbm90IG9uY2UgcGVyIHRyeVxuICAgICAgICAgICAgY29ubmVjdGlvbkJyb2tlbi5jYWxsKHRoaXMsIG1lc3NhZ2UpO1xuICAgICAgICB9XG4gICAgfS5iaW5kKHRoaXMpKTtcblxuICAgIGNvbWV0ZC5hZGRMaXN0ZW5lcignL21ldGEvZGlzY29ubmVjdCcsIGNvbm5lY3Rpb25Ccm9rZW4pO1xuXG4gICAgY29tZXRkLmFkZExpc3RlbmVyKCcvbWV0YS9oYW5kc2hha2UnLCBmdW5jdGlvbiAobWVzc2FnZSkge1xuICAgICAgICBpZiAobWVzc2FnZS5zdWNjZXNzZnVsKSB7XG4gICAgICAgICAgICAvL2h0dHA6Ly9kb2NzLmNvbWV0ZC5vcmcvcmVmZXJlbmNlL2phdmFzY3JpcHRfc3Vic2NyaWJlLmh0bWwjamF2YXNjcmlwdF9zdWJzY3JpYmVfbWV0YV9jaGFubmVsc1xuICAgICAgICAgICAgLy8gXiBcImR5bmFtaWMgc3Vic2NyaXB0aW9ucyBhcmUgY2xlYXJlZCAobGlrZSBhbnkgb3RoZXIgc3Vic2NyaXB0aW9uKSBhbmQgdGhlIGFwcGxpY2F0aW9uIG5lZWRzIHRvIGZpZ3VyZSBvdXQgd2hpY2ggZHluYW1pYyBzdWJzY3JpcHRpb24gbXVzdCBiZSBwZXJmb3JtZWQgYWdhaW5cIlxuICAgICAgICAgICAgY29tZXRkLmJhdGNoKGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgICAgICAkKG1lLmN1cnJlbnRTdWJzY3JpcHRpb25zKS5lYWNoKGZ1bmN0aW9uIChpbmRleCwgc3Vicykge1xuICAgICAgICAgICAgICAgICAgICBjb21ldGQucmVzdWJzY3JpYmUoc3Vicyk7XG4gICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICB9KTtcbiAgICAgICAgfVxuICAgIH0pO1xuXG4gICAgLy9PdGhlciBpbnRlcmVzdGluZyBldmVudHMgZm9yIHJlZmVyZW5jZVxuICAgIGNvbWV0ZC5hZGRMaXN0ZW5lcignL21ldGEvc3Vic2NyaWJlJywgZnVuY3Rpb24gKG1lc3NhZ2UpIHtcbiAgICAgICAgJChtZSkudHJpZ2dlcignc3Vic2NyaWJlJywgbWVzc2FnZSk7XG4gICAgfSk7XG4gICAgY29tZXRkLmFkZExpc3RlbmVyKCcvbWV0YS91bnN1YnNjcmliZScsIGZ1bmN0aW9uIChtZXNzYWdlKSB7XG4gICAgICAgICQobWUpLnRyaWdnZXIoJ3Vuc3Vic2NyaWJlJywgbWVzc2FnZSk7XG4gICAgfSk7XG4gICAgY29tZXRkLmFkZExpc3RlbmVyKCcvbWV0YS9wdWJsaXNoJywgZnVuY3Rpb24gKG1lc3NhZ2UpIHtcbiAgICAgICAgJChtZSkudHJpZ2dlcigncHVibGlzaCcsIG1lc3NhZ2UpO1xuICAgIH0pO1xuICAgIGNvbWV0ZC5hZGRMaXN0ZW5lcignL21ldGEvdW5zdWNjZXNzZnVsJywgZnVuY3Rpb24gKG1lc3NhZ2UpIHtcbiAgICAgICAgJChtZSkudHJpZ2dlcignZXJyb3InLCBtZXNzYWdlKTtcbiAgICB9KTtcblxuICAgIGNvbWV0ZC5oYW5kc2hha2UoZGVmYXVsdENvbWV0T3B0aW9ucy5oYW5kc2hha2UpO1xuXG4gICAgdGhpcy5jb21ldGQgPSBjb21ldGQ7XG59O1xuXG5cbkNoYW5uZWxNYW5hZ2VyLnByb3RvdHlwZSA9ICQuZXh0ZW5kKENoYW5uZWxNYW5hZ2VyLnByb3RvdHlwZSwge1xuXG4gICAgLyoqXG4gICAgICogQ3JlYXRlcyBhbmQgcmV0dXJucyBhIGNoYW5uZWwsIHRoYXQgaXMsIGFuIGluc3RhbmNlIG9mIGEgW0NoYW5uZWwgU2VydmljZV0oLi4vY2hhbm5lbC1zZXJ2aWNlLykuXG4gICAgICpcbiAgICAgKiAqKkV4YW1wbGUqKlxuICAgICAqXG4gICAgICogICAgICB2YXIgY20gPSBuZXcgRi5tYW5hZ2VyLkNoYW5uZWxNYW5hZ2VyKCk7XG4gICAgICogICAgICB2YXIgY2hhbm5lbCA9IGNtLmdldENoYW5uZWwoKTtcbiAgICAgKlxuICAgICAqICAgICAgY2hhbm5lbC5zdWJzY3JpYmUoJ3RvcGljJywgY2FsbGJhY2spO1xuICAgICAqICAgICAgY2hhbm5lbC5wdWJsaXNoKCd0b3BpYycsIHsgbXlEYXRhOiAxMDAgfSk7XG4gICAgICpcbiAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAqIEBwYXJhbSB7T2JqZWN0fFN0cmluZ30gb3B0aW9ucyAoT3B0aW9uYWwpIElmIHN0cmluZywgYXNzdW1lZCB0byBiZSB0aGUgYmFzZSBjaGFubmVsIHVybC4gSWYgb2JqZWN0LCBhc3N1bWVkIHRvIGJlIGNvbmZpZ3VyYXRpb24gb3B0aW9ucyBmb3IgdGhlIGNvbnN0cnVjdG9yLlxuICAgICAqIEByZXR1cm4ge0NoYW5uZWx9IENoYW5uZWwgaW5zdGFuY2VcbiAgICAgKi9cbiAgICBnZXRDaGFubmVsOiBmdW5jdGlvbiAob3B0aW9ucykge1xuICAgICAgICAvL0lmIHlvdSBqdXN0IHdhbnQgdG8gcGFzcyBpbiBhIHN0cmluZ1xuICAgICAgICBpZiAob3B0aW9ucyAmJiAhJC5pc1BsYWluT2JqZWN0KG9wdGlvbnMpKSB7XG4gICAgICAgICAgICBvcHRpb25zID0ge1xuICAgICAgICAgICAgICAgIGJhc2U6IG9wdGlvbnNcbiAgICAgICAgICAgIH07XG4gICAgICAgIH1cbiAgICAgICAgdmFyIGRlZmF1bHRzID0ge1xuICAgICAgICAgICAgdHJhbnNwb3J0OiB0aGlzLmNvbWV0ZFxuICAgICAgICB9O1xuICAgICAgICB2YXIgY2hhbm5lbCA9IG5ldyBDaGFubmVsKCQuZXh0ZW5kKHRydWUsIHt9LCB0aGlzLm9wdGlvbnMuY2hhbm5lbCwgZGVmYXVsdHMsIG9wdGlvbnMpKTtcblxuXG4gICAgICAgIC8vV3JhcCBzdWJzIGFuZCB1bnN1YnMgc28gd2UgY2FuIHVzZSBpdCB0byByZS1hdHRhY2ggaGFuZGxlcnMgYWZ0ZXIgYmVpbmcgZGlzY29ubmVjdGVkXG4gICAgICAgIHZhciBzdWJzID0gY2hhbm5lbC5zdWJzY3JpYmU7XG4gICAgICAgIGNoYW5uZWwuc3Vic2NyaWJlID0gZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgdmFyIHN1YmlkID0gc3Vicy5hcHBseShjaGFubmVsLCBhcmd1bWVudHMpO1xuICAgICAgICAgICAgdGhpcy5jdXJyZW50U3Vic2NyaXB0aW9ucyA9IHRoaXMuY3VycmVudFN1YnNjcmlwdGlvbnMuY29uY2F0KHN1YmlkKTtcbiAgICAgICAgICAgIHJldHVybiBzdWJpZDtcbiAgICAgICAgfS5iaW5kKHRoaXMpO1xuXG5cbiAgICAgICAgdmFyIHVuc3VicyA9IGNoYW5uZWwudW5zdWJzY3JpYmU7XG4gICAgICAgIGNoYW5uZWwudW5zdWJzY3JpYmUgPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICB2YXIgcmVtb3ZlZCA9IHVuc3Vicy5hcHBseShjaGFubmVsLCBhcmd1bWVudHMpO1xuICAgICAgICAgICAgZm9yICh2YXIgaSA9IDA7IGkgPCB0aGlzLmN1cnJlbnRTdWJzY3JpcHRpb25zLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgICAgICAgICAgaWYgKHRoaXMuY3VycmVudFN1YnNjcmlwdGlvbnNbaV0uaWQgPT09IHJlbW92ZWQuaWQpIHtcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5jdXJyZW50U3Vic2NyaXB0aW9ucy5zcGxpY2UoaSwgMSk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICAgICAgcmV0dXJuIHJlbW92ZWQ7XG4gICAgICAgIH0uYmluZCh0aGlzKTtcblxuICAgICAgICByZXR1cm4gY2hhbm5lbDtcbiAgICB9LFxuXG4gICAgLyoqXG4gICAgICogU3RhcnQgbGlzdGVuaW5nIGZvciBldmVudHMgb24gdGhpcyBpbnN0YW5jZS4gU2lnbmF0dXJlIGlzIHNhbWUgYXMgZm9yIGpRdWVyeSBFdmVudHM6IGh0dHA6Ly9hcGkuanF1ZXJ5LmNvbS9vbi8uXG4gICAgICpcbiAgICAgKiBTdXBwb3J0ZWQgZXZlbnRzIGFyZTogYGNvbm5lY3RgLCBgZGlzY29ubmVjdGAsIGBzdWJzY3JpYmVgLCBgdW5zdWJzY3JpYmVgLCBgcHVibGlzaGAsIGBlcnJvcmAuXG4gICAgICpcbiAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAqXG4gICAgICogQHBhcmFtIHtzdHJpbmd9IGV2ZW50IFRoZSBldmVudCB0eXBlLiBTZWUgbW9yZSBkZXRhaWwgYXQgalF1ZXJ5IEV2ZW50czogaHR0cDovL2FwaS5qcXVlcnkuY29tL29uLy5cbiAgICAgKi9cbiAgICBvbjogZnVuY3Rpb24gKGV2ZW50KSB7XG4gICAgICAgICQodGhpcykub24uYXBwbHkoJCh0aGlzKSwgYXJndW1lbnRzKTtcbiAgICB9LFxuXG4gICAgLyoqXG4gICAgICogU3RvcCBsaXN0ZW5pbmcgZm9yIGV2ZW50cyBvbiB0aGlzIGluc3RhbmNlLiBTaWduYXR1cmUgaXMgc2FtZSBhcyBmb3IgalF1ZXJ5IEV2ZW50czogaHR0cDovL2FwaS5qcXVlcnkuY29tL29mZi8uXG4gICAgICpcbiAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAqXG4gICAgICogQHBhcmFtIHtzdHJpbmd9IGV2ZW50IFRoZSBldmVudCB0eXBlLiBTZWUgbW9yZSBkZXRhaWwgYXQgalF1ZXJ5IEV2ZW50czogaHR0cDovL2FwaS5qcXVlcnkuY29tL29mZi8uXG4gICAgICovXG4gICAgb2ZmOiBmdW5jdGlvbiAoZXZlbnQpIHtcbiAgICAgICAgJCh0aGlzKS5vZmYuYXBwbHkoJCh0aGlzKSwgYXJndW1lbnRzKTtcbiAgICB9LFxuXG4gICAgLyoqXG4gICAgICogVHJpZ2dlciBldmVudHMgYW5kIGV4ZWN1dGUgaGFuZGxlcnMuIFNpZ25hdHVyZSBpcyBzYW1lIGFzIGZvciBqUXVlcnkgRXZlbnRzOiBodHRwOi8vYXBpLmpxdWVyeS5jb20vdHJpZ2dlci8uXG4gICAgICpcbiAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAqXG4gICAgICogQHBhcmFtIHtzdHJpbmd9IGV2ZW50IFRoZSBldmVudCB0eXBlLiBTZWUgbW9yZSBkZXRhaWwgYXQgalF1ZXJ5IEV2ZW50czogaHR0cDovL2FwaS5qcXVlcnkuY29tL3RyaWdnZXIvLlxuICAgICAqL1xuICAgIHRyaWdnZXI6IGZ1bmN0aW9uIChldmVudCkge1xuICAgICAgICAkKHRoaXMpLnRyaWdnZXIuYXBwbHkoJCh0aGlzKSwgYXJndW1lbnRzKTtcbiAgICB9XG59KTtcblxubW9kdWxlLmV4cG9ydHMgPSBDaGFubmVsTWFuYWdlcjtcbiIsIid1c2Ugc3RyaWN0JztcblxuLyoqXG4gKiAjIyBFcGljZW50ZXIgQ2hhbm5lbCBNYW5hZ2VyXG4gKlxuICogVGhlIEVwaWNlbnRlciBwbGF0Zm9ybSBwcm92aWRlcyBhIHB1c2ggY2hhbm5lbCwgd2hpY2ggYWxsb3dzIHlvdSB0byBwdWJsaXNoIGFuZCBzdWJzY3JpYmUgdG8gbWVzc2FnZXMgd2l0aGluIGEgW3Byb2plY3RdKC4uLy4uLy4uL2dsb3NzYXJ5LyNwcm9qZWN0cyksIFtncm91cF0oLi4vLi4vLi4vZ2xvc3NhcnkvI2dyb3VwcyksIG9yIFttdWx0aXBsYXllciB3b3JsZF0oLi4vLi4vLi4vZ2xvc3NhcnkvI3dvcmxkKS5cbiAqXG4gKiA8YSBuYW1lPVwiYmFja2dyb3VuZFwiPjwvYT5cbiAqICMjIyBDaGFubmVsIEJhY2tncm91bmRcbiAqXG4gKiBDaGFubmVsIG5vdGlmaWNhdGlvbnMgYXJlIG9ubHkgYXZhaWxhYmxlIGZvciBbdGVhbSBwcm9qZWN0c10oLi4vLi4vLi4vZ2xvc3NhcnkvI3RlYW0pLiBUaGVyZSBhcmUgdHdvIG1haW4gdXNlIGNhc2VzIGZvciB0aGUgcHVzaCBjaGFubmVsOiBldmVudCBub3RpZmljYXRpb25zIGFuZCBjaGF0IG1lc3NhZ2VzLlxuICpcbiAqICMjIyMgRXZlbnQgTm90aWZpY2F0aW9uc1xuICpcbiAqIFdpdGhpbiBhIFttdWx0aXBsYXllciBzaW11bGF0aW9uIG9yIHdvcmxkXSguLi8uLi8uLi9nbG9zc2FyeS8jd29ybGQpLCBpdCBpcyBvZnRlbiB1c2VmdWwgZm9yIHlvdXIgcHJvamVjdCdzIFttb2RlbF0oLi4vLi4vLi4vd3JpdGluZ195b3VyX21vZGVsLykgdG8gYWxlcnQgdGhlIFt1c2VyIGludGVyZmFjZSAoYnJvd3NlcildKC4uLy4uLy4uL2NyZWF0aW5nX3lvdXJfaW50ZXJmYWNlLykgdGhhdCBzb21ldGhpbmcgbmV3IGhhcyBoYXBwZW5lZC5cbiAqXG4gKiBVc3VhbGx5LCB0aGlzIFwic29tZXRoaW5nIG5ld1wiIGlzIGFuIGV2ZW50IHdpdGhpbiB0aGUgcHJvamVjdCwgZ3JvdXAsIG9yIHdvcmxkLCBzdWNoIGFzOlxuICpcbiAqICogQW4gZW5kIHVzZXIgY29tZXMgb25saW5lIChsb2dzIGluKSBvciBnb2VzIG9mZmxpbmUuIChUaGlzIGlzIGVzcGVjaWFsbHkgaW50ZXJlc3RpbmcgaW4gYSBtdWx0aXBsYXllciB3b3JsZDsgb25seSBhdmFpbGFibGUgaWYgeW91IGhhdmUgW2VuYWJsZWQgYXV0aG9yaXphdGlvbl0oLi4vLi4vLi4vdXBkYXRpbmdfeW91cl9zZXR0aW5ncy8jZ2VuZXJhbC1zZXR0aW5ncykgZm9yIHRoZSBjaGFubmVsLilcbiAqICogQW4gZW5kIHVzZXIgaXMgYXNzaWduZWQgdG8gYSB3b3JsZC5cbiAqICogQW4gZW5kIHVzZXIgdXBkYXRlcyBhIHZhcmlhYmxlIC8gbWFrZXMgYSBkZWNpc2lvbi5cbiAqICogQW4gZW5kIHVzZXIgY3JlYXRlcyBvciB1cGRhdGVzIGRhdGEgc3RvcmVkIGluIHRoZSBbRGF0YSBBUEldKC4uL2RhdGEtYXBpLXNlcnZpY2UvKS5cbiAqICogQW4gb3BlcmF0aW9uIChtZXRob2QpIGlzIGNhbGxlZC4gKFRoaXMgaXMgZXNwZWNpYWxseSBpbnRlcmVzdGluZyBpZiB0aGUgbW9kZWwgaXMgYWR2YW5jZWQsIGZvciBpbnN0YW5jZSwgdGhlIFZlbnNpbSBgc3RlcGAgb3BlcmF0aW9uIGlzIGNhbGxlZC4pXG4gKlxuICogV2hlbiB0aGVzZSBldmVudHMgb2NjdXIsIHlvdSBvZnRlbiB3YW50IHRvIGhhdmUgdGhlIHVzZXIgaW50ZXJmYWNlIGZvciBvbmUgb3IgbW9yZSBlbmQgdXNlcnMgYXV0b21hdGljYWxseSB1cGRhdGUgd2l0aCBuZXcgaW5mb3JtYXRpb24uXG4gKlxuICogIyMjIyBDaGF0IE1lc3NhZ2VzXG4gKlxuICogQW5vdGhlciByZWFzb24gdG8gdXNlIHRoZSBwdXNoIGNoYW5uZWwgaXMgdG8gYWxsb3cgcGxheWVycyAoZW5kIHVzZXJzKSB0byBzZW5kIGNoYXQgbWVzc2FnZXMgdG8gb3RoZXIgcGxheWVycywgYW5kIHRvIGhhdmUgdGhvc2UgbWVzc2FnZXMgYXBwZWFyIGltbWVkaWF0ZWx5LlxuICpcbiAqICMjIyMgR2V0dGluZyBTdGFydGVkXG4gKlxuICogRm9yIGJvdGggdGhlIGV2ZW50IG5vdGlmaWNhdGlvbiBhbmQgY2hhdCBtZXNzYWdlIHVzZSBjYXNlczpcbiAqXG4gKiAqIEZpcnN0LCBlbmFibGUgY2hhbm5lbCBub3RpZmljYXRpb25zIGZvciB5b3VyIHByb2plY3QuXG4gKiAgICAgICogQ2hhbm5lbCBub3RpZmljYXRpb25zIGFyZSBvbmx5IGF2YWlsYWJsZSBmb3IgW3RlYW0gcHJvamVjdHNdKC4uLy4uLy4uL2dsb3NzYXJ5LyN0ZWFtKS4gVG8gZW5hYmxlIG5vdGlmaWNhdGlvbnMgZm9yIHlvdXIgcHJvamVjdCwgW3VwZGF0ZSB5b3VyIHByb2plY3Qgc2V0dGluZ3NdKC4uLy4uLy4uL3VwZGF0aW5nX3lvdXJfc2V0dGluZ3MvI2dlbmVyYWwtc2V0dGluZ3MpIHRvIHR1cm4gb24gdGhlICoqUHVzaCBDaGFubmVsKiogc2V0dGluZywgYW5kIG9wdGlvbmFsbHkgcmVxdWlyZSBhdXRob3JpemF0aW9uIGZvciB0aGUgY2hhbm5lbC5cbiAqICogVGhlbiwgaW5zdGFudGlhdGUgYW4gRXBpY2VudGVyIENoYW5uZWwgTWFuYWdlci5cbiAqICogTmV4dCwgZ2V0IHRoZSBjaGFubmVsIHdpdGggdGhlIHNjb3BlIHlvdSB3YW50ICh1c2VyLCB3b3JsZCwgZ3JvdXAsIGRhdGEpLlxuICogKiBGaW5hbGx5LCB1c2UgdGhlIGNoYW5uZWwncyBgc3Vic2NyaWJlKClgIGFuZCBgcHVibGlzaCgpYCBtZXRob2RzIHRvIHN1YnNjcmliZSB0byB0b3BpY3Mgb3IgcHVibGlzaCBkYXRhIHRvIHRvcGljcy5cbiAqXG4gKiBIZXJlJ3MgYW4gZXhhbXBsZSBvZiB0aG9zZSBsYXN0IHRocmVlIHN0ZXBzIChpbnN0YW50aWF0ZSwgZ2V0IGNoYW5uZWwsIHN1YnNjcmliZSk6XG4gKlxuICogICAgIHZhciBjbSA9IG5ldyBGLm1hbmFnZXIuQ2hhbm5lbE1hbmFnZXIoKTtcbiAqICAgICB2YXIgZ2MgPSBjbS5nZXRHcm91cENoYW5uZWwoKTtcbiAqICAgICBnYy5zdWJzY3JpYmUoJycsIGZ1bmN0aW9uKGRhdGEpIHsgY29uc29sZS5sb2coZGF0YSk7IH0pO1xuICogICAgIGdjLnB1Ymxpc2goJycsIHsgbWVzc2FnZTogJ2EgbmV3IG1lc3NhZ2UgdG8gdGhlIGdyb3VwJyB9KTtcbiAqXG4gKiBGb3IgYSBtb3JlIGRldGFpbGVkIGV4YW1wbGUsIHNlZSBhIFtjb21wbGV0ZSBwdWJsaXNoIGFuZCBzdWJzY3JpYmUgZXhhbXBsZV0oLi4vLi4vLi4vcmVzdF9hcGlzL211bHRpcGxheWVyL2NoYW5uZWwvI2VwaWpzLWV4YW1wbGUpLlxuICpcbiAqIEZvciBkZXRhaWxzIG9uIHdoYXQgZGF0YSBpcyBwdWJsaXNoZWQgYXV0b21hdGljYWxseSB0byB3aGljaCBjaGFubmVscywgc2VlIFtBdXRvbWF0aWMgUHVibGlzaGluZyBvZiBFdmVudHNdKC4uLy4uLy4uL3Jlc3RfYXBpcy9tdWx0aXBsYXllci9jaGFubmVsLyNwdWJsaXNoLW1lc3NhZ2UtYXV0bykuXG4gKlxuICogIyMjIyBDcmVhdGluZyBhbiBFcGljZW50ZXIgQ2hhbm5lbCBNYW5hZ2VyXG4gKlxuICogVGhlIEVwaWNlbnRlciBDaGFubmVsIE1hbmFnZXIgaXMgYSB3cmFwcGVyIGFyb3VuZCB0aGUgKG1vcmUgZ2VuZXJpYykgW0NoYW5uZWwgTWFuYWdlcl0oLi4vY2hhbm5lbC1tYW5hZ2VyLyksIHRvIGluc3RhbnRpYXRlIGl0IHdpdGggRXBpY2VudGVyLXNwZWNpZmljIGRlZmF1bHRzLiBJZiB5b3UgYXJlIGludGVyZXN0ZWQgaW4gaW5jbHVkaW5nIGEgbm90aWZpY2F0aW9uIG9yIGNoYXQgZmVhdHVyZSBpbiB5b3VyIHByb2plY3QsIHVzaW5nIGFuIEVwaWNlbnRlciBDaGFubmVsIE1hbmFnZXIgaXMgdGhlIGVhc2llc3Qgd2F5IHRvIGdldCBzdGFydGVkLlxuICpcbiAqIFlvdSdsbCBuZWVkIHRvIGluY2x1ZGUgdGhlIGBlcGljZW50ZXItbXVsdGlwbGF5ZXItZGVwZW5kZW5jaWVzLmpzYCBsaWJyYXJ5IGluIGFkZGl0aW9uIHRvIHRoZSBgZXBpY2VudGVyLmpzYCBsaWJyYXJ5IGluIHlvdXIgcHJvamVjdCB0byB1c2UgdGhlIEVwaWNlbnRlciBDaGFubmVsIE1hbmFnZXIuIFNlZSBbSW5jbHVkaW5nIEVwaWNlbnRlci5qc10oLi4vLi4vI2luY2x1ZGUpLlxuICpcbiAqIFRoZSBwYXJhbWV0ZXJzIGZvciBpbnN0YW50aWF0aW5nIGFuIEVwaWNlbnRlciBDaGFubmVsIE1hbmFnZXIgaW5jbHVkZTpcbiAqXG4gKiAqIGBvcHRpb25zYCBPYmplY3Qgd2l0aCBkZXRhaWxzIGFib3V0IHRoZSBFcGljZW50ZXIgcHJvamVjdCBmb3IgdGhpcyBFcGljZW50ZXIgQ2hhbm5lbCBNYW5hZ2VyIGluc3RhbmNlLlxuICogKiBgb3B0aW9ucy5hY2NvdW50YCBUaGUgRXBpY2VudGVyIGFjY291bnQgaWQgKCoqVGVhbSBJRCoqIGZvciB0ZWFtIHByb2plY3RzLCAqKlVzZXIgSUQqKiBmb3IgcGVyc29uYWwgcHJvamVjdHMpLlxuICogKiBgb3B0aW9ucy5wcm9qZWN0YCBFcGljZW50ZXIgcHJvamVjdCBpZC5cbiAqICogYG9wdGlvbnMudXNlck5hbWVgIEVwaWNlbnRlciB1c2VyTmFtZSB1c2VkIGZvciBhdXRoZW50aWNhdGlvbi5cbiAqICogYG9wdGlvbnMudXNlcklkYCBFcGljZW50ZXIgdXNlciBpZCB1c2VkIGZvciBhdXRoZW50aWNhdGlvbi4gT3B0aW9uYWw7IGBvcHRpb25zLnVzZXJOYW1lYCBpcyBwcmVmZXJyZWQuXG4gKiAqIGBvcHRpb25zLnRva2VuYCBFcGljZW50ZXIgdG9rZW4gdXNlZCBmb3IgYXV0aGVudGljYXRpb24uIChZb3UgY2FuIHJldHJpZXZlIHRoaXMgdXNpbmcgYGF1dGhNYW5hZ2VyLmdldFRva2VuKClgIGZyb20gdGhlIFtBdXRob3JpemF0aW9uIE1hbmFnZXJdKC4uL2F1dGgtbWFuYWdlci8pLilcbiAqICogYG9wdGlvbnMuYWxsb3dBbGxDaGFubmVsc2AgSWYgbm90IGluY2x1ZGVkIG9yIGlmIHNldCB0byBgZmFsc2VgLCBhbGwgY2hhbm5lbCBwYXRocyBhcmUgdmFsaWRhdGVkOyBpZiB5b3VyIHByb2plY3QgcmVxdWlyZXMgW1B1c2ggQ2hhbm5lbCBBdXRob3JpemF0aW9uXSguLi8uLi8uLi91cGRhdGluZ195b3VyX3NldHRpbmdzLyksIHlvdSBzaG91bGQgdXNlIHRoaXMgb3B0aW9uLiBJZiB5b3Ugd2FudCB0byBhbGxvdyBvdGhlciBjaGFubmVsIHBhdGhzLCBzZXQgdG8gYHRydWVgOyB0aGlzIGlzIG5vdCBjb21tb24uXG4gKi9cblxudmFyIENoYW5uZWxNYW5hZ2VyID0gcmVxdWlyZSgnLi9jaGFubmVsLW1hbmFnZXInKTtcbnZhciBDb25maWdTZXJ2aWNlID0gcmVxdWlyZSgnLi4vc2VydmljZS9jb25maWd1cmF0aW9uLXNlcnZpY2UnKTtcbnZhciBjbGFzc0Zyb20gPSByZXF1aXJlKCcuLi91dGlsL2luaGVyaXQnKTtcbnZhciBTZXNzaW9uTWFuYWdlciA9IHJlcXVpcmUoJy4uL3N0b3JlL3Nlc3Npb24tbWFuYWdlcicpO1xuXG52YXIgdmFsaWRUeXBlcyA9IHtcbiAgICBwcm9qZWN0OiB0cnVlLFxuICAgIGdyb3VwOiB0cnVlLFxuICAgIHdvcmxkOiB0cnVlLFxuICAgIHVzZXI6IHRydWUsXG4gICAgZGF0YTogdHJ1ZSxcbiAgICBnZW5lcmFsOiB0cnVlLFxuICAgIGNoYXQ6IHRydWVcbn07XG52YXIgZ2V0RnJvbVNlc3Npb25PckVycm9yID0gZnVuY3Rpb24gKHZhbHVlLCBzZXNzaW9uS2V5TmFtZSwgc2V0dGluZ3MpIHtcbiAgICBpZiAoIXZhbHVlKSB7XG4gICAgICAgIGlmIChzZXR0aW5ncyAmJiBzZXR0aW5nc1tzZXNzaW9uS2V5TmFtZV0pIHtcbiAgICAgICAgICAgIHZhbHVlID0gc2V0dGluZ3Nbc2Vzc2lvbktleU5hbWVdO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKHNlc3Npb25LZXlOYW1lICsgJyBub3QgZm91bmQuIFBsZWFzZSBsb2ctaW4gYWdhaW4sIG9yIHNwZWNpZnkgJyArIHNlc3Npb25LZXlOYW1lICsgJyBleHBsaWNpdGx5Jyk7XG4gICAgICAgIH1cbiAgICB9XG4gICAgcmV0dXJuIHZhbHVlO1xufTtcblxudmFyIGlzUHJlc2VuY2VEYXRhID0gZnVuY3Rpb24gKHBheWxvYWQpIHtcbiAgICByZXR1cm4gcGF5bG9hZC5kYXRhICYmIHBheWxvYWQuZGF0YS50eXBlID09PSAndXNlcicgJiYgcGF5bG9hZC5kYXRhLnVzZXI7XG59O1xuXG52YXIgX19zdXBlciA9IENoYW5uZWxNYW5hZ2VyLnByb3RvdHlwZTtcbnZhciBFcGljZW50ZXJDaGFubmVsTWFuYWdlciA9IGNsYXNzRnJvbShDaGFubmVsTWFuYWdlciwge1xuICAgIGNvbnN0cnVjdG9yOiBmdW5jdGlvbiAob3B0aW9ucykge1xuICAgICAgICB0aGlzLnNlc3Npb25NYW5hZ2VyID0gbmV3IFNlc3Npb25NYW5hZ2VyKG9wdGlvbnMpO1xuICAgICAgICB2YXIgZGVmYXVsdENvbWV0T3B0aW9ucyA9IHRoaXMuc2Vzc2lvbk1hbmFnZXIuZ2V0TWVyZ2VkT3B0aW9ucyhvcHRpb25zKTtcblxuICAgICAgICB2YXIgdXJsQ29uZmlnID0gbmV3IENvbmZpZ1NlcnZpY2UoZGVmYXVsdENvbWV0T3B0aW9ucykuZ2V0KCdzZXJ2ZXInKTtcbiAgICAgICAgaWYgKCFkZWZhdWx0Q29tZXRPcHRpb25zLnVybCkge1xuICAgICAgICAgICAgZGVmYXVsdENvbWV0T3B0aW9ucy51cmwgPSB1cmxDb25maWcuZ2V0QVBJUGF0aCgnY2hhbm5lbCcpO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKGRlZmF1bHRDb21ldE9wdGlvbnMuaGFuZHNoYWtlID09PSB1bmRlZmluZWQpIHtcbiAgICAgICAgICAgIHZhciB1c2VyTmFtZSA9IGRlZmF1bHRDb21ldE9wdGlvbnMudXNlck5hbWU7XG4gICAgICAgICAgICB2YXIgdXNlcklkID0gZGVmYXVsdENvbWV0T3B0aW9ucy51c2VySWQ7XG4gICAgICAgICAgICB2YXIgdG9rZW4gPSBkZWZhdWx0Q29tZXRPcHRpb25zLnRva2VuO1xuICAgICAgICAgICAgaWYgKCh1c2VyTmFtZSB8fCB1c2VySWQpICYmIHRva2VuKSB7XG4gICAgICAgICAgICAgICAgdmFyIHVzZXJQcm9wID0gdXNlck5hbWUgPyAndXNlck5hbWUnIDogJ3VzZXJJZCc7XG4gICAgICAgICAgICAgICAgdmFyIGV4dCA9IHtcbiAgICAgICAgICAgICAgICAgICAgYXV0aG9yaXphdGlvbjogJ0JlYXJlciAnICsgdG9rZW5cbiAgICAgICAgICAgICAgICB9O1xuICAgICAgICAgICAgICAgIGV4dFt1c2VyUHJvcF0gPSB1c2VyTmFtZSA/IHVzZXJOYW1lIDogdXNlcklkO1xuXG4gICAgICAgICAgICAgICAgZGVmYXVsdENvbWV0T3B0aW9ucy5oYW5kc2hha2UgPSB7XG4gICAgICAgICAgICAgICAgICAgIGV4dDogZXh0XG4gICAgICAgICAgICAgICAgfTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuXG4gICAgICAgIHRoaXMub3B0aW9ucyA9IGRlZmF1bHRDb21ldE9wdGlvbnM7XG4gICAgICAgIHJldHVybiBfX3N1cGVyLmNvbnN0cnVjdG9yLmNhbGwodGhpcywgZGVmYXVsdENvbWV0T3B0aW9ucyk7XG4gICAgfSxcblxuICAgIC8qKlxuICAgICAqIENyZWF0ZXMgYW5kIHJldHVybnMgYSBjaGFubmVsLCB0aGF0IGlzLCBhbiBpbnN0YW5jZSBvZiBhIFtDaGFubmVsIFNlcnZpY2VdKC4uL2NoYW5uZWwtc2VydmljZS8pLlxuICAgICAqXG4gICAgICogVGhpcyBtZXRob2QgZW5mb3JjZXMgRXBpY2VudGVyLXNwZWNpZmljIGNoYW5uZWwgbmFtaW5nOiBhbGwgY2hhbm5lbHMgcmVxdWVzdGVkIG11c3QgYmUgaW4gdGhlIGZvcm0gYC97dHlwZX0ve2FjY291bnQgaWR9L3twcm9qZWN0IGlkfS97Li4ufWAsIHdoZXJlIGB0eXBlYCBpcyBvbmUgb2YgYHJ1bmAsIGBkYXRhYCwgYHVzZXJgLCBgd29ybGRgLCBvciBgY2hhdGAuXG4gICAgICpcbiAgICAgKiAqKkV4YW1wbGUqKlxuICAgICAqXG4gICAgICogICAgICB2YXIgY20gPSBuZXcgRi5tYW5hZ2VyLkVwaWNlbnRlckNoYW5uZWxNYW5hZ2VyKCk7XG4gICAgICogICAgICB2YXIgY2hhbm5lbCA9IGNtLmdldENoYW5uZWwoJy9ncm91cC9hY21lL3N1cHBseS1jaGFpbi1nYW1lLycpO1xuICAgICAqXG4gICAgICogICAgICBjaGFubmVsLnN1YnNjcmliZSgndG9waWMnLCBjYWxsYmFjayk7XG4gICAgICogICAgICBjaGFubmVsLnB1Ymxpc2goJ3RvcGljJywgeyBteURhdGE6IDEwMCB9KTtcbiAgICAgKlxuICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICogQHBhcmFtIHtPYmplY3R8U3RyaW5nfSBvcHRpb25zIChPcHRpb25hbCkgSWYgc3RyaW5nLCBhc3N1bWVkIHRvIGJlIHRoZSBiYXNlIGNoYW5uZWwgdXJsLiBJZiBvYmplY3QsIGFzc3VtZWQgdG8gYmUgY29uZmlndXJhdGlvbiBvcHRpb25zIGZvciB0aGUgY29uc3RydWN0b3IuXG4gICAgICogQHJldHVybiB7Q2hhbm5lbH0gQ2hhbm5lbCBpbnN0YW5jZVxuICAgICAqL1xuICAgIGdldENoYW5uZWw6IGZ1bmN0aW9uIChvcHRpb25zKSB7XG4gICAgICAgIGlmIChvcHRpb25zICYmIHR5cGVvZiBvcHRpb25zICE9PSAnb2JqZWN0Jykge1xuICAgICAgICAgICAgb3B0aW9ucyA9IHtcbiAgICAgICAgICAgICAgICBiYXNlOiBvcHRpb25zXG4gICAgICAgICAgICB9O1xuICAgICAgICB9XG4gICAgICAgIHZhciBjaGFubmVsT3B0cyA9ICQuZXh0ZW5kKHt9LCB0aGlzLm9wdGlvbnMsIG9wdGlvbnMpO1xuICAgICAgICB2YXIgYmFzZSA9IGNoYW5uZWxPcHRzLmJhc2U7XG4gICAgICAgIGlmICghYmFzZSkge1xuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdObyBiYXNlIHRvcGljIHdhcyBwcm92aWRlZCcpO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKCFjaGFubmVsT3B0cy5hbGxvd0FsbENoYW5uZWxzKSB7XG4gICAgICAgICAgICB2YXIgYmFzZVBhcnRzID0gYmFzZS5zcGxpdCgnLycpO1xuICAgICAgICAgICAgdmFyIGNoYW5uZWxUeXBlID0gYmFzZVBhcnRzWzFdO1xuICAgICAgICAgICAgaWYgKGJhc2VQYXJ0cy5sZW5ndGggPCA0KSB7IC8vZXNsaW50LWRpc2FibGUtbGluZVxuICAgICAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcignSW52YWxpZCBjaGFubmVsIGJhc2UgbmFtZSwgaXQgbXVzdCBiZSBpbiB0aGUgZm9ybSAve3R5cGV9L3thY2NvdW50IGlkfS97cHJvamVjdCBpZH0vey4uLn0nKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGlmICghdmFsaWRUeXBlc1tjaGFubmVsVHlwZV0pIHtcbiAgICAgICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ0ludmFsaWQgY2hhbm5lbCB0eXBlJyk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIF9fc3VwZXIuZ2V0Q2hhbm5lbC5hcHBseSh0aGlzLCBhcmd1bWVudHMpO1xuICAgIH0sXG5cbiAgICAvKipcbiAgICAgKiBDcmVhdGUgYW5kIHJldHVybiBhIHB1Ymxpc2gvc3Vic2NyaWJlIGNoYW5uZWwgKGZyb20gdGhlIHVuZGVybHlpbmcgW0NoYW5uZWwgTWFuYWdlcl0oLi4vY2hhbm5lbC1tYW5hZ2VyLykpIGZvciB0aGUgZ2l2ZW4gW2dyb3VwXSguLi8uLi8uLi9nbG9zc2FyeS8jZ3JvdXBzKS4gVGhlIGdyb3VwIG11c3QgZXhpc3QgaW4gdGhlIGFjY291bnQgKHRlYW0pIGFuZCBwcm9qZWN0IHByb3ZpZGVkLlxuICAgICAqXG4gICAgICogVGhlcmUgYXJlIG5vIG5vdGlmaWNhdGlvbnMgZnJvbSBFcGljZW50ZXIgb24gdGhpcyBjaGFubmVsOyBhbGwgbWVzc2FnZXMgYXJlIHVzZXItb3JpZ2luYXRlZC5cbiAgICAgKlxuICAgICAqICoqRXhhbXBsZSoqXG4gICAgICpcbiAgICAgKiAgICAgdmFyIGNtID0gbmV3IEYubWFuYWdlci5DaGFubmVsTWFuYWdlcigpO1xuICAgICAqICAgICB2YXIgZ2MgPSBjbS5nZXRHcm91cENoYW5uZWwoKTtcbiAgICAgKiAgICAgZ2Muc3Vic2NyaWJlKCdicm9hZGNhc3RzJywgY2FsbGJhY2spO1xuICAgICAqXG4gICAgICogKipSZXR1cm4gVmFsdWUqKlxuICAgICAqXG4gICAgICogKiAqQ2hhbm5lbCogUmV0dXJucyB0aGUgY2hhbm5lbCAoYW4gaW5zdGFuY2Ugb2YgdGhlIFtDaGFubmVsIFNlcnZpY2VdKC4uL2NoYW5uZWwtc2VydmljZS8pKS5cbiAgICAgKlxuICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICpcbiAgICAgKiBAcGFyYW0gIHtTdHJpbmd9IGdyb3VwTmFtZSAoT3B0aW9uYWwpIEdyb3VwIHRvIGJyb2FkY2FzdCB0by4gSWYgbm90IHByb3ZpZGVkLCBwaWNrcyB1cCBncm91cCBmcm9tIGN1cnJlbnQgc2Vzc2lvbiBpZiBlbmQgdXNlciBpcyBsb2dnZWQgaW4uXG4gICAgICogQHJldHVybiB7Q2hhbm5lbH0gQ2hhbm5lbCBpbnN0YW5jZVxuICAgICAqL1xuICAgIGdldEdyb3VwQ2hhbm5lbDogZnVuY3Rpb24gKGdyb3VwTmFtZSkge1xuICAgICAgICB2YXIgc2Vzc2lvbiA9IHRoaXMuc2Vzc2lvbk1hbmFnZXIuZ2V0TWVyZ2VkT3B0aW9ucyh0aGlzLm9wdGlvbnMpO1xuICAgICAgICBncm91cE5hbWUgPSBnZXRGcm9tU2Vzc2lvbk9yRXJyb3IoZ3JvdXBOYW1lLCAnZ3JvdXBOYW1lJywgc2Vzc2lvbik7XG4gICAgICAgIHZhciBhY2NvdW50ID0gZ2V0RnJvbVNlc3Npb25PckVycm9yKCcnLCAnYWNjb3VudCcsIHNlc3Npb24pO1xuICAgICAgICB2YXIgcHJvamVjdCA9IGdldEZyb21TZXNzaW9uT3JFcnJvcignJywgJ3Byb2plY3QnLCBzZXNzaW9uKTtcblxuICAgICAgICB2YXIgYmFzZVRvcGljID0gWycvZ3JvdXAnLCBhY2NvdW50LCBwcm9qZWN0LCBncm91cE5hbWVdLmpvaW4oJy8nKTtcbiAgICAgICAgdmFyIGNoYW5uZWwgPSBfX3N1cGVyLmdldENoYW5uZWwuY2FsbCh0aGlzLCB7IGJhc2U6IGJhc2VUb3BpYyB9KTtcbiAgICAgICAgdmFyIG9sZHN1YnMgPSBjaGFubmVsLnN1YnNjcmliZTtcbiAgICAgICAgY2hhbm5lbC5zdWJzY3JpYmUgPSBmdW5jdGlvbiAodG9waWMsIGNhbGxiYWNrLCBjb250ZXh0LCBvcHRpb25zKSB7XG4gICAgICAgICAgICB2YXIgY2FsbGJhY2tXaXRob3V0UHJlc2VuY2VEYXRhID0gZnVuY3Rpb24gKHBheWxvYWQpIHtcbiAgICAgICAgICAgICAgICBpZiAoIWlzUHJlc2VuY2VEYXRhKHBheWxvYWQpKSB7XG4gICAgICAgICAgICAgICAgICAgIGNhbGxiYWNrLmNhbGwoY29udGV4dCwgcGF5bG9hZCk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfTtcbiAgICAgICAgICAgIHJldHVybiBvbGRzdWJzLmNhbGwoY2hhbm5lbCwgdG9waWMsIGNhbGxiYWNrV2l0aG91dFByZXNlbmNlRGF0YSwgY29udGV4dCwgb3B0aW9ucyk7XG4gICAgICAgIH07XG4gICAgICAgIHJldHVybiBjaGFubmVsO1xuICAgIH0sXG5cbiAgICAvKipcbiAgICAgKiBDcmVhdGUgYW5kIHJldHVybiBhIHB1Ymxpc2gvc3Vic2NyaWJlIGNoYW5uZWwgKGZyb20gdGhlIHVuZGVybHlpbmcgW0NoYW5uZWwgTWFuYWdlcl0oLi4vY2hhbm5lbC1tYW5hZ2VyLykpIGZvciB0aGUgZ2l2ZW4gW3dvcmxkXSguLi8uLi8uLi9nbG9zc2FyeS8jd29ybGQpLlxuICAgICAqXG4gICAgICogVGhpcyBpcyB0eXBpY2FsbHkgdXNlZCB0b2dldGhlciB3aXRoIHRoZSBbV29ybGQgTWFuYWdlcl0oLi4vd29ybGQtbWFuYWdlcikuXG4gICAgICpcbiAgICAgKiAqKkV4YW1wbGUqKlxuICAgICAqXG4gICAgICogICAgIHZhciBjbSA9IG5ldyBGLm1hbmFnZXIuQ2hhbm5lbE1hbmFnZXIoKTtcbiAgICAgKiAgICAgdmFyIHdvcmxkTWFuYWdlciA9IG5ldyBGLm1hbmFnZXIuV29ybGRNYW5hZ2VyKHtcbiAgICAgKiAgICAgICAgIGFjY291bnQ6ICdhY21lLXNpbXVsYXRpb25zJyxcbiAgICAgKiAgICAgICAgIHByb2plY3Q6ICdzdXBwbHktY2hhaW4tZ2FtZScsXG4gICAgICogICAgICAgICBncm91cDogJ3RlYW0xJyxcbiAgICAgKiAgICAgICAgIHJ1bjogeyBtb2RlbDogJ21vZGVsLmVxbicgfVxuICAgICAqICAgICB9KTtcbiAgICAgKiAgICAgd29ybGRNYW5hZ2VyLmdldEN1cnJlbnRXb3JsZCgpLnRoZW4oZnVuY3Rpb24gKHdvcmxkT2JqZWN0LCB3b3JsZEFkYXB0ZXIpIHtcbiAgICAgKiAgICAgICAgIHZhciB3b3JsZENoYW5uZWwgPSBjbS5nZXRXb3JsZENoYW5uZWwod29ybGRPYmplY3QpO1xuICAgICAqICAgICAgICAgd29ybGRDaGFubmVsLnN1YnNjcmliZSgnJywgZnVuY3Rpb24gKGRhdGEpIHtcbiAgICAgKiAgICAgICAgICAgICBjb25zb2xlLmxvZyhkYXRhKTtcbiAgICAgKiAgICAgICAgIH0pO1xuICAgICAqICAgICAgfSk7XG4gICAgICpcbiAgICAgKiAqKlJldHVybiBWYWx1ZSoqXG4gICAgICpcbiAgICAgKiAqICpDaGFubmVsKiBSZXR1cm5zIHRoZSBjaGFubmVsIChhbiBpbnN0YW5jZSBvZiB0aGUgW0NoYW5uZWwgU2VydmljZV0oLi4vY2hhbm5lbC1zZXJ2aWNlLykpLlxuICAgICAqXG4gICAgICogKipQYXJhbWV0ZXJzKipcbiAgICAgKlxuICAgICAqIEBwYXJhbSAge1N0cmluZ3xPYmplY3R9IHdvcmxkIFRoZSB3b3JsZCBvYmplY3Qgb3IgaWQuXG4gICAgICogQHBhcmFtICB7U3RyaW5nfSBncm91cE5hbWUgKE9wdGlvbmFsKSBHcm91cCB0aGUgd29ybGQgZXhpc3RzIGluLiBJZiBub3QgcHJvdmlkZWQsIHBpY2tzIHVwIGdyb3VwIGZyb20gY3VycmVudCBzZXNzaW9uIGlmIGVuZCB1c2VyIGlzIGxvZ2dlZCBpbi5cbiAgICAgKiBAcmV0dXJuIHtDaGFubmVsfSBDaGFubmVsIGluc3RhbmNlXG4gICAgICovXG4gICAgZ2V0V29ybGRDaGFubmVsOiBmdW5jdGlvbiAod29ybGQsIGdyb3VwTmFtZSkge1xuICAgICAgICB2YXIgd29ybGRpZCA9ICgkLmlzUGxhaW5PYmplY3Qod29ybGQpICYmIHdvcmxkLmlkKSA/IHdvcmxkLmlkIDogd29ybGQ7XG4gICAgICAgIGlmICghd29ybGRpZCkge1xuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdQbGVhc2Ugc3BlY2lmeSBhIHdvcmxkIGlkJyk7XG4gICAgICAgIH1cbiAgICAgICAgdmFyIHNlc3Npb24gPSB0aGlzLnNlc3Npb25NYW5hZ2VyLmdldE1lcmdlZE9wdGlvbnModGhpcy5vcHRpb25zKTtcblxuICAgICAgICBncm91cE5hbWUgPSBnZXRGcm9tU2Vzc2lvbk9yRXJyb3IoZ3JvdXBOYW1lLCAnZ3JvdXBOYW1lJywgc2Vzc2lvbik7XG4gICAgICAgIHZhciBhY2NvdW50ID0gZ2V0RnJvbVNlc3Npb25PckVycm9yKCcnLCAnYWNjb3VudCcsIHNlc3Npb24pO1xuICAgICAgICB2YXIgcHJvamVjdCA9IGdldEZyb21TZXNzaW9uT3JFcnJvcignJywgJ3Byb2plY3QnLCBzZXNzaW9uKTtcblxuICAgICAgICB2YXIgYmFzZVRvcGljID0gWycvd29ybGQnLCBhY2NvdW50LCBwcm9qZWN0LCBncm91cE5hbWUsIHdvcmxkaWRdLmpvaW4oJy8nKTtcbiAgICAgICAgcmV0dXJuIF9fc3VwZXIuZ2V0Q2hhbm5lbC5jYWxsKHRoaXMsIHsgYmFzZTogYmFzZVRvcGljIH0pO1xuICAgIH0sXG5cbiAgICAvKipcbiAgICAgKiBDcmVhdGUgYW5kIHJldHVybiBhIHB1Ymxpc2gvc3Vic2NyaWJlIGNoYW5uZWwgKGZyb20gdGhlIHVuZGVybHlpbmcgW0NoYW5uZWwgTWFuYWdlcl0oLi4vY2hhbm5lbC1tYW5hZ2VyLykpIGZvciB0aGUgY3VycmVudCBbZW5kIHVzZXJdKC4uLy4uLy4uL2dsb3NzYXJ5LyN1c2VycykgaW4gdGhhdCB1c2VyJ3MgY3VycmVudCBbd29ybGRdKC4uLy4uLy4uL2dsb3NzYXJ5LyN3b3JsZCkuXG4gICAgICpcbiAgICAgKiBUaGlzIGlzIHR5cGljYWxseSB1c2VkIHRvZ2V0aGVyIHdpdGggdGhlIFtXb3JsZCBNYW5hZ2VyXSguLi93b3JsZC1tYW5hZ2VyKS4gTm90ZSB0aGF0IHRoaXMgY2hhbm5lbCBvbmx5IGdldHMgbm90aWZpY2F0aW9ucyBmb3Igd29ybGRzIGN1cnJlbnRseSBpbiBtZW1vcnkuIChTZWUgbW9yZSBiYWNrZ3JvdW5kIG9uIFtwZXJzaXN0ZW5jZV0oLi4vLi4vLi4vcnVuX3BlcnNpc3RlbmNlKS4pXG4gICAgICpcbiAgICAgKiAqKkV4YW1wbGUqKlxuICAgICAqXG4gICAgICogICAgIHZhciBjbSA9IG5ldyBGLm1hbmFnZXIuQ2hhbm5lbE1hbmFnZXIoKTtcbiAgICAgKiAgICAgdmFyIHdvcmxkTWFuYWdlciA9IG5ldyBGLm1hbmFnZXIuV29ybGRNYW5hZ2VyKHtcbiAgICAgKiAgICAgICAgIGFjY291bnQ6ICdhY21lLXNpbXVsYXRpb25zJyxcbiAgICAgKiAgICAgICAgIHByb2plY3Q6ICdzdXBwbHktY2hhaW4tZ2FtZScsXG4gICAgICogICAgICAgICBncm91cDogJ3RlYW0xJyxcbiAgICAgKiAgICAgICAgIHJ1bjogeyBtb2RlbDogJ21vZGVsLmVxbicgfVxuICAgICAqICAgICB9KTtcbiAgICAgKiAgICAgd29ybGRNYW5hZ2VyLmdldEN1cnJlbnRXb3JsZCgpLnRoZW4oZnVuY3Rpb24gKHdvcmxkT2JqZWN0LCB3b3JsZEFkYXB0ZXIpIHtcbiAgICAgKiAgICAgICAgIHZhciB1c2VyQ2hhbm5lbCA9IGNtLmdldFVzZXJDaGFubmVsKHdvcmxkT2JqZWN0KTtcbiAgICAgKiAgICAgICAgIHVzZXJDaGFubmVsLnN1YnNjcmliZSgnJywgZnVuY3Rpb24gKGRhdGEpIHtcbiAgICAgKiAgICAgICAgICAgICBjb25zb2xlLmxvZyhkYXRhKTtcbiAgICAgKiAgICAgICAgIH0pO1xuICAgICAqICAgICAgfSk7XG4gICAgICpcbiAgICAgKlxuICAgICAqICoqUmV0dXJuIFZhbHVlKipcbiAgICAgKlxuICAgICAqICogKkNoYW5uZWwqIFJldHVybnMgdGhlIGNoYW5uZWwgKGFuIGluc3RhbmNlIG9mIHRoZSBbQ2hhbm5lbCBTZXJ2aWNlXSguLi9jaGFubmVsLXNlcnZpY2UvKSkuXG4gICAgICpcbiAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAqXG4gICAgICogQHBhcmFtICB7U3RyaW5nfE9iamVjdH0gd29ybGQgV29ybGQgb2JqZWN0IG9yIGlkLlxuICAgICAqIEBwYXJhbSAge1N0cmluZ3xPYmplY3R9IHVzZXIgKE9wdGlvbmFsKSBVc2VyIG9iamVjdCBvciBpZC4gSWYgbm90IHByb3ZpZGVkLCBwaWNrcyB1cCB1c2VyIGlkIGZyb20gY3VycmVudCBzZXNzaW9uIGlmIGVuZCB1c2VyIGlzIGxvZ2dlZCBpbi5cbiAgICAgKiBAcGFyYW0gIHtTdHJpbmd9IGdyb3VwTmFtZSAoT3B0aW9uYWwpIEdyb3VwIHRoZSB3b3JsZCBleGlzdHMgaW4uIElmIG5vdCBwcm92aWRlZCwgcGlja3MgdXAgZ3JvdXAgZnJvbSBjdXJyZW50IHNlc3Npb24gaWYgZW5kIHVzZXIgaXMgbG9nZ2VkIGluLlxuICAgICAqIEByZXR1cm4ge0NoYW5uZWx9IENoYW5uZWwgaW5zdGFuY2VcbiAgICAgKi9cbiAgICBnZXRVc2VyQ2hhbm5lbDogZnVuY3Rpb24gKHdvcmxkLCB1c2VyLCBncm91cE5hbWUpIHtcbiAgICAgICAgdmFyIHdvcmxkaWQgPSAoJC5pc1BsYWluT2JqZWN0KHdvcmxkKSAmJiB3b3JsZC5pZCkgPyB3b3JsZC5pZCA6IHdvcmxkO1xuICAgICAgICBpZiAoIXdvcmxkaWQpIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcignUGxlYXNlIHNwZWNpZnkgYSB3b3JsZCBpZCcpO1xuICAgICAgICB9XG4gICAgICAgIHZhciBzZXNzaW9uID0gdGhpcy5zZXNzaW9uTWFuYWdlci5nZXRNZXJnZWRPcHRpb25zKHRoaXMub3B0aW9ucyk7XG5cbiAgICAgICAgdmFyIHVzZXJpZCA9ICgkLmlzUGxhaW5PYmplY3QodXNlcikgJiYgdXNlci5pZCkgPyB1c2VyLmlkIDogdXNlcjtcbiAgICAgICAgdXNlcmlkID0gZ2V0RnJvbVNlc3Npb25PckVycm9yKHVzZXJpZCwgJ3VzZXJJZCcsIHNlc3Npb24pO1xuICAgICAgICBncm91cE5hbWUgPSBnZXRGcm9tU2Vzc2lvbk9yRXJyb3IoZ3JvdXBOYW1lLCAnZ3JvdXBOYW1lJywgc2Vzc2lvbik7XG5cbiAgICAgICAgdmFyIGFjY291bnQgPSBnZXRGcm9tU2Vzc2lvbk9yRXJyb3IoJycsICdhY2NvdW50Jywgc2Vzc2lvbik7XG4gICAgICAgIHZhciBwcm9qZWN0ID0gZ2V0RnJvbVNlc3Npb25PckVycm9yKCcnLCAncHJvamVjdCcsIHNlc3Npb24pO1xuXG4gICAgICAgIHZhciBiYXNlVG9waWMgPSBbJy91c2VyJywgYWNjb3VudCwgcHJvamVjdCwgZ3JvdXBOYW1lLCB3b3JsZGlkLCB1c2VyaWRdLmpvaW4oJy8nKTtcbiAgICAgICAgcmV0dXJuIF9fc3VwZXIuZ2V0Q2hhbm5lbC5jYWxsKHRoaXMsIHsgYmFzZTogYmFzZVRvcGljIH0pO1xuICAgIH0sXG5cbiAgICAvKipcbiAgICAgKiBDcmVhdGUgYW5kIHJldHVybiBhIHB1Ymxpc2gvc3Vic2NyaWJlIGNoYW5uZWwgKGZyb20gdGhlIHVuZGVybHlpbmcgW0NoYW5uZWwgTWFuYWdlcl0oLi4vY2hhbm5lbC1tYW5hZ2VyLykpIHRoYXQgYXV0b21hdGljYWxseSB0cmFja3MgdGhlIHByZXNlbmNlIG9mIGFuIFtlbmQgdXNlcl0oLi4vLi4vLi4vZ2xvc3NhcnkvI3VzZXJzKSwgdGhhdCBpcywgd2hldGhlciB0aGUgZW5kIHVzZXIgaXMgY3VycmVudGx5IG9ubGluZSBpbiB0aGlzIGdyb3VwLiBOb3RpZmljYXRpb25zIGFyZSBhdXRvbWF0aWNhbGx5IHNlbnQgd2hlbiB0aGUgZW5kIHVzZXIgY29tZXMgb25saW5lLCBhbmQgd2hlbiB0aGUgZW5kIHVzZXIgZ29lcyBvZmZsaW5lIChub3QgcHJlc2VudCBmb3IgbW9yZSB0aGFuIDIgbWludXRlcykuIFVzZWZ1bCBpbiBtdWx0aXBsYXllciBnYW1lcyBmb3IgbGV0dGluZyBlYWNoIGVuZCB1c2VyIGtub3cgd2hldGhlciBvdGhlciB1c2VycyBpbiB0aGVpciBncm91cCBhcmUgYWxzbyBvbmxpbmUuXG4gICAgICpcbiAgICAgKiBOb3RlIHRoYXQgdGhlIHByZXNlbmNlIGNoYW5uZWwgaXMgdHJhY2tpbmcgYWxsIGVuZCB1c2VycyBpbiBhIGdyb3VwLiBJbiBwYXJ0aWN1bGFyLCBpZiB0aGUgcHJvamVjdCBhZGRpdGlvbmFsbHkgc3BsaXRzIGVhY2ggZ3JvdXAgaW50byBbd29ybGRzXSguLi93b3JsZC1tYW5hZ2VyLyksIHRoaXMgY2hhbm5lbCBjb250aW51ZXMgdG8gc2hvdyBub3RpZmljYXRpb25zIGZvciBhbGwgZW5kIHVzZXJzIGluIHRoZSBncm91cCAobm90IHJlc3RyaWN0ZWQgYnkgd29ybGRzKS5cbiAgICAgKlxuICAgICAqICoqRXhhbXBsZSoqXG4gICAgICpcbiAgICAgKiAgICAgdmFyIGNtID0gbmV3IEYubWFuYWdlci5DaGFubmVsTWFuYWdlcigpO1xuICAgICAqICAgICB2YXIgcGMgPSBjbS5nZXRQcmVzZW5jZUNoYW5uZWwoKTtcbiAgICAgKiAgICAgcGMuc3Vic2NyaWJlKCcnLCBmdW5jdGlvbiAoZGF0YSkge1xuICAgICAqICAgICAgICAgIC8vICdkYXRhJyBpcyB0aGUgZW50aXJlIG1lc3NhZ2Ugb2JqZWN0IHRvIHRoZSBjaGFubmVsO1xuICAgICAqICAgICAgICAgIC8vIHBhcnNlIGZvciBpbmZvcm1hdGlvbiBvZiBpbnRlcmVzdFxuICAgICAqICAgICAgICAgIGlmIChkYXRhLmRhdGEuc3ViVHlwZSA9PT0gJ2Rpc2Nvbm5lY3QnKSB7XG4gICAgICogICAgICAgICAgICAgICBjb25zb2xlLmxvZygndXNlciAnLCBkYXRhLmRhdGEudXNlci51c2VyTmFtZSwgJ2Rpc2Nvbm5lY3RlZCBhdCAnLCBkYXRhLmRhdGEuZGF0ZSk7XG4gICAgICogICAgICAgICAgfVxuICAgICAqICAgICAgICAgIGlmIChkYXRhLmRhdGEuc3ViVHlwZSA9PT0gJ2Nvbm5lY3QnKSB7XG4gICAgICogICAgICAgICAgICAgICBjb25zb2xlLmxvZygndXNlciAnLCBkYXRhLmRhdGEudXNlci51c2VyTmFtZSwgJ2Nvbm5lY3RlZCBhdCAnLCBkYXRhLmRhdGEuZGF0ZSk7XG4gICAgICogICAgICAgICAgfVxuICAgICAqICAgICB9KTtcbiAgICAgKlxuICAgICAqXG4gICAgICogKipSZXR1cm4gVmFsdWUqKlxuICAgICAqXG4gICAgICogKiAqQ2hhbm5lbCogUmV0dXJucyB0aGUgY2hhbm5lbCAoYW4gaW5zdGFuY2Ugb2YgdGhlIFtDaGFubmVsIFNlcnZpY2VdKC4uL2NoYW5uZWwtc2VydmljZS8pKS5cbiAgICAgKlxuICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICpcbiAgICAgKiBAcGFyYW0gIHtTdHJpbmd9IGdyb3VwTmFtZSAoT3B0aW9uYWwpIEdyb3VwIHRoZSBlbmQgdXNlciBpcyBpbi4gSWYgbm90IHByb3ZpZGVkLCBwaWNrcyB1cCBncm91cCBmcm9tIGN1cnJlbnQgc2Vzc2lvbiBpZiBlbmQgdXNlciBpcyBsb2dnZWQgaW4uXG4gICAgICogQHJldHVybiB7Q2hhbm5lbH0gQ2hhbm5lbCBpbnN0YW5jZVxuICAgICAqL1xuICAgIGdldFByZXNlbmNlQ2hhbm5lbDogZnVuY3Rpb24gKGdyb3VwTmFtZSkge1xuICAgICAgICB2YXIgc2Vzc2lvbiA9IHRoaXMuc2Vzc2lvbk1hbmFnZXIuZ2V0TWVyZ2VkT3B0aW9ucyh0aGlzLm9wdGlvbnMpO1xuICAgICAgICBncm91cE5hbWUgPSBnZXRGcm9tU2Vzc2lvbk9yRXJyb3IoZ3JvdXBOYW1lLCAnZ3JvdXBOYW1lJywgc2Vzc2lvbik7XG4gICAgICAgIHZhciBhY2NvdW50ID0gZ2V0RnJvbVNlc3Npb25PckVycm9yKCcnLCAnYWNjb3VudCcsIHNlc3Npb24pO1xuICAgICAgICB2YXIgcHJvamVjdCA9IGdldEZyb21TZXNzaW9uT3JFcnJvcignJywgJ3Byb2plY3QnLCBzZXNzaW9uKTtcblxuICAgICAgICB2YXIgYmFzZVRvcGljID0gWycvZ3JvdXAnLCBhY2NvdW50LCBwcm9qZWN0LCBncm91cE5hbWVdLmpvaW4oJy8nKTtcbiAgICAgICAgdmFyIGNoYW5uZWwgPSBfX3N1cGVyLmdldENoYW5uZWwuY2FsbCh0aGlzLCB7IGJhc2U6IGJhc2VUb3BpYyB9KTtcbiAgICAgICAgdmFyIG9sZHN1YnMgPSBjaGFubmVsLnN1YnNjcmliZTtcbiAgICAgICAgY2hhbm5lbC5zdWJzY3JpYmUgPSBmdW5jdGlvbiAodG9waWMsIGNhbGxiYWNrLCBjb250ZXh0LCBvcHRpb25zKSB7XG4gICAgICAgICAgICB2YXIgY2FsbGJhY2tXaXRoT25seVByZXNlbmNlRGF0YSA9IGZ1bmN0aW9uIChwYXlsb2FkKSB7XG4gICAgICAgICAgICAgICAgaWYgKGlzUHJlc2VuY2VEYXRhKHBheWxvYWQpKSB7XG4gICAgICAgICAgICAgICAgICAgIGNhbGxiYWNrLmNhbGwoY29udGV4dCwgcGF5bG9hZCk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfTtcbiAgICAgICAgICAgIHJldHVybiBvbGRzdWJzLmNhbGwoY2hhbm5lbCwgdG9waWMsIGNhbGxiYWNrV2l0aE9ubHlQcmVzZW5jZURhdGEsIGNvbnRleHQsIG9wdGlvbnMpO1xuICAgICAgICB9O1xuICAgICAgICByZXR1cm4gY2hhbm5lbDtcbiAgICB9LFxuXG4gICAgLyoqXG4gICAgICogQ3JlYXRlIGFuZCByZXR1cm4gYSBwdWJsaXNoL3N1YnNjcmliZSBjaGFubmVsIChmcm9tIHRoZSB1bmRlcmx5aW5nIFtDaGFubmVsIE1hbmFnZXJdKC4uL2NoYW5uZWwtbWFuYWdlci8pKSBmb3IgdGhlIGdpdmVuIGNvbGxlY3Rpb24uIChUaGUgY29sbGVjdGlvbiBuYW1lIGlzIHNwZWNpZmllZCBpbiB0aGUgYHJvb3RgIGFyZ3VtZW50IHdoZW4gdGhlIFtEYXRhIFNlcnZpY2VdKC4uL2RhdGEtYXBpLXNlcnZpY2UvKSBpcyBpbnN0YW50aWF0ZWQuKSBNdXN0IGJlIG9uZSBvZiB0aGUgY29sbGVjdGlvbnMgaW4gdGhpcyBhY2NvdW50ICh0ZWFtKSBhbmQgcHJvamVjdC5cbiAgICAgKlxuICAgICAqIFRoZXJlIGFyZSBhdXRvbWF0aWMgbm90aWZpY2F0aW9ucyBmcm9tIEVwaWNlbnRlciBvbiB0aGlzIGNoYW5uZWwgd2hlbiBkYXRhIGlzIGNyZWF0ZWQsIHVwZGF0ZWQsIG9yIGRlbGV0ZWQgaW4gdGhpcyBjb2xsZWN0aW9uLiBTZWUgbW9yZSBvbiBbYXV0b21hdGljIG1lc3NhZ2VzIHRvIHRoZSBkYXRhIGNoYW5uZWxdKC4uLy4uLy4uL3Jlc3RfYXBpcy9tdWx0aXBsYXllci9jaGFubmVsLyNkYXRhLW1lc3NhZ2VzKS5cbiAgICAgKlxuICAgICAqICoqRXhhbXBsZSoqXG4gICAgICpcbiAgICAgKiAgICAgdmFyIGNtID0gbmV3IEYubWFuYWdlci5DaGFubmVsTWFuYWdlcigpO1xuICAgICAqICAgICB2YXIgZGMgPSBjbS5nZXREYXRhQ2hhbm5lbCgnc3VydmV5LXJlc3BvbnNlcycpO1xuICAgICAqICAgICBkYy5zdWJzY3JpYmUoJycsIGZ1bmN0aW9uKGRhdGEsIG1ldGEpIHtcbiAgICAgKiAgICAgICAgICBjb25zb2xlLmxvZyhkYXRhKTtcbiAgICAgKlxuICAgICAqICAgICAgICAgIC8vIG1ldGEuZGF0ZSBpcyB0aW1lIG9mIGNoYW5nZSxcbiAgICAgKiAgICAgICAgICAvLyBtZXRhLnN1YlR5cGUgaXMgdGhlIGtpbmQgb2YgY2hhbmdlOiBuZXcsIHVwZGF0ZSwgb3IgZGVsZXRlXG4gICAgICogICAgICAgICAgLy8gbWV0YS5wYXRoIGlzIHRoZSBmdWxsIHBhdGggdG8gdGhlIGNoYW5nZWQgZGF0YVxuICAgICAqICAgICAgICAgIGNvbnNvbGUubG9nKG1ldGEpO1xuICAgICAqICAgICB9KTtcbiAgICAgKlxuICAgICAqICoqUmV0dXJuIFZhbHVlKipcbiAgICAgKlxuICAgICAqICogKkNoYW5uZWwqIFJldHVybnMgdGhlIGNoYW5uZWwgKGFuIGluc3RhbmNlIG9mIHRoZSBbQ2hhbm5lbCBTZXJ2aWNlXSguLi9jaGFubmVsLXNlcnZpY2UvKSkuXG4gICAgICpcbiAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAqXG4gICAgICogQHBhcmFtICB7U3RyaW5nfSBjb2xsZWN0aW9uIE5hbWUgb2YgY29sbGVjdGlvbiB3aG9zZSBhdXRvbWF0aWMgbm90aWZpY2F0aW9ucyB5b3Ugd2FudCB0byByZWNlaXZlLlxuICAgICAqIEByZXR1cm4ge0NoYW5uZWx9IENoYW5uZWwgaW5zdGFuY2VcbiAgICAgKi9cbiAgICBnZXREYXRhQ2hhbm5lbDogZnVuY3Rpb24gKGNvbGxlY3Rpb24pIHtcbiAgICAgICAgaWYgKCFjb2xsZWN0aW9uKSB7XG4gICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ1BsZWFzZSBzcGVjaWZ5IGEgY29sbGVjdGlvbiB0byBsaXN0ZW4gb24uJyk7XG4gICAgICAgIH1cblxuICAgICAgICB2YXIgc2Vzc2lvbiA9IHRoaXMuc2Vzc2lvbk1hbmFnZXIuZ2V0TWVyZ2VkT3B0aW9ucyh0aGlzLm9wdGlvbnMpO1xuICAgICAgICB2YXIgYWNjb3VudCA9IGdldEZyb21TZXNzaW9uT3JFcnJvcignJywgJ2FjY291bnQnLCBzZXNzaW9uKTtcbiAgICAgICAgdmFyIHByb2plY3QgPSBnZXRGcm9tU2Vzc2lvbk9yRXJyb3IoJycsICdwcm9qZWN0Jywgc2Vzc2lvbik7XG4gICAgICAgIHZhciBiYXNlVG9waWMgPSBbJy9kYXRhJywgYWNjb3VudCwgcHJvamVjdCwgY29sbGVjdGlvbl0uam9pbignLycpO1xuICAgICAgICB2YXIgY2hhbm5lbCA9IF9fc3VwZXIuZ2V0Q2hhbm5lbC5jYWxsKHRoaXMsIHsgYmFzZTogYmFzZVRvcGljIH0pO1xuXG4gICAgICAgIC8vVE9ETzogRml4IGFmdGVyIEVwaWNlbnRlciBidWcgaXMgcmVzb2x2ZWRcbiAgICAgICAgdmFyIG9sZHN1YnMgPSBjaGFubmVsLnN1YnNjcmliZTtcbiAgICAgICAgY2hhbm5lbC5zdWJzY3JpYmUgPSBmdW5jdGlvbiAodG9waWMsIGNhbGxiYWNrLCBjb250ZXh0LCBvcHRpb25zKSB7XG4gICAgICAgICAgICB2YXIgY2FsbGJhY2tXaXRoQ2xlYW5EYXRhID0gZnVuY3Rpb24gKHBheWxvYWQpIHtcbiAgICAgICAgICAgICAgICB2YXIgbWV0YSA9IHtcbiAgICAgICAgICAgICAgICAgICAgcGF0aDogcGF5bG9hZC5jaGFubmVsLFxuICAgICAgICAgICAgICAgICAgICBzdWJUeXBlOiBwYXlsb2FkLmRhdGEuc3ViVHlwZSxcbiAgICAgICAgICAgICAgICAgICAgZGF0ZTogcGF5bG9hZC5kYXRhLmRhdGUsXG4gICAgICAgICAgICAgICAgICAgIGRhdGFQYXRoOiBwYXlsb2FkLmRhdGEuZGF0YS5wYXRoLFxuICAgICAgICAgICAgICAgIH07XG4gICAgICAgICAgICAgICAgdmFyIGFjdHVhbERhdGEgPSBwYXlsb2FkLmRhdGEuZGF0YTtcbiAgICAgICAgICAgICAgICBpZiAoYWN0dWFsRGF0YS5kYXRhICE9PSB1bmRlZmluZWQpIHsgLy9EZWxldGUgbm90aWZpY2F0aW9ucyBhcmUgb25lIGRhdGEtbGV2ZWwgYmVoaW5kIG9mIGNvdXJzZVxuICAgICAgICAgICAgICAgICAgICBhY3R1YWxEYXRhID0gYWN0dWFsRGF0YS5kYXRhO1xuICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgIGNhbGxiYWNrLmNhbGwoY29udGV4dCwgYWN0dWFsRGF0YSwgbWV0YSk7XG4gICAgICAgICAgICB9O1xuICAgICAgICAgICAgcmV0dXJuIG9sZHN1YnMuY2FsbChjaGFubmVsLCB0b3BpYywgY2FsbGJhY2tXaXRoQ2xlYW5EYXRhLCBjb250ZXh0LCBvcHRpb25zKTtcbiAgICAgICAgfTtcblxuICAgICAgICByZXR1cm4gY2hhbm5lbDtcbiAgICB9XG59KTtcblxubW9kdWxlLmV4cG9ydHMgPSBFcGljZW50ZXJDaGFubmVsTWFuYWdlcjtcbiIsIid1c2Ugc3RyaWN0JztcblxubW9kdWxlLmV4cG9ydHMgPSB7XG4gICAgRVBJX1NFU1NJT05fS0VZOiAnZXBpY2VudGVyanMuc2Vzc2lvbicsXG4gICAgU1RSQVRFR1lfU0VTU0lPTl9LRVk6ICdlcGljZW50ZXItc2NlbmFyaW8nXG59OyIsIi8qKlxuKiAjIyBSdW4gTWFuYWdlclxuKlxuKiBUaGUgUnVuIE1hbmFnZXIgZ2l2ZXMgeW91IGFjY2VzcyB0byBydW5zIGZvciB5b3VyIHByb2plY3QuIFRoaXMgYWxsb3dzIHlvdSB0byByZWFkIGFuZCB1cGRhdGUgdmFyaWFibGVzLCBjYWxsIG9wZXJhdGlvbnMsIGV0Yy4gQWRkaXRpb25hbGx5LCB0aGUgUnVuIE1hbmFnZXIgZ2l2ZXMgeW91IGNvbnRyb2wgb3ZlciBydW4gY3JlYXRpb24gZGVwZW5kaW5nIG9uIHJ1biBzdGF0ZXMuIFNwZWNpZmljYWxseSwgeW91IGNhbiBzZWxlY3QgW3J1biBjcmVhdGlvbiBzdHJhdGVnaWVzIChydWxlcyldKC4uL3N0cmF0ZWdpZXMvKSBmb3Igd2hpY2ggcnVucyBlbmQgdXNlcnMgb2YgeW91ciBwcm9qZWN0IHdvcmsgd2l0aCB3aGVuIHRoZXkgbG9nIGluIHRvIHlvdXIgcHJvamVjdC5cbipcbiogVGhlcmUgYXJlIG1hbnkgd2F5cyB0byBjcmVhdGUgbmV3IHJ1bnMsIGluY2x1ZGluZyB0aGUgRXBpY2VudGVyLmpzIFtSdW4gU2VydmljZV0oLi4vcnVuLWFwaS1zZXJ2aWNlLykgYW5kIHRoZSBSRVNGVGZ1bCBbUnVuIEFQSV0oLi4vLi4vLi4vcmVzdF9hcGlzL2FnZ3JlZ2F0ZV9ydW5fYXBpKS4gSG93ZXZlciwgZm9yIHNvbWUgcHJvamVjdHMgaXQgbWFrZXMgbW9yZSBzZW5zZSB0byBwaWNrIHVwIHdoZXJlIHRoZSB1c2VyIGxlZnQgb2ZmLCB1c2luZyBhbiBleGlzdGluZyBydW4uIEFuZCBpbiBzb21lIHByb2plY3RzLCB3aGV0aGVyIHRvIGNyZWF0ZSBhIG5ldyBydW4gb3IgdXNlIGFuIGV4aXN0aW5nIG9uZSBpcyBjb25kaXRpb25hbCwgZm9yIGV4YW1wbGUgYmFzZWQgb24gY2hhcmFjdGVyaXN0aWNzIG9mIHRoZSBleGlzdGluZyBydW4gb3IgeW91ciBvd24ga25vd2xlZGdlIGFib3V0IHRoZSBtb2RlbC4gVGhlIFJ1biBNYW5hZ2VyIHByb3ZpZGVzIHRoaXMgbGV2ZWwgb2YgY29udHJvbDogeW91ciBjYWxsIHRvIGBnZXRSdW4oKWAsIHJhdGhlciB0aGFuIGFsd2F5cyByZXR1cm5pbmcgYSBuZXcgcnVuLCByZXR1cm5zIGEgcnVuIGJhc2VkIG9uIHRoZSBzdHJhdGVneSB5b3UndmUgc3BlY2lmaWVkLlxuKlxuKlxuKiAjIyMgVXNpbmcgdGhlIFJ1biBNYW5hZ2VyIHRvIGNyZWF0ZSBhbmQgYWNjZXNzIHJ1bnNcbipcbiogVG8gdXNlIHRoZSBSdW4gTWFuYWdlciwgaW5zdGFudGlhdGUgaXQgYnkgcGFzc2luZyBpbjpcbipcbiogICAqIGBydW5gOiAocmVxdWlyZWQpIFJ1biBvYmplY3QuIE11c3QgY29udGFpbjpcbiogICAgICAgKiBgYWNjb3VudGA6IEVwaWNlbnRlciBhY2NvdW50IGlkICgqKlRlYW0gSUQqKiBmb3IgdGVhbSBwcm9qZWN0cywgKipVc2VyIElEKiogZm9yIHBlcnNvbmFsIHByb2plY3RzKS5cbiogICAgICAgKiBgcHJvamVjdGA6IEVwaWNlbnRlciBwcm9qZWN0IGlkLlxuKiAgICAgICAqIGBtb2RlbGA6IFRoZSBuYW1lIG9mIHlvdXIgcHJpbWFyeSBtb2RlbCBmaWxlLiAoU2VlIG1vcmUgb24gW1dyaXRpbmcgeW91ciBNb2RlbF0oLi4vLi4vLi4vd3JpdGluZ195b3VyX21vZGVsLykuKVxuKiAgICAgICAqIGBzY29wZWA6IChvcHRpb25hbCkgU2NvcGUgb2JqZWN0IGZvciB0aGUgcnVuLCBmb3IgZXhhbXBsZSBgc2NvcGUuZ3JvdXBgIHdpdGggdmFsdWUgb2YgdGhlIG5hbWUgb2YgdGhlIGdyb3VwLlxuKiAgICAgICAqIGBzZXJ2ZXJgOiAob3B0aW9uYWwpIEFuIG9iamVjdCB3aXRoIG9uZSBmaWVsZCwgYGhvc3RgLiBUaGUgdmFsdWUgb2YgYGhvc3RgIGlzIHRoZSBzdHJpbmcgYGFwaS5mb3Jpby5jb21gLCB0aGUgVVJJIG9mIHRoZSBGb3JpbyBzZXJ2ZXIuIFRoaXMgaXMgYXV0b21hdGljYWxseSBzZXQsIGJ1dCB5b3UgY2FuIHBhc3MgaXQgZXhwbGljaXRseSBpZiBkZXNpcmVkLiBJdCBpcyBtb3N0IGNvbW1vbmx5IHVzZWQgZm9yIGNsYXJpdHkgd2hlbiB5b3UgYXJlIFtob3N0aW5nIGFuIEVwaWNlbnRlciBwcm9qZWN0IG9uIHlvdXIgb3duIHNlcnZlcl0oLi4vLi4vLi4vaG93X3RvL3NlbGZfaG9zdGluZy8pLlxuKiAgICAgICAqIGBmaWxlc2A6IChvcHRpb25hbCkgSWYgYW5kIG9ubHkgaWYgeW91IGFyZSB1c2luZyBhIFZlbnNpbSBtb2RlbCBhbmQgeW91IGhhdmUgYWRkaXRpb25hbCBkYXRhIHRvIHBhc3MgaW4gdG8geW91ciBtb2RlbCwgeW91IGNhbiBvcHRpb25hbGx5IHBhc3MgYSBgZmlsZXNgIG9iamVjdCB3aXRoIHRoZSBuYW1lcyBvZiB0aGUgZmlsZXMsIGZvciBleGFtcGxlOiBgXCJmaWxlc1wiOiB7XCJkYXRhXCI6IFwibXlFeHRyYURhdGEueGxzXCJ9YC4gKFNlZSBtb3JlIG9uIFtVc2luZyBFeHRlcm5hbCBEYXRhIGluIFZlbnNpbV0oLi4vLi4vLi4vbW9kZWxfY29kZS92ZW5zaW0vdmVuc2ltX2V4YW1wbGVfeGxzLykuKVxuKlxuKiAgICogYHN0cmF0ZWd5YDogKG9wdGlvbmFsKSBSdW4gY3JlYXRpb24gc3RyYXRlZ3kgZm9yIHdoZW4gdG8gY3JlYXRlIGEgbmV3IHJ1biBhbmQgd2hlbiB0byByZXVzZSBhbiBlbmQgdXNlcidzIGV4aXN0aW5nIHJ1bi4gVGhpcyBpcyAqb3B0aW9uYWwqOyBieSBkZWZhdWx0LCB0aGUgUnVuIE1hbmFnZXIgc2VsZWN0cyBgcmV1c2UtcGVyLXNlc3Npb25gLCBvciBgcmV1c2UtbGFzdC1pbml0aWFsaXplZGAgaWYgeW91IGFsc28gcGFzcyBpbiBhbiBpbml0aWFsIG9wZXJhdGlvbi4gU2VlIFtiZWxvd10oI3VzaW5nLXRoZS1ydW4tbWFuYWdlci10by1hY2Nlc3MtYW5kLXJlZ2lzdGVyLXN0cmF0ZWdpZXMpIGZvciBtb3JlIGluZm9ybWF0aW9uIG9uIHN0cmF0ZWdpZXMuXG4qXG4qICAgKiBgc3RyYXRlZ3lPcHRpb25zYDogKG9wdGlvbmFsKSBBZGRpdGlvbmFsIG9wdGlvbnMgcGFzc2VkIGRpcmVjdGx5IHRvIHRoZSBbcnVuIGNyZWF0aW9uIHN0cmF0ZWd5XSguLi9zdHJhdGVnaWVzLykuXG4qXG4qICAgKiBgc2Vzc2lvbktleWA6IChvcHRpb25hbCkgTmFtZSBvZiBicm93c2VyIGNvb2tpZSBpbiB3aGljaCB0byBzdG9yZSBydW4gaW5mb3JtYXRpb24sIGluY2x1ZGluZyBydW4gaWQuIE1hbnkgY29uZGl0aW9uYWwgc3RyYXRlZ2llcywgaW5jbHVkaW5nIHRoZSBwcm92aWRlZCBzdHJhdGVnaWVzLCByZWx5IG9uIHRoaXMgYnJvd3NlciBjb29raWUgdG8gc3RvcmUgdGhlIHJ1biBpZCBhbmQgaGVscCBtYWtlIHRoZSBkZWNpc2lvbiBvZiB3aGV0aGVyIHRvIGNyZWF0ZSBhIG5ldyBydW4gb3IgdXNlIGFuIGV4aXN0aW5nIG9uZS4gVGhlIG5hbWUgb2YgdGhpcyBjb29raWUgZGVmYXVsdHMgdG8gYGVwaWNlbnRlci1zY2VuYXJpb2AgYW5kIGNhbiBiZSBzZXQgd2l0aCB0aGUgYHNlc3Npb25LZXlgIHBhcmFtZXRlci4gVGhpcyBjYW4gYWxzbyBiZSBhIGZ1bmN0aW9uIHdoaWNoIHJldHVybnMgYSBzdHJpbmcsIGlmIHlvdSdkIGxpa2UgdG8gY29udHJvbCB0aGlzIGF0IHJ1bnRpbWUuXG4qXG4qXG4qIEFmdGVyIGluc3RhbnRpYXRpbmcgYSBSdW4gTWFuYWdlciwgbWFrZSBhIGNhbGwgdG8gYGdldFJ1bigpYCB3aGVuZXZlciB5b3UgbmVlZCB0byBhY2Nlc3MgYSBydW4gZm9yIHRoaXMgZW5kIHVzZXIuIFRoZSBgUnVuTWFuYWdlci5ydW5gIGNvbnRhaW5zIHRoZSBpbnN0YW50aWF0ZWQgW1J1biBTZXJ2aWNlXSguLi9ydW4tYXBpLXNlcnZpY2UvKS4gVGhlIFJ1biBTZXJ2aWNlIGFsbG93cyB5b3UgdG8gYWNjZXNzIHZhcmlhYmxlcywgY2FsbCBvcGVyYXRpb25zLCBldGMuXG4qXG4qICoqRXhhbXBsZSoqXG4qXG4qICAgICAgIHZhciBybSA9IG5ldyBGLm1hbmFnZXIuUnVuTWFuYWdlcih7XG4qICAgICAgICAgICBydW46IHtcbiogICAgICAgICAgICAgICBhY2NvdW50OiAnYWNtZS1zaW11bGF0aW9ucycsXG4qICAgICAgICAgICAgICAgcHJvamVjdDogJ3N1cHBseS1jaGFpbi1nYW1lJyxcbiogICAgICAgICAgICAgICBtb2RlbDogJ3N1cHBseS1jaGFpbi1tb2RlbC5qbCcsXG4qICAgICAgICAgICAgICAgc2VydmVyOiB7IGhvc3Q6ICdhcGkuZm9yaW8uY29tJyB9XG4qICAgICAgICAgICB9LFxuKiAgICAgICAgICAgc3RyYXRlZ3k6ICdyZXVzZS1uZXZlcicsXG4qICAgICAgICAgICBzZXNzaW9uS2V5OiAnZXBpY2VudGVyLXNlc3Npb24nXG4qICAgICAgIH0pO1xuKiAgICAgICBybS5nZXRSdW4oKVxuKiAgICAgICAgICAgLnRoZW4oZnVuY3Rpb24ocnVuKSB7XG4qICAgICAgICAgICAgICAgLy8gdGhlIHJldHVybiB2YWx1ZSBvZiBnZXRSdW4oKSBpcyBhIHJ1biBvYmplY3RcbiogICAgICAgICAgICAgICB2YXIgdGhpc1J1bklkID0gcnVuLmlkO1xuKiAgICAgICAgICAgICAgIC8vIHRoZSBSdW5NYW5hZ2VyLnJ1biBhbHNvIGNvbnRhaW5zIHRoZSBpbnN0YW50aWF0ZWQgUnVuIFNlcnZpY2UsXG4qICAgICAgICAgICAgICAgLy8gc28gYW55IFJ1biBTZXJ2aWNlIG1ldGhvZCBpcyB2YWxpZCBoZXJlXG4qICAgICAgICAgICAgICAgcm0ucnVuLmRvKCdydW5Nb2RlbCcpO1xuKiAgICAgICB9KVxuKlxuKlxuKiAjIyMgVXNpbmcgdGhlIFJ1biBNYW5hZ2VyIHRvIGFjY2VzcyBhbmQgcmVnaXN0ZXIgc3RyYXRlZ2llc1xuKlxuKiBUaGUgYHN0cmF0ZWd5YCBmb3IgYSBSdW4gTWFuYWdlciBkZXNjcmliZXMgd2hlbiB0byBjcmVhdGUgYSBuZXcgcnVuIGFuZCB3aGVuIHRvIHJldXNlIGFuIGVuZCB1c2VyJ3MgZXhpc3RpbmcgcnVuLiBUaGUgUnVuIE1hbmFnZXIgaXMgcmVzcG9uc2libGUgZm9yIHBhc3NpbmcgYSBzdHJhdGVneSBldmVyeXRoaW5nIGl0IG1pZ2h0IG5lZWQgdG8gZGV0ZXJtaW5lIHRoZSAnY29ycmVjdCcgcnVuLCB0aGF0IGlzLCBob3cgdG8gZmluZCB0aGUgYmVzdCBleGlzdGluZyBydW4gYW5kIGhvdyB0byBkZWNpZGUgd2hlbiB0byBjcmVhdGUgYSBuZXcgcnVuLlxuKlxuKiBUaGVyZSBhcmUgc2V2ZXJhbCBjb21tb24gc3RyYXRlZ2llcyBwcm92aWRlZCBhcyBwYXJ0IG9mIEVwaWNlbnRlci5qcywgd2hpY2ggeW91IGNhbiBsaXN0IGJ5IGFjY2Vzc2luZyBgRi5tYW5hZ2VyLlJ1bk1hbmFnZXIuc3RyYXRlZ2llc2AuIFlvdSBjYW4gYWxzbyBjcmVhdGUgeW91ciBvd24gc3RyYXRlZ2llcywgYW5kIHJlZ2lzdGVyIHRoZW0gdG8gdXNlIHdpdGggUnVuIE1hbmFnZXJzLiBTZWUgW1J1biBNYW5hZ2VyIFN0cmF0ZWdpZXNdKC4uL3N0cmF0ZWdpZXMvKSBmb3IgZGV0YWlscy5cbiogXG4qL1xuXG4ndXNlIHN0cmljdCc7XG52YXIgc3RyYXRlZ2llcyA9IHJlcXVpcmUoJy4vcnVuLXN0cmF0ZWdpZXMnKTtcbnZhciBzcGVjaWFsT3BlcmF0aW9ucyA9IHJlcXVpcmUoJy4vc3BlY2lhbC1vcGVyYXRpb25zJyk7XG5cbnZhciBSdW5TZXJ2aWNlID0gcmVxdWlyZSgnLi4vc2VydmljZS9ydW4tYXBpLXNlcnZpY2UnKTtcbnZhciBTZXNzaW9uTWFuYWdlciA9IHJlcXVpcmUoJy4uL3N0b3JlL3Nlc3Npb24tbWFuYWdlcicpO1xuXG52YXIgdXRpbCA9IHJlcXVpcmUoJy4uL3V0aWwvb2JqZWN0LXV0aWwnKTtcbnZhciBrZXlOYW1lcyA9IHJlcXVpcmUoJy4va2V5LW5hbWVzJyk7XG5cbmZ1bmN0aW9uIHBhdGNoUnVuU2VydmljZShzZXJ2aWNlLCBtYW5hZ2VyKSB7XG4gICAgaWYgKHNlcnZpY2UucGF0Y2hlZCkge1xuICAgICAgICByZXR1cm4gc2VydmljZTtcbiAgICB9XG5cbiAgICB2YXIgb3JpZyA9IHNlcnZpY2UuZG87XG4gICAgc2VydmljZS5kbyA9IGZ1bmN0aW9uIChvcGVyYXRpb24sIHBhcmFtcywgb3B0aW9ucykge1xuICAgICAgICB2YXIgcmVzZXJ2ZWRPcHMgPSBPYmplY3Qua2V5cyhzcGVjaWFsT3BlcmF0aW9ucyk7XG4gICAgICAgIGlmIChyZXNlcnZlZE9wcy5pbmRleE9mKG9wZXJhdGlvbikgPT09IC0xKSB7XG4gICAgICAgICAgICByZXR1cm4gb3JpZy5hcHBseShzZXJ2aWNlLCBhcmd1bWVudHMpO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgcmV0dXJuIHNwZWNpYWxPcGVyYXRpb25zW29wZXJhdGlvbl0uY2FsbChzZXJ2aWNlLCBwYXJhbXMsIG9wdGlvbnMsIG1hbmFnZXIpO1xuICAgICAgICB9XG4gICAgfTtcblxuICAgIHNlcnZpY2UucGF0Y2hlZCA9IHRydWU7XG5cbiAgICByZXR1cm4gc2VydmljZTtcbn1cblxuZnVuY3Rpb24gc2Vzc2lvbktleUZyb21PcHRpb25zKG9wdGlvbnMsIHJ1blNlcnZpY2UpIHtcbiAgICB2YXIgY29uZmlnID0gcnVuU2VydmljZS5nZXRDdXJyZW50Q29uZmlnKCk7XG4gICAgdmFyIHNlc3Npb25LZXkgPSAkLmlzRnVuY3Rpb24ob3B0aW9ucy5zZXNzaW9uS2V5KSA/IG9wdGlvbnMuc2Vzc2lvbktleShjb25maWcpIDogb3B0aW9ucy5zZXNzaW9uS2V5O1xuICAgIHJldHVybiBzZXNzaW9uS2V5O1xufVxuXG5mdW5jdGlvbiBzZXRSdW5JblNlc3Npb24oc2Vzc2lvbktleSwgcnVuLCBzZXNzaW9uTWFuYWdlcikge1xuICAgIGlmIChzZXNzaW9uS2V5KSB7XG4gICAgICAgIGRlbGV0ZSBydW4udmFyaWFibGVzO1xuICAgICAgICBzZXNzaW9uTWFuYWdlci5nZXRTdG9yZSgpLnNldChzZXNzaW9uS2V5LCBKU09OLnN0cmluZ2lmeShydW4pKTtcbiAgICB9XG59XG5cbnZhciBkZWZhdWx0cyA9IHtcbiAgICBzZXNzaW9uS2V5OiBmdW5jdGlvbiAoY29uZmlnKSB7IFxuICAgICAgICB2YXIgYmFzZUtleSA9IGtleU5hbWVzLlNUUkFURUdZX1NFU1NJT05fS0VZO1xuICAgICAgICB2YXIga2V5ID0gWydhY2NvdW50JywgJ3Byb2plY3QnLCAnbW9kZWwnXS5yZWR1Y2UoZnVuY3Rpb24gKGFjY3VtLCBrZXkpIHtcbiAgICAgICAgICAgIHJldHVybiBjb25maWdba2V5XSA/IGFjY3VtICsgJy0nICsgY29uZmlnW2tleV0gOiBhY2N1bTsgXG4gICAgICAgIH0sIGJhc2VLZXkpO1xuICAgICAgICByZXR1cm4ga2V5O1xuICAgIH1cbn07XG5cbmZ1bmN0aW9uIFJ1bk1hbmFnZXIob3B0aW9ucykge1xuICAgIHRoaXMub3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LCBkZWZhdWx0cywgb3B0aW9ucyk7XG5cbiAgICBpZiAodGhpcy5vcHRpb25zLnJ1biBpbnN0YW5jZW9mIFJ1blNlcnZpY2UpIHtcbiAgICAgICAgdGhpcy5ydW4gPSB0aGlzLm9wdGlvbnMucnVuO1xuICAgIH0gZWxzZSBpZiAoIXV0aWwuaXNFbXB0eSh0aGlzLm9wdGlvbnMucnVuKSkge1xuICAgICAgICB0aGlzLnJ1biA9IG5ldyBSdW5TZXJ2aWNlKHRoaXMub3B0aW9ucy5ydW4pO1xuICAgIH0gZWxzZSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcignTm8gcnVuIG9wdGlvbnMgcGFzc2VkIHRvIFJ1bk1hbmFnZXInKTtcbiAgICB9XG4gICAgcGF0Y2hSdW5TZXJ2aWNlKHRoaXMucnVuLCB0aGlzKTtcblxuICAgIHRoaXMuc3RyYXRlZ3kgPSBzdHJhdGVnaWVzLmdldEJlc3RTdHJhdGVneSh0aGlzLm9wdGlvbnMpO1xuICAgIHRoaXMuc2Vzc2lvbk1hbmFnZXIgPSBuZXcgU2Vzc2lvbk1hbmFnZXIodGhpcy5vcHRpb25zKTtcbn1cblxuUnVuTWFuYWdlci5wcm90b3R5cGUgPSB7XG4gICAgLyoqXG4gICAgICogUmV0dXJucyB0aGUgcnVuIG9iamVjdCBmb3IgdGhlICdjb3JyZWN0JyBydW4uIFRoZSBjb3JyZWN0IHJ1biBpcyBkZWZpbmVkIGJ5IHRoZSBzdHJhdGVneS4gXG4gICAgICpcbiAgICAgKiBGb3IgZXhhbXBsZSwgaWYgdGhlIHN0cmF0ZWd5IGlzIGByZXVzZS1uZXZlcmAsIHRoZSBjYWxsXG4gICAgICogdG8gYGdldFJ1bigpYCBhbHdheXMgcmV0dXJucyBhIG5ld2x5IGNyZWF0ZWQgcnVuOyBpZiB0aGUgc3RyYXRlZ3kgaXMgYHJldXNlLXBlci1zZXNzaW9uYCxcbiAgICAgKiBgZ2V0UnVuKClgIHJldHVybnMgdGhlIHJ1biBjdXJyZW50bHkgcmVmZXJlbmNlZCBpbiB0aGUgYnJvd3NlciBjb29raWUsIGFuZCBpZiB0aGVyZSBpcyBub25lLCBjcmVhdGVzIGEgbmV3IHJ1bi4gXG4gICAgICogU2VlIFtSdW4gTWFuYWdlciBTdHJhdGVnaWVzXSguLi9zdHJhdGVnaWVzLykgZm9yIG1vcmUgb24gc3RyYXRlZ2llcy5cbiAgICAgKlxuICAgICAqICAqKkV4YW1wbGUqKlxuICAgICAqXG4gICAgICogICAgICBybS5nZXRSdW4oKS50aGVuKGZ1bmN0aW9uIChydW4pIHtcbiAgICAgKiAgICAgICAgICAvLyB1c2UgdGhlIHJ1biBvYmplY3RcbiAgICAgKiAgICAgICAgICB2YXIgdGhpc1J1bklkID0gcnVuLmlkO1xuICAgICAqXG4gICAgICogICAgICAgICAgLy8gdXNlIHRoZSBSdW4gU2VydmljZSBvYmplY3RcbiAgICAgKiAgICAgICAgICBybS5ydW4uZG8oJ3J1bk1vZGVsJyk7XG4gICAgICogICAgICB9KTtcbiAgICAgKlxuICAgICAqICAgICAgcm0uZ2V0UnVuKFsnc2FtcGxlX2ludCddKS50aGVuKGZ1bmN0aW9uIChydW4pIHtcbiAgICAgKiAgICAgICAgIC8vIGFuIG9iamVjdCB3aG9zZSBmaWVsZHMgYXJlIHRoZSBuYW1lIDogdmFsdWUgcGFpcnMgb2YgdGhlIHZhcmlhYmxlcyBwYXNzZWQgdG8gZ2V0UnVuKClcbiAgICAgKiAgICAgICAgIGNvbnNvbGUubG9nKHJ1bi52YXJpYWJsZXMpO1xuICAgICAqICAgICAgICAgLy8gdGhlIHZhbHVlIG9mIHNhbXBsZV9pbnRcbiAgICAgKiAgICAgICAgIGNvbnNvbGUubG9nKHJ1bi52YXJpYWJsZXMuc2FtcGxlX2ludCk7IFxuICAgICAqICAgICAgfSk7XG4gICAgICpcbiAgICAgKiBAcGFyYW0ge0FycmF5fSB2YXJpYWJsZXMgKE9wdGlvbmFsKSBUaGUgcnVuIG9iamVjdCBpcyBwb3B1bGF0ZWQgd2l0aCB0aGUgcHJvdmlkZWQgbW9kZWwgdmFyaWFibGVzLCBpZiBwcm92aWRlZC4gTm90ZTogYGdldFJ1bigpYCBkb2VzIG5vdCB0aHJvdyBhbiBlcnJvciBpZiB5b3UgdHJ5IHRvIGdldCBhIHZhcmlhYmxlIHdoaWNoIGRvZXNuJ3QgZXhpc3QuIEluc3RlYWQsIHRoZSB2YXJpYWJsZXMgbGlzdCBpcyBlbXB0eSwgYW5kIGFueSBlcnJvcnMgYXJlIGxvZ2dlZCB0byB0aGUgY29uc29sZS5cbiAgICAgKiBAcGFyYW0ge09iamVjdH0gb3B0aW9ucyAoT3B0aW9uYWwpIENvbmZpZ3VyYXRpb24gb3B0aW9uczsgcGFzc2VkIG9uIHRvIFtSdW5TZXJ2aWNlI2NyZWF0ZV0oLi4vcnVuLWFwaS1zZXJ2aWNlLyNjcmVhdGUpIGlmIHRoZSBzdHJhdGVneSBkb2VzIGNyZWF0ZSBhIG5ldyBydW4uXG4gICAgICogQHJldHVybiB7JHByb21pc2V9IFByb21pc2UgdG8gY29tcGxldGUgdGhlIGNhbGwuXG4gICAgICovXG4gICAgZ2V0UnVuOiBmdW5jdGlvbiAodmFyaWFibGVzLCBvcHRpb25zKSB7XG4gICAgICAgIHZhciBtZSA9IHRoaXM7XG4gICAgICAgIHZhciBzZXNzaW9uU3RvcmUgPSB0aGlzLnNlc3Npb25NYW5hZ2VyLmdldFN0b3JlKCk7XG5cbiAgICAgICAgdmFyIHNlc3Npb25Db250ZW50cyA9IHNlc3Npb25TdG9yZS5nZXQoc2Vzc2lvbktleUZyb21PcHRpb25zKHRoaXMub3B0aW9ucywgbWUucnVuKSk7XG4gICAgICAgIHZhciBydW5TZXNzaW9uID0gSlNPTi5wYXJzZShzZXNzaW9uQ29udGVudHMgfHwgJ3t9Jyk7XG4gICAgICAgIFxuICAgICAgICBpZiAocnVuU2Vzc2lvbi5ydW5JZCkge1xuICAgICAgICAgICAgLy9FcGlKUyA8IDIuMiB1c2VkIHJ1bklkIGFzIGtleSwgc28gbWFpbnRhaW4gY29tcHRhaWJpbGl0eS4gUmVtb3ZlIGF0IHNvbWUgZnV0dXJlIGRhdGUgKFN1bW1lciBgMTc/KVxuICAgICAgICAgICAgcnVuU2Vzc2lvbi5pZCA9IHJ1blNlc3Npb24ucnVuSWQ7XG4gICAgICAgIH1cblxuICAgICAgICB2YXIgYXV0aFNlc3Npb24gPSB0aGlzLnNlc3Npb25NYW5hZ2VyLmdldFNlc3Npb24oKTtcbiAgICAgICAgaWYgKHRoaXMuc3RyYXRlZ3kucmVxdWlyZXNBdXRoICYmIHV0aWwuaXNFbXB0eShhdXRoU2Vzc2lvbikpIHtcbiAgICAgICAgICAgIGNvbnNvbGUuZXJyb3IoJ05vIHVzZXItc2Vzc2lvbiBhdmFpbGFibGUnLCB0aGlzLm9wdGlvbnMuc3RyYXRlZ3ksICdyZXF1aXJlcyBhdXRoZW50aWNhdGlvbi4nKTtcbiAgICAgICAgICAgIHJldHVybiAkLkRlZmVycmVkKCkucmVqZWN0KCdObyB1c2VyLXNlc3Npb24gYXZhaWxhYmxlJykucHJvbWlzZSgpO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiB0aGlzLnN0cmF0ZWd5XG4gICAgICAgICAgICAgICAgLmdldFJ1bih0aGlzLnJ1biwgYXV0aFNlc3Npb24sIHJ1blNlc3Npb24sIG9wdGlvbnMpLnRoZW4oZnVuY3Rpb24gKHJ1bikge1xuICAgICAgICAgICAgICAgICAgICBpZiAocnVuICYmIHJ1bi5pZCkge1xuICAgICAgICAgICAgICAgICAgICAgICAgbWUucnVuLnVwZGF0ZUNvbmZpZyh7IGZpbHRlcjogcnVuLmlkIH0pO1xuICAgICAgICAgICAgICAgICAgICAgICAgdmFyIHNlc3Npb25LZXkgPSBzZXNzaW9uS2V5RnJvbU9wdGlvbnMobWUub3B0aW9ucywgbWUucnVuKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIHNldFJ1bkluU2Vzc2lvbihzZXNzaW9uS2V5LCBydW4sIG1lLnNlc3Npb25NYW5hZ2VyKTtcblxuICAgICAgICAgICAgICAgICAgICAgICAgaWYgKHZhcmlhYmxlcyAmJiB2YXJpYWJsZXMubGVuZ3RoKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIG1lLnJ1bi52YXJpYWJsZXMoKS5xdWVyeSh2YXJpYWJsZXMpLnRoZW4oZnVuY3Rpb24gKHJlc3VsdHMpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcnVuLnZhcmlhYmxlcyA9IHJlc3VsdHM7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybiBydW47XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgfSkuY2F0Y2goZnVuY3Rpb24gKGVycikge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBydW4udmFyaWFibGVzID0ge307XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbnNvbGUuZXJyb3IoZXJyKTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIHJ1bjtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICByZXR1cm4gcnVuO1xuICAgICAgICAgICAgICAgIH0pO1xuICAgIH0sXG5cbiAgICAvKipcbiAgICAgKiBSZXR1cm5zIHRoZSBydW4gb2JqZWN0IGZvciBhICdyZXNldCcgcnVuLiBUaGUgZGVmaW5pdGlvbiBvZiBhIHJlc2V0IGlzIGRlZmluZWQgYnkgdGhlIHN0cmF0ZWd5LCBidXQgdHlwaWNhbGx5IG1lYW5zIGZvcmNpbmcgdGhlIGNyZWF0aW9uIG9mIGEgbmV3IHJ1bi4gRm9yIGV4YW1wbGUsIGByZXNldCgpYCBmb3IgdGhlIGRlZmF1bHQgc3RyYXRlZ2llcyBgcmV1c2UtcGVyLXNlc3Npb25gIGFuZCBgcmV1c2UtbGFzdC1pbml0aWFsaXplZGAgYm90aCBjcmVhdGUgbmV3IHJ1bnMuXG4gICAgICpcbiAgICAgKiAgKipFeGFtcGxlKipcbiAgICAgKlxuICAgICAqICAgICAgcm0ucmVzZXQoKS50aGVuKGZ1bmN0aW9uIChydW4pIHtcbiAgICAgKiAgICAgICAgICAvLyB1c2UgdGhlIChuZXcpIHJ1biBvYmplY3RcbiAgICAgKiAgICAgICAgICB2YXIgdGhpc1J1bklkID0gcnVuLmlkO1xuICAgICAqXG4gICAgICogICAgICAgICAgLy8gdXNlIHRoZSBSdW4gU2VydmljZSBvYmplY3RcbiAgICAgKiAgICAgICAgICBybS5ydW4uZG8oJ3J1bk1vZGVsJyk7XG4gICAgICogICAgICB9KTtcbiAgICAgKlxuICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICogQHBhcmFtIHtPYmplY3R9IG9wdGlvbnMgKE9wdGlvbmFsKSBDb25maWd1cmF0aW9uIG9wdGlvbnM7IHBhc3NlZCBvbiB0byBbUnVuU2VydmljZSNjcmVhdGVdKC4uL3J1bi1hcGktc2VydmljZS8jY3JlYXRlKS5cbiAgICAgKiBAcmV0dXJuIHtQcm9taXNlfVxuICAgICAqL1xuICAgIHJlc2V0OiBmdW5jdGlvbiAob3B0aW9ucykge1xuICAgICAgICB2YXIgbWUgPSB0aGlzO1xuICAgICAgICB2YXIgYXV0aFNlc3Npb24gPSB0aGlzLnNlc3Npb25NYW5hZ2VyLmdldFNlc3Npb24oKTtcbiAgICAgICAgaWYgKHRoaXMuc3RyYXRlZ3kucmVxdWlyZXNBdXRoICYmIHV0aWwuaXNFbXB0eShhdXRoU2Vzc2lvbikpIHtcbiAgICAgICAgICAgIGNvbnNvbGUuZXJyb3IoJ05vIHVzZXItc2Vzc2lvbiBhdmFpbGFibGUnLCB0aGlzLm9wdGlvbnMuc3RyYXRlZ3ksICdyZXF1aXJlcyBhdXRoZW50aWNhdGlvbi4nKTtcbiAgICAgICAgICAgIHJldHVybiAkLkRlZmVycmVkKCkucmVqZWN0KCdObyB1c2VyLXNlc3Npb24gYXZhaWxhYmxlJykucHJvbWlzZSgpO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiB0aGlzLnN0cmF0ZWd5LnJlc2V0KHRoaXMucnVuLCBhdXRoU2Vzc2lvbiwgb3B0aW9ucykudGhlbihmdW5jdGlvbiAocnVuKSB7XG4gICAgICAgICAgICBpZiAocnVuICYmIHJ1bi5pZCkge1xuICAgICAgICAgICAgICAgIG1lLnJ1bi51cGRhdGVDb25maWcoeyBmaWx0ZXI6IHJ1bi5pZCB9KTtcbiAgICAgICAgICAgICAgICB2YXIgc2Vzc2lvbktleSA9IHNlc3Npb25LZXlGcm9tT3B0aW9ucyhtZS5vcHRpb25zLCBtZS5ydW4pO1xuICAgICAgICAgICAgICAgIHNldFJ1bkluU2Vzc2lvbihzZXNzaW9uS2V5LCBydW4uaWQsIG1lLnNlc3Npb25NYW5hZ2VyKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHJldHVybiBydW47XG4gICAgICAgIH0pO1xuICAgIH1cbn07XG5cblJ1bk1hbmFnZXIuc3RyYXRlZ2llcyA9IHN0cmF0ZWdpZXM7XG5tb2R1bGUuZXhwb3J0cyA9IFJ1bk1hbmFnZXI7XG4iLCIndXNlIHN0cmljdCc7XG5cbnZhciBCYXNlID0gcmVxdWlyZSgnLi9ub25lLXN0cmF0ZWd5Jyk7XG52YXIgY2xhc3NGcm9tID0gcmVxdWlyZSgnLi4vLi4vdXRpbC9pbmhlcml0Jyk7XG5cbi8qKlxuKiAjIyBDb25kaXRpb25hbCBDcmVhdGlvbiBTdHJhdGVneVxuKlxuKiBUaGlzIHN0cmF0ZWd5IHdpbGwgdHJ5IHRvIGdldCB0aGUgcnVuIHN0b3JlZCBpbiB0aGUgY29va2llIGFuZFxuKiBldmFsdWF0ZSBpZiBpdCBuZWVkcyB0byBjcmVhdGUgYSBuZXcgcnVuIGJ5IGNhbGxpbmcgdGhlIGBjb25kaXRpb25gIGZ1bmN0aW9uLlxuKi9cblxudmFyIFN0cmF0ZWd5ID0gY2xhc3NGcm9tKEJhc2UsIHtcbiAgICBjb25zdHJ1Y3RvcjogZnVuY3Rpb24gU3RyYXRlZ3koY29uZGl0aW9uKSB7XG4gICAgICAgIGlmIChjb25kaXRpb24gPT0gbnVsbCkgeyAvL2VzbGludC1kaXNhYmxlLWxpbmVcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcignQ29uZGl0aW9uYWwgc3RyYXRlZ3kgbmVlZHMgYSBjb25kaXRpb24gdG8gY3JlYXRlIGEgcnVuJyk7XG4gICAgICAgIH1cbiAgICAgICAgdGhpcy5jb25kaXRpb24gPSB0eXBlb2YgY29uZGl0aW9uICE9PSAnZnVuY3Rpb24nID8gZnVuY3Rpb24gKCkgeyByZXR1cm4gY29uZGl0aW9uOyB9IDogY29uZGl0aW9uO1xuICAgIH0sXG5cbiAgICAvKipcbiAgICAgKiBHZXRzIGEgbmV3ICdjb3JyZWN0JyBydW4sIG9yIHVwZGF0ZXMgdGhlIGV4aXN0aW5nIG9uZSAodGhlIGRlZmluaXRpb24gb2YgJ2NvcnJlY3QnIGRlcGVuZHMgb24gc3RyYXRlZ3kgaW1wbGVtZW50YXRpb24pLlxuICAgICAqIEBwYXJhbSAge1J1blNlcnZpY2V9IHJ1blNlcnZpY2UgQSBSdW4gU2VydmljZSBpbnN0YW5jZSBmb3IgdGhlIGN1cnJlbnQgcnVuLCBhcyBkZXRlcm1pbmVkIGJ5IHRoZSBSdW4gTWFuYWdlci5cbiAgICAgKiBAcGFyYW0gIHtPYmplY3R9IHVzZXJTZXNzaW9uIEluZm9ybWF0aW9uIGFib3V0IHRoZSBjdXJyZW50IHVzZXIgc2Vzc2lvbi4gU2VlIFtBdXRoTWFuYWdlciNnZXRDdXJyZW50VXNlclNlc3Npb25JbmZvXSguLi9hdXRoLW1hbmFnZXIvI2dldGN1cnJlbnR1c2Vyc2Vzc2lvbmluZm8pIGZvciBmb3JtYXQuXG4gICAgICogQHBhcmFtICB7T2JqZWN0fSBvcHRpb25zIChPcHRpb25hbCkgU2VlIFtSdW5TZXJ2aWNlI2NyZWF0ZV0oLi4vcnVuLWFwaS1zZXJ2aWNlLyNjcmVhdGUpIGZvciBzdXBwb3J0ZWQgb3B0aW9ucy5cbiAgICAgKiBAcmV0dXJuIHtQcm9taXNlfSAgICAgICAgICAgICBcbiAgICAgKi9cbiAgICByZXNldDogZnVuY3Rpb24gKHJ1blNlcnZpY2UsIHVzZXJTZXNzaW9uLCBvcHRpb25zKSB7XG4gICAgICAgIHZhciBncm91cCA9IHVzZXJTZXNzaW9uICYmIHVzZXJTZXNzaW9uLmdyb3VwTmFtZTtcbiAgICAgICAgdmFyIG9wdCA9ICQuZXh0ZW5kKHtcbiAgICAgICAgICAgIHNjb3BlOiB7IGdyb3VwOiBncm91cCB9XG4gICAgICAgIH0sIHJ1blNlcnZpY2UuZ2V0Q3VycmVudENvbmZpZygpKTtcblxuICAgICAgICByZXR1cm4gcnVuU2VydmljZVxuICAgICAgICAgICAgICAgIC5jcmVhdGUob3B0LCBvcHRpb25zKVxuICAgICAgICAgICAgICAgIC50aGVuKGZ1bmN0aW9uIChydW4pIHtcbiAgICAgICAgICAgICAgICAgICAgcnVuLmZyZXNobHlDcmVhdGVkID0gdHJ1ZTtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIHJ1bjtcbiAgICAgICAgICAgICAgICB9KTtcbiAgICB9LFxuXG4gICAgLyoqXG4gICAgICogR2V0cyB0aGUgJ2NvcnJlY3QnIHJ1biAodGhlIGRlZmluaXRpb24gb2YgJ2NvcnJlY3QnIGRlcGVuZHMgb24gc3RyYXRlZ3kgaW1wbGVtZW50YXRpb24pLlxuICAgICAqIEBwYXJhbSAge1J1blNlcnZpY2V9IHJ1blNlcnZpY2UgQSBSdW4gU2VydmljZSBpbnN0YW5jZSBmb3IgdGhlIGN1cnJlbnQgcnVuLCBhcyBkZXRlcm1pbmVkIGJ5IHRoZSBSdW4gTWFuYWdlci5cbiAgICAgKiBAcGFyYW0gIHtPYmplY3R9IHVzZXJTZXNzaW9uIEluZm9ybWF0aW9uIGFib3V0IHRoZSBjdXJyZW50IHVzZXIgc2Vzc2lvbi4gU2VlIFtBdXRoTWFuYWdlciNnZXRDdXJyZW50VXNlclNlc3Npb25JbmZvXSguLi9hdXRoLW1hbmFnZXIvI2dldGN1cnJlbnR1c2Vyc2Vzc2lvbmluZm8pIGZvciBmb3JtYXQuXG4gICAgICogQHBhcmFtICB7T2JqZWN0fSBydW5TZXNzaW9uIFRoZSBSdW4gTWFuYWdlciBzdG9yZXMgdGhlICdsYXN0IGFjY2Vzc2VkJyBydW4gaW4gYSBjb29raWUgYW5kIHBhc3NlcyBpdCBiYWNrIGhlcmUuXG4gICAgICogQHBhcmFtICB7T2JqZWN0fSBvcHRpb25zIChPcHRpb25hbCkgU2VlIFtSdW5TZXJ2aWNlI2NyZWF0ZV0oLi4vcnVuLWFwaS1zZXJ2aWNlLyNjcmVhdGUpIGZvciBzdXBwb3J0ZWQgb3B0aW9ucy5cbiAgICAgKiBAcmV0dXJuIHtQcm9taXNlfSAgICAgICAgICAgICBcbiAgICAgKi9cbiAgICBnZXRSdW46IGZ1bmN0aW9uIChydW5TZXJ2aWNlLCB1c2VyU2Vzc2lvbiwgcnVuU2Vzc2lvbiwgb3B0aW9ucykge1xuICAgICAgICB2YXIgbWUgPSB0aGlzO1xuICAgICAgICBpZiAocnVuU2Vzc2lvbiAmJiBydW5TZXNzaW9uLmlkKSB7XG4gICAgICAgICAgICByZXR1cm4gdGhpcy5sb2FkQW5kQ2hlY2socnVuU2VydmljZSwgdXNlclNlc3Npb24sIHJ1blNlc3Npb24sIG9wdGlvbnMpLmNhdGNoKGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gbWUucmVzZXQocnVuU2VydmljZSwgdXNlclNlc3Npb24sIG9wdGlvbnMpOyAvL2lmIGl0IGdvdCB0aGUgd3JvbmcgY29va2llIGZvciBlLmcuXG4gICAgICAgICAgICB9KTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIHJldHVybiB0aGlzLnJlc2V0KHJ1blNlcnZpY2UsIHVzZXJTZXNzaW9uLCBvcHRpb25zKTtcbiAgICAgICAgfVxuICAgIH0sXG5cbiAgICBsb2FkQW5kQ2hlY2s6IGZ1bmN0aW9uIChydW5TZXJ2aWNlLCB1c2VyU2Vzc2lvbiwgcnVuU2Vzc2lvbiwgb3B0aW9ucykge1xuICAgICAgICB2YXIgc2hvdWxkQ3JlYXRlID0gZmFsc2U7XG4gICAgICAgIHZhciBtZSA9IHRoaXM7XG5cbiAgICAgICAgcmV0dXJuIHJ1blNlcnZpY2VcbiAgICAgICAgICAgIC5sb2FkKHJ1blNlc3Npb24uaWQsIG51bGwsIHtcbiAgICAgICAgICAgICAgICBzdWNjZXNzOiBmdW5jdGlvbiAocnVuLCBtc2csIGhlYWRlcnMpIHtcbiAgICAgICAgICAgICAgICAgICAgc2hvdWxkQ3JlYXRlID0gbWUuY29uZGl0aW9uKHJ1biwgaGVhZGVycywgdXNlclNlc3Npb24sIHJ1blNlc3Npb24pO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH0pXG4gICAgICAgICAgICAudGhlbihmdW5jdGlvbiAocnVuKSB7XG4gICAgICAgICAgICAgICAgaWYgKHNob3VsZENyZWF0ZSkge1xuICAgICAgICAgICAgICAgICAgICByZXR1cm4gbWUucmVzZXQocnVuU2VydmljZSwgdXNlclNlc3Npb24sIG9wdGlvbnMpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICByZXR1cm4gcnVuO1xuICAgICAgICAgICAgfSk7XG4gICAgfVxufSk7XG5cbm1vZHVsZS5leHBvcnRzID0gU3RyYXRlZ3k7XG4iLCIvKipcbiAqIFRoZSBgbmV3LWlmLWluaXRpYWxpemVkYCBzdHJhdGVneSBjcmVhdGVzIGEgbmV3IHJ1biBpZiB0aGUgY3VycmVudCBvbmUgaXMgaW4gbWVtb3J5IG9yIGhhcyBpdHMgYGluaXRpYWxpemVkYCBmaWVsZCBzZXQgdG8gYHRydWVgLiBUaGUgYGluaXRpYWxpemVkYCBmaWVsZCBpbiB0aGUgcnVuIHJlY29yZCBpcyBhdXRvbWF0aWNhbGx5IHNldCB0byBgdHJ1ZWAgYXQgcnVuIGNyZWF0aW9uLCBidXQgY2FuIGJlIGNoYW5nZWQuXG4gKiBcbiAqIFRoaXMgc3RyYXRlZ3kgaXMgdXNlZnVsIGlmIHlvdXIgcHJvamVjdCBpcyBzdHJ1Y3R1cmVkIHN1Y2ggdGhhdCBpbW1lZGlhdGVseSBhZnRlciBhIHJ1biBpcyBjcmVhdGVkLCB0aGUgbW9kZWwgaXMgZXhlY3V0ZWQgY29tcGxldGVseSAoZm9yIGV4YW1wbGUsIGEgVmVuc2ltIG1vZGVsIGlzIHN0ZXBwZWQgdG8gdGhlIGVuZCkuIEl0IGlzIHNpbWlsYXIgdG8gdGhlIGBuZXctaWYtbWlzc2luZ2Agc3RyYXRlZ3ksIGV4Y2VwdCB0aGF0IGl0IGNoZWNrcyBhIGZpZWxkIG9mIHRoZSBydW4gcmVjb3JkLlxuICogXG4gKiBTcGVjaWZpY2FsbHksIHRoZSBzdHJhdGVneSBpczpcbiAqXG4gKiAqIENoZWNrIHRoZSBgc2Vzc2lvbktleWAgY29va2llLiBcbiAqICAqIFRoaXMgY29va2llIGlzIHNldCBieSB0aGUgW1J1biBNYW5hZ2VyXSguLi9ydW4tbWFuYWdlci8pIGFuZCBjb25maWd1cmFibGUgdGhyb3VnaCBpdHMgb3B0aW9ucy5cbiAqICAqIElmIHRoZSBjb29raWUgZXhpc3RzLCBjaGVjayB3aGV0aGVyIHRoZSBydW4gaXMgaW4gbWVtb3J5IG9yIG9ubHkgcGVyc2lzdGVkIGluIHRoZSBkYXRhYmFzZS4gQWRkaXRpb25hbGx5LCBjaGVjayB3aGV0aGVyIHRoZSBydW4ncyBgaW5pdGlhbGl6ZWRgIGZpZWxkIGlzIGB0cnVlYC4gXG4gKiAgICAgICogSWYgdGhlIHJ1biBpcyBpbiBtZW1vcnksIGNyZWF0ZSBhIG5ldyBydW4uXG4gKiAgICAgICogSWYgdGhlIHJ1bidzIGBpbml0aWFsaXplZGAgZmllbGQgaXMgYHRydWVgLCBjcmVhdGUgYSBuZXcgcnVuLlxuICogICAgICAqIE90aGVyd2lzZSwgdXNlIHRoZSBleGlzdGluZyBydW4uXG4gKiAgKiBJZiB0aGUgY29va2llIGRvZXMgbm90IGV4aXN0LCBjcmVhdGUgYSBuZXcgcnVuIGZvciB0aGlzIGVuZCB1c2VyLlxuICogIFxuICogIEBkZXByZWNhdGVkIENvbnNpZGVyIHVzaW5nIGByZXVzZS1sYXN0LWluaXRpYWxpemVkYCBpbnN0ZWFkXG4gKi9cblxuJ3VzZSBzdHJpY3QnO1xudmFyIGNsYXNzRnJvbSA9IHJlcXVpcmUoJy4uLy4uLy4uL3V0aWwvaW5oZXJpdCcpO1xudmFyIENvbmRpdGlvbmFsU3RyYXRlZ3kgPSByZXF1aXJlKCcuLi9jb25kaXRpb25hbC1jcmVhdGlvbi1zdHJhdGVneScpO1xuXG52YXIgX19zdXBlciA9IENvbmRpdGlvbmFsU3RyYXRlZ3kucHJvdG90eXBlO1xuXG52YXIgU3RyYXRlZ3kgPSBjbGFzc0Zyb20oQ29uZGl0aW9uYWxTdHJhdGVneSwge1xuICAgIGNvbnN0cnVjdG9yOiBmdW5jdGlvbiAob3B0aW9ucykge1xuICAgICAgICBfX3N1cGVyLmNvbnN0cnVjdG9yLmNhbGwodGhpcywgdGhpcy5jcmVhdGVJZiwgb3B0aW9ucyk7XG4gICAgICAgIGNvbnNvbGUud2FybignVGhpcyBzdHJhdGVneSBpcyBkZXByZWNhdGVkOyBhbGwgcnVucyBub3cgZGVmYXVsdCB0byBiZWluZyBpbml0aWFsaXplZCBieSBkZWZhdWx0IG1ha2luZyB0aGlzIHJlZHVuZGFudC4gQ29uc2lkZXIgdXNpbmcgYHJldXNlLWxhc3QtaW5pdGlhbGl6ZWRgIGluc3RlYWQuJyk7XG4gICAgfSxcblxuICAgIGNyZWF0ZUlmOiBmdW5jdGlvbiAocnVuLCBoZWFkZXJzKSB7XG4gICAgICAgIHJldHVybiBoZWFkZXJzLmdldFJlc3BvbnNlSGVhZGVyKCdwcmFnbWEnKSA9PT0gJ3BlcnNpc3RlbnQnIHx8IHJ1bi5pbml0aWFsaXplZDtcbiAgICB9XG59KTtcblxubW9kdWxlLmV4cG9ydHMgPSBTdHJhdGVneTtcbiIsIi8qKlxuICogVGhlIGBuZXctaWYtcGVyc2lzdGVkYCBzdHJhdGVneSBjcmVhdGVzIGEgbmV3IHJ1biB3aGVuIHRoZSBjdXJyZW50IG9uZSBiZWNvbWVzIHBlcnNpc3RlZCAoZW5kIHVzZXIgaXMgaWRsZSBmb3IgYSBzZXQgcGVyaW9kKSwgYnV0IG90aGVyd2lzZSB1c2VzIHRoZSBjdXJyZW50IG9uZS4gXG4gKiBcbiAqIFVzaW5nIHRoaXMgc3RyYXRlZ3kgbWVhbnMgdGhhdCB3aGVuIGVuZCB1c2VycyBuYXZpZ2F0ZSBiZXR3ZWVuIHBhZ2VzIGluIHlvdXIgcHJvamVjdCwgb3IgcmVmcmVzaCB0aGVpciBicm93c2VycywgdGhleSB3aWxsIHN0aWxsIGJlIHdvcmtpbmcgd2l0aCB0aGUgc2FtZSBydW4uIFxuICogXG4gKiBIb3dldmVyLCBpZiB0aGV5IGFyZSBpZGxlIGZvciBsb25nZXIgdGhhbiB5b3VyIHByb2plY3QncyAqKk1vZGVsIFNlc3Npb24gVGltZW91dCoqIChjb25maWd1cmVkIGluIHlvdXIgcHJvamVjdCdzIFtTZXR0aW5nc10oLi4vLi4vLi4vdXBkYXRpbmdfeW91cl9zZXR0aW5ncy8pKSwgdGhlbiB0aGVpciBydW4gaXMgcGVyc2lzdGVkOyB0aGUgbmV4dCB0aW1lIHRoZXkgaW50ZXJhY3Qgd2l0aCB0aGUgcHJvamVjdCwgdGhleSB3aWxsIGdldCBhIG5ldyBydW4uIChTZWUgbW9yZSBiYWNrZ3JvdW5kIG9uIFtSdW4gUGVyc2lzdGVuY2VdKC4uLy4uLy4uL3J1bl9wZXJzaXN0ZW5jZS8pLilcbiAqIFxuICogVGhpcyBzdHJhdGVneSBpcyB1c2VmdWwgZm9yIG11bHRpLXBhZ2UgcHJvamVjdHMgd2hlcmUgZW5kIHVzZXJzIHBsYXkgdGhyb3VnaCBhIHNpbXVsYXRpb24gaW4gb25lIHNpdHRpbmcsIHN0ZXBwaW5nIHRocm91Z2ggdGhlIG1vZGVsIHNlcXVlbnRpYWxseSAoZm9yIGV4YW1wbGUsIGEgVmVuc2ltIG1vZGVsIHRoYXQgdXNlcyB0aGUgYHN0ZXBgIG9wZXJhdGlvbikgb3IgY2FsbGluZyBzcGVjaWZpYyBmdW5jdGlvbnMgdW50aWwgdGhlIG1vZGVsIGlzIFwiY29tcGxldGUuXCIgSG93ZXZlciwgeW91IHdpbGwgbmVlZCB0byBndWFyYW50ZWUgdGhhdCB5b3VyIGVuZCB1c2VycyB3aWxsIHJlbWFpbiBlbmdhZ2VkIHdpdGggdGhlIHByb2plY3QgZnJvbSBiZWdpbm5pbmcgdG8gZW5kICZtZGFzaDsgb3IgYXQgbGVhc3QsIHRoYXQgaWYgdGhleSBhcmUgaWRsZSBmb3IgbG9uZ2VyIHRoYW4gdGhlICoqTW9kZWwgU2Vzc2lvbiBUaW1lb3V0KiosIGl0IGlzIG9rYXkgZm9yIHRoZW0gdG8gc3RhcnQgdGhlIHByb2plY3QgZnJvbSBzY3JhdGNoICh3aXRoIGFuIHVuaW5pdGlhbGl6ZWQgbW9kZWwpLiBcbiAqIFxuICogU3BlY2lmaWNhbGx5LCB0aGUgc3RyYXRlZ3kgaXM6XG4gKlxuICogKiBDaGVjayB0aGUgYHNlc3Npb25LZXlgIGNvb2tpZS5cbiAqICAgKiBUaGlzIGNvb2tpZSBpcyBzZXQgYnkgdGhlIFtSdW4gTWFuYWdlcl0oLi4vcnVuLW1hbmFnZXIvKSBhbmQgY29uZmlndXJhYmxlIHRocm91Z2ggaXRzIG9wdGlvbnMuXG4gKiAgICogSWYgdGhlIGNvb2tpZSBleGlzdHMsIGNoZWNrIHdoZXRoZXIgdGhlIHJ1biBpcyBpbiBtZW1vcnkgb3Igb25seSBwZXJzaXN0ZWQgaW4gdGhlIGRhdGFiYXNlLiBcbiAqICAgICAgKiBJZiB0aGUgcnVuIGlzIGluIG1lbW9yeSwgdXNlIHRoZSBydW4uXG4gKiAgICAgICogSWYgdGhlIHJ1biBpcyBvbmx5IHBlcnNpc3RlZCAoYW5kIG5vdCBzdGlsbCBpbiBtZW1vcnkpLCBjcmVhdGUgYSBuZXcgcnVuIGZvciB0aGlzIGVuZCB1c2VyLlxuICogICAgICAqIElmIHRoZSBjb29raWUgZG9lcyBub3QgZXhpc3QsIGNyZWF0ZSBhIG5ldyBydW4gZm9yIHRoaXMgZW5kIHVzZXIuXG4gKlxuICogQGRlcHJlY2F0ZWQgVGhlIHJ1bi1zZXJ2aWNlIG5vdyBzZXRzIGEgaGVhZGVyIHRvIGF1dG9tYXRpY2FsbHkgYnJpbmcgYmFjayBydW5zIGludG8gbWVtb3J5XG4gKi9cblxuJ3VzZSBzdHJpY3QnO1xudmFyIGNsYXNzRnJvbSA9IHJlcXVpcmUoJy4uLy4uLy4uL3V0aWwvaW5oZXJpdCcpO1xudmFyIENvbmRpdGlvbmFsU3RyYXRlZ3kgPSByZXF1aXJlKCcuLi9jb25kaXRpb25hbC1jcmVhdGlvbi1zdHJhdGVneScpO1xuXG52YXIgX19zdXBlciA9IENvbmRpdGlvbmFsU3RyYXRlZ3kucHJvdG90eXBlO1xuXG52YXIgU3RyYXRlZ3kgPSBjbGFzc0Zyb20oQ29uZGl0aW9uYWxTdHJhdGVneSwge1xuICAgIGNvbnN0cnVjdG9yOiBmdW5jdGlvbiAob3B0aW9ucykge1xuICAgICAgICBfX3N1cGVyLmNvbnN0cnVjdG9yLmNhbGwodGhpcywgdGhpcy5jcmVhdGVJZiwgb3B0aW9ucyk7XG4gICAgICAgIGNvbnNvbGUud2FybignVGhpcyBzdHJhdGVneSBpcyBkZXByZWNhdGVkOyB0aGUgcnVuLXNlcnZpY2Ugbm93IHNldHMgYSBoZWFkZXIgdG8gYXV0b21hdGljYWxseSBicmluZyBiYWNrIHJ1bnMgaW50byBtZW1vcnknKTtcbiAgICB9LFxuXG4gICAgY3JlYXRlSWY6IGZ1bmN0aW9uIChydW4sIGhlYWRlcnMpIHtcbiAgICAgICAgcmV0dXJuIGhlYWRlcnMuZ2V0UmVzcG9uc2VIZWFkZXIoJ3ByYWdtYScpID09PSAncGVyc2lzdGVudCc7XG4gICAgfVxufSk7XG5cbm1vZHVsZS5leHBvcnRzID0gU3RyYXRlZ3k7XG4iLCIvKipcbiAqICMjIyBXb3JraW5nIHdpdGggUnVuIFN0cmF0ZWdpZXNcbiAqXG4gKiBZb3UgY2FuIGFjY2VzcyBhIGxpc3Qgb2YgYXZhaWxhYmxlIHN0cmF0ZWdpZXMgdXNpbmcgYEYubWFuYWdlci5SdW5NYW5hZ2VyLnN0cmF0ZWdpZXMubGlzdGAuIFlvdSBjYW4gYWxzbyBhc2sgZm9yIGEgcGFydGljdWxhciBzdHJhdGVneSBieSBuYW1lLlxuICpcbiAqIElmIHlvdSBkZWNpZGUgdG8gW2NyZWF0ZSB5b3VyIG93biBydW4gc3RyYXRlZ3ldKCNjcmVhdGUteW91ci1vd24pLCB5b3UgY2FuIHJlZ2lzdGVyIHlvdXIgc3RyYXRlZ3kuIFJlZ2lzdGVyaW5nIHlvdXIgc3RyYXRlZ3kgbWVhbnMgdGhhdDpcbiAqXG4gKiAqIFlvdSBjYW4gcGFzcyB0aGUgc3RyYXRlZ3kgYnkgbmFtZSB0byBhIFJ1biBNYW5hZ2VyIChhcyBvcHBvc2VkIHRvIHBhc3NpbmcgdGhlIHN0cmF0ZWd5IGZ1bmN0aW9uKTogYG5ldyBGLm1hbmFnZXIuUnVuTWFuYWdlcih7IHN0cmF0ZWd5OiAnbXluZXduYW1lJ30pYC5cbiAqICogWW91IGNhbiBwYXNzIGNvbmZpZ3VyYXRpb24gb3B0aW9ucyB0byB5b3VyIHN0cmF0ZWd5LlxuICogKiBZb3UgY2FuIHNwZWNpZnkgd2hldGhlciBvciBub3QgeW91ciBzdHJhdGVneSByZXF1aXJlcyBhdXRob3JpemF0aW9uIChhIHZhbGlkIHVzZXIgc2Vzc2lvbikgdG8gd29yay5cbiAqL1xuXG5cbnZhciBsaXN0ID0ge1xuICAgICdjb25kaXRpb25hbC1jcmVhdGlvbic6IHJlcXVpcmUoJy4vY29uZGl0aW9uYWwtY3JlYXRpb24tc3RyYXRlZ3knKSxcbiAgICAnbmV3LWlmLWluaXRpYWxpemVkJzogcmVxdWlyZSgnLi9kZXByZWNhdGVkL25ldy1pZi1pbml0aWFsaXplZC1zdHJhdGVneScpLCAvL2RlcHJlY2F0ZWRcbiAgICAnbmV3LWlmLXBlcnNpc3RlZCc6IHJlcXVpcmUoJy4vZGVwcmVjYXRlZC9uZXctaWYtcGVyc2lzdGVkLXN0cmF0ZWd5JyksIC8vZGVwcmVjYXRlZFxuXG4gICAgbm9uZTogcmVxdWlyZSgnLi9ub25lLXN0cmF0ZWd5JyksXG5cbiAgICBtdWx0aXBsYXllcjogcmVxdWlyZSgnLi9tdWx0aXBsYXllci1zdHJhdGVneScpLFxuICAgICdyZXVzZS1uZXZlcic6IHJlcXVpcmUoJy4vcmV1c2UtbmV2ZXInKSxcbiAgICAncmV1c2UtcGVyLXNlc3Npb24nOiByZXF1aXJlKCcuL3JldXNlLXBlci1zZXNzaW9uJyksXG4gICAgJ3JldXNlLWFjcm9zcy1zZXNzaW9ucyc6IHJlcXVpcmUoJy4vcmV1c2UtYWNyb3NzLXNlc3Npb25zJyksXG4gICAgJ3JldXNlLWxhc3QtaW5pdGlhbGl6ZWQnOiByZXF1aXJlKCcuL3JldXNlLWxhc3QtaW5pdGlhbGl6ZWQnKSxcbn07XG5cbi8vQWRkIGJhY2sgb2xkZXIgYWxpYXNlc1xubGlzdFsnYWx3YXlzLW5ldyddID0gbGlzdFsncmV1c2UtbmV2ZXInXTtcbmxpc3RbJ25ldy1pZi1taXNzaW5nJ10gPSBsaXN0WydyZXVzZS1wZXItc2Vzc2lvbiddO1xubGlzdFsncGVyc2lzdGVudC1zaW5nbGUtcGxheWVyJ10gPSBsaXN0WydyZXVzZS1hY3Jvc3Mtc2Vzc2lvbnMnXTtcblxuXG5tb2R1bGUuZXhwb3J0cyA9IHtcbiAgICAvKipcbiAgICAgKiBMaXN0IG9mIGF2YWlsYWJsZSBzdHJhdGVnaWVzLiBXaXRoaW4gdGhpcyBvYmplY3QsIGVhY2gga2V5IGlzIHRoZSBzdHJhdGVneSBuYW1lIGFuZCB0aGUgYXNzb2NpYXRlZCB2YWx1ZSBpcyB0aGUgc3RyYXRlZ3kgY29uc3RydWN0b3IuXG4gICAgICogQHR5cGUge09iamVjdH0gXG4gICAgICovXG4gICAgbGlzdDogbGlzdCxcblxuICAgIC8qKlxuICAgICAqIEdldHMgc3RyYXRlZ3kgYnkgbmFtZS5cbiAgICAgKlxuICAgICAqICoqRXhhbXBsZSoqXG4gICAgICpcbiAgICAgKiAgICAgIHZhciByZXVzZVN0cmF0ID0gRi5tYW5hZ2VyLlJ1bk1hbmFnZXIuc3RyYXRlZ2llcy5ieU5hbWUoJ3JldXNlLWFjcm9zcy1zZXNzaW9ucycpO1xuICAgICAqICAgICAgLy8gc2hvd3Mgc3RyYXRlZ3kgZnVuY3Rpb25cbiAgICAgKiAgICAgIGNvbnNvbGUubG9nKCdyZXVzZVN0cmF0ID0gJywgcmV1c2VTdHJhdCk7XG4gICAgICogICAgICAvLyBjcmVhdGUgYSBuZXcgcnVuIG1hbmFnZXIgdXNpbmcgdGhpcyBzdHJhdGVneVxuICAgICAqICAgICAgdmFyIHJtID0gbmV3IEYubWFuYWdlci5SdW5NYW5hZ2VyKHtzdHJhdGVneTogcmV1c2VTdHJhdCwgcnVuOiB7IG1vZGVsOiAnbW9kZWwudm1mJ30gfSk7XG4gICAgICpcbiAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAqIEBwYXJhbSAge1N0cmluZ30gc3RyYXRlZ3lOYW1lIE5hbWUgb2Ygc3RyYXRlZ3kgdG8gZ2V0LlxuICAgICAqIEByZXR1cm4ge0Z1bmN0aW9ufSBTdHJhdGVneSBmdW5jdGlvbi5cbiAgICAgKi9cbiAgICBieU5hbWU6IGZ1bmN0aW9uIChzdHJhdGVneU5hbWUpIHtcbiAgICAgICAgcmV0dXJuIGxpc3Rbc3RyYXRlZ3lOYW1lXTtcbiAgICB9LFxuXG4gICAgZ2V0QmVzdFN0cmF0ZWd5OiBmdW5jdGlvbiAob3B0aW9ucykge1xuICAgICAgICB2YXIgc3RyYXRlZ3kgPSBvcHRpb25zLnN0cmF0ZWd5O1xuICAgICAgICBpZiAoIXN0cmF0ZWd5KSB7XG4gICAgICAgICAgICBpZiAob3B0aW9ucy5zdHJhdGVneU9wdGlvbnMgJiYgb3B0aW9ucy5zdHJhdGVneU9wdGlvbnMuaW5pdE9wZXJhdGlvbikge1xuICAgICAgICAgICAgICAgIHN0cmF0ZWd5ID0gJ3JldXNlLWxhc3QtaW5pdGlhbGl6ZWQnO1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICBzdHJhdGVneSA9ICdyZXVzZS1wZXItc2Vzc2lvbic7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICBpZiAoc3RyYXRlZ3kuZ2V0UnVuKSB7XG4gICAgICAgICAgICByZXR1cm4gc3RyYXRlZ3k7XG4gICAgICAgIH1cbiAgICAgICAgdmFyIFN0cmF0ZWd5Q3RvciA9IHR5cGVvZiBzdHJhdGVneSA9PT0gJ2Z1bmN0aW9uJyA/IHN0cmF0ZWd5IDogdGhpcy5ieU5hbWUoc3RyYXRlZ3kpO1xuICAgICAgICBpZiAoIVN0cmF0ZWd5Q3Rvcikge1xuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdTcGVjaWZpZWQgcnVuIGNyZWF0aW9uIHN0cmF0ZWd5IHdhcyBpbnZhbGlkOicsIHN0cmF0ZWd5KTtcbiAgICAgICAgfVxuXG4gICAgICAgIHZhciBzdHJhdGVneUluc3RhbmNlID0gbmV3IFN0cmF0ZWd5Q3RvcihvcHRpb25zKTtcbiAgICAgICAgaWYgKCFzdHJhdGVneUluc3RhbmNlLmdldFJ1biB8fCAhc3RyYXRlZ3lJbnN0YW5jZS5yZXNldCkge1xuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdBbGwgc3RyYXRlZ2llcyBzaG91bGQgaW1wbGVtZW50IGEgYGdldFJ1bmAgYW5kIGByZXNldGAgaW50ZXJmYWNlJywgb3B0aW9ucy5zdHJhdGVneSk7XG4gICAgICAgIH1cbiAgICAgICAgc3RyYXRlZ3lJbnN0YW5jZS5yZXF1aXJlc0F1dGggPSBTdHJhdGVneUN0b3IucmVxdWlyZXNBdXRoO1xuXG4gICAgICAgIHJldHVybiBzdHJhdGVneUluc3RhbmNlO1xuICAgIH0sXG5cbiAgICAvKipcbiAgICAgKiBBZGRzIGEgbmV3IHN0cmF0ZWd5LlxuICAgICAqXG4gICAgICogKipFeGFtcGxlKipcbiAgICAgKlxuICAgICAqICAgICAgLy8gdGhpcyBcImZhdm9yaXRlIHJ1blwiIHN0cmF0ZWd5IGFsd2F5cyByZXR1cm5zIHRoZSBzYW1lIHJ1biwgbm8gbWF0dGVyIHdoYXRcbiAgICAgKiAgICAgIC8vIChub3QgYSB1c2VmdWwgc3RyYXRlZ3ksIGV4Y2VwdCBhcyBhbiBleGFtcGxlKVxuICAgICAqICAgICAgRi5tYW5hZ2VyLlJ1bk1hbmFnZXIuc3RyYXRlZ2llcy5yZWdpc3RlcihcbiAgICAgKiAgICAgICAgICAnZmF2UnVuJywgXG4gICAgICogICAgICAgICAgZnVuY3Rpb24oKSB7IFxuICAgICAqICAgICAgICAgICAgICByZXR1cm4geyBnZXRSdW46IGZ1bmN0aW9uKCkgeyByZXR1cm4gJzAwMDAwMTVhNGNkMTcwMDIwOWNkMGE3ZDIwN2Y0NGJhYzI4OSc7IH0sXG4gICAgICogICAgICAgICAgICAgICAgICAgICAgcmVzZXQ6IGZ1bmN0aW9uKCkgeyByZXR1cm4gJzAwMDAwMTVhNGNkMTcwMDIwOWNkMGE3ZDIwN2Y0NGJhYzI4OSc7IH0gXG4gICAgICogICAgICAgICAgICAgIH0gXG4gICAgICogICAgICAgICAgfSwgXG4gICAgICogICAgICAgICAgeyByZXF1aXJlc0F1dGg6IHRydWUgfVxuICAgICAqICAgICAgKTtcbiAgICAgKiAgICAgIFxuICAgICAqICAgICAgdmFyIHJtID0gbmV3IEYubWFuYWdlci5SdW5NYW5hZ2VyKHtzdHJhdGVneTogJ2ZhdlJ1bicsIHJ1bjogeyBtb2RlbDogJ21vZGVsLnZtZid9IH0pO1xuICAgICAqXG4gICAgICogKipQYXJhbWV0ZXJzKipcbiAgICAgKiBAcGFyYW0gIHtTdHJpbmd9IG5hbWUgTmFtZSBmb3Igc3RyYXRlZ3kuIFRoaXMgc3RyaW5nIGNhbiB0aGVuIGJlIHBhc3NlZCB0byBhIFJ1biBNYW5hZ2VyIGFzIGBuZXcgRi5tYW5hZ2VyLlJ1bk1hbmFnZXIoeyBzdHJhdGVneTogJ215bmV3bmFtZSd9KWAuXG4gICAgICogQHBhcmFtICB7RnVuY3Rpb259IHN0cmF0ZWd5IFRoZSBzdHJhdGVneSBjb25zdHJ1Y3Rvci4gV2lsbCBiZSBjYWxsZWQgd2l0aCBgbmV3YCBvbiBSdW4gTWFuYWdlciBpbml0aWFsaXphdGlvbi5cbiAgICAgKiBAcGFyYW0gIHtPYmplY3R9IG9wdGlvbnMgIE9wdGlvbnMgZm9yIHN0cmF0ZWd5LlxuICAgICAqIEBwYXJhbSAge0Jvb2xlYW59IG9wdGlvbnMucmVxdWlyZXNBdXRoIFNwZWNpZnkgaWYgdGhlIHN0cmF0ZWd5IHJlcXVpcmVzIGEgdmFsaWQgdXNlciBzZXNzaW9uIHRvIHdvcmsuXG4gICAgICovXG4gICAgcmVnaXN0ZXI6IGZ1bmN0aW9uIChuYW1lLCBzdHJhdGVneSwgb3B0aW9ucykge1xuICAgICAgICBzdHJhdGVneS5vcHRpb25zID0gb3B0aW9ucztcbiAgICAgICAgbGlzdFtuYW1lXSA9IHN0cmF0ZWd5O1xuICAgIH1cbn07IiwiLyoqXG4gKiBUaGUgYG11bHRpcGxheWVyYCBzdHJhdGVneSBpcyBmb3IgdXNlIHdpdGggW211bHRpcGxheWVyIHdvcmxkc10oLi4vLi4vLi4vZ2xvc3NhcnkvI3dvcmxkKS4gSXQgY2hlY2tzIHRoZSBjdXJyZW50IHdvcmxkIGZvciB0aGlzIGVuZCB1c2VyLCBhbmQgYWx3YXlzIHJldHVybnMgdGhlIGN1cnJlbnQgcnVuIGZvciB0aGF0IHdvcmxkLiBUaGlzIGlzIGVxdWl2YWxlbnQgdG8gY2FsbGluZyBgZ2V0Q3VycmVudFdvcmxkRm9yVXNlcigpYCBhbmQgdGhlbiBgZ2V0Q3VycmVudFJ1bklkKClgIGZyb20gdGhlIFtXb3JsZCBBUEkgQWRhcGF0ZXJdKC4uL3dvcmxkLWFwaS1hZGFwdGVyLykuIElmIHlvdSB1c2UgdGhlIFtXb3JsZCBNYW5hZ2VyXSguLi93b3JsZC1tYW5hZ2VyLyksIHlvdSBhcmUgYXV0b21hdGljYWxseSB1c2luZyB0aGlzIHN0cmF0ZWd5LlxuICogXG4gKiBVc2luZyB0aGlzIHN0cmF0ZWd5IG1lYW5zIHRoYXQgZW5kIHVzZXJzIGluIHByb2plY3RzIHdpdGggbXVsdGlwbGF5ZXIgd29ybGRzIGFsd2F5cyBzZWUgdGhlIG1vc3QgY3VycmVudCB3b3JsZCBhbmQgcnVuLiBUaGlzIGVuc3VyZXMgdGhhdCB0aGV5IGFyZSBpbiBzeW5jIHdpdGggdGhlIG90aGVyIGVuZCB1c2VycyBzaGFyaW5nIHRoZWlyIHdvcmxkIGFuZCBydW4uIEluIHR1cm4sIHRoaXMgYWxsb3dzIGZvciBjb21wZXRpdGl2ZSBvciBjb2xsYWJvcmF0aXZlIG11bHRpcGxheWVyIHByb2plY3RzLlxuICovXG4ndXNlIHN0cmljdCc7XG5cbnZhciBjbGFzc0Zyb20gPSByZXF1aXJlKCcuLi8uLi91dGlsL2luaGVyaXQnKTtcblxudmFyIElkZW50aXR5U3RyYXRlZ3kgPSByZXF1aXJlKCcuL25vbmUtc3RyYXRlZ3knKTtcbnZhciBXb3JsZEFwaUFkYXB0ZXIgPSByZXF1aXJlKCcuLi8uLi9zZXJ2aWNlL3dvcmxkLWFwaS1hZGFwdGVyJyk7XG5cbnZhciBkZWZhdWx0cyA9IHt9O1xuXG52YXIgU3RyYXRlZ3kgPSBjbGFzc0Zyb20oSWRlbnRpdHlTdHJhdGVneSwge1xuICAgIGNvbnN0cnVjdG9yOiBmdW5jdGlvbiAob3B0aW9ucykge1xuICAgICAgICB0aGlzLm9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSwgZGVmYXVsdHMsIG9wdGlvbnMpO1xuICAgICAgICB0aGlzLndvcmxkQXBpID0gbmV3IFdvcmxkQXBpQWRhcHRlcih0aGlzLm9wdGlvbnMucnVuKTtcbiAgICB9LFxuXG4gICAgcmVzZXQ6IGZ1bmN0aW9uIChydW5TZXJ2aWNlLCBzZXNzaW9uLCBvcHRpb25zKSB7XG4gICAgICAgIHZhciBjdXJVc2VySWQgPSBzZXNzaW9uLnVzZXJJZDtcbiAgICAgICAgdmFyIGN1ckdyb3VwTmFtZSA9IHNlc3Npb24uZ3JvdXBOYW1lO1xuXG4gICAgICAgIHJldHVybiB0aGlzLndvcmxkQXBpXG4gICAgICAgICAgICAuZ2V0Q3VycmVudFdvcmxkRm9yVXNlcihjdXJVc2VySWQsIGN1ckdyb3VwTmFtZSlcbiAgICAgICAgICAgIC50aGVuKGZ1bmN0aW9uICh3b3JsZCkge1xuICAgICAgICAgICAgICAgIHJldHVybiB0aGlzLndvcmxkQXBpLm5ld1J1bkZvcldvcmxkKHdvcmxkLmlkLCBvcHRpb25zKS50aGVuKGZ1bmN0aW9uIChydW5pZCkge1xuICAgICAgICAgICAgICAgICAgICByZXR1cm4ge1xuICAgICAgICAgICAgICAgICAgICAgICAgaWQ6IHJ1bmlkXG4gICAgICAgICAgICAgICAgICAgIH07XG4gICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICB9LmJpbmQodGhpcykpO1xuICAgIH0sXG5cbiAgICBnZXRSdW46IGZ1bmN0aW9uIChydW5TZXJ2aWNlLCBzZXNzaW9uKSB7XG4gICAgICAgIHZhciBjdXJVc2VySWQgPSBzZXNzaW9uLnVzZXJJZDtcbiAgICAgICAgdmFyIGN1ckdyb3VwTmFtZSA9IHNlc3Npb24uZ3JvdXBOYW1lO1xuICAgICAgICB2YXIgd29ybGRBcGkgPSB0aGlzLndvcmxkQXBpO1xuICAgICAgICB2YXIgbW9kZWwgPSB0aGlzLm9wdGlvbnMubW9kZWw7XG4gICAgICAgIHZhciBtZSA9IHRoaXM7XG4gICAgICAgIHZhciBkdGQgPSAkLkRlZmVycmVkKCk7XG5cbiAgICAgICAgaWYgKCFjdXJVc2VySWQpIHtcbiAgICAgICAgICAgIHJldHVybiBkdGQucmVqZWN0KHsgc3RhdHVzQ29kZTogNDAwLCBlcnJvcjogJ1dlIG5lZWQgYW4gYXV0aGVudGljYXRlZCB1c2VyIHRvIGpvaW4gYSBtdWx0aXBsYXllciB3b3JsZC4gKEVSUjogbm8gdXNlcklkIGluIHNlc3Npb24pJyB9LCBzZXNzaW9uKS5wcm9taXNlKCk7XG4gICAgICAgIH1cblxuICAgICAgICB2YXIgbG9hZFJ1bkZyb21Xb3JsZCA9IGZ1bmN0aW9uICh3b3JsZCkge1xuICAgICAgICAgICAgaWYgKCF3b3JsZCkge1xuICAgICAgICAgICAgICAgIHJldHVybiBkdGQucmVqZWN0KHsgc3RhdHVzQ29kZTogNDA0LCBlcnJvcjogJ1RoZSB1c2VyIGlzIG5vdCBpbiBhbnkgd29ybGQuJyB9LCB7IG9wdGlvbnM6IG1lLm9wdGlvbnMsIHNlc3Npb246IHNlc3Npb24gfSk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICByZXR1cm4gd29ybGRBcGkuZ2V0Q3VycmVudFJ1bklkKHsgbW9kZWw6IG1vZGVsLCBmaWx0ZXI6IHdvcmxkLmlkIH0pXG4gICAgICAgICAgICAgICAgLnRoZW4oZnVuY3Rpb24gKGlkKSB7XG4gICAgICAgICAgICAgICAgICAgIHJldHVybiBydW5TZXJ2aWNlLmxvYWQoaWQpO1xuICAgICAgICAgICAgICAgIH0pXG4gICAgICAgICAgICAgICAgLnRoZW4oZHRkLnJlc29sdmUpXG4gICAgICAgICAgICAgICAgLmZhaWwoZHRkLnJlamVjdCk7XG4gICAgICAgIH07XG5cbiAgICAgICAgdmFyIHNlcnZlckVycm9yID0gZnVuY3Rpb24gKGVycm9yKSB7XG4gICAgICAgICAgICAvLyBpcyB0aGlzIHBvc3NpYmxlP1xuICAgICAgICAgICAgcmV0dXJuIGR0ZC5yZWplY3QoZXJyb3IsIHNlc3Npb24sIG1lLm9wdGlvbnMpO1xuICAgICAgICB9O1xuXG4gICAgICAgIHRoaXMud29ybGRBcGlcbiAgICAgICAgICAgIC5nZXRDdXJyZW50V29ybGRGb3JVc2VyKGN1clVzZXJJZCwgY3VyR3JvdXBOYW1lKVxuICAgICAgICAgICAgLnRoZW4obG9hZFJ1bkZyb21Xb3JsZClcbiAgICAgICAgICAgIC5mYWlsKHNlcnZlckVycm9yKTtcblxuICAgICAgICByZXR1cm4gZHRkLnByb21pc2UoKTtcbiAgICB9LFxuXG59KTtcblxubW9kdWxlLmV4cG9ydHMgPSBTdHJhdGVneTtcbiIsIi8qKlxuICogVGhlIGBub25lYCBzdHJhdGVneSBuZXZlciByZXR1cm5zIGEgcnVuIG9yIHRyaWVzIHRvIGNyZWF0ZSBhIG5ldyBydW4uIEl0IHNpbXBseSByZXR1cm5zIHRoZSBjb250ZW50cyBvZiB0aGUgY3VycmVudCBbUnVuIFNlcnZpY2UgaW5zdGFuY2VdKC4uL3J1bi1hcGktc2VydmljZS8pLlxuICogXG4gKiBUaGlzIHN0cmF0ZWd5IGlzIHVzZWZ1bCBpZiB5b3Ugd2FudCB0byBtYW51YWxseSBkZWNpZGUgaG93IHRvIGNyZWF0ZSB5b3VyIG93biBydW5zIGFuZCBkb24ndCB3YW50IGFueSBhdXRvbWF0aWMgYXNzaXN0YW5jZS5cbiAqL1xuXG4ndXNlIHN0cmljdCc7XG5cbnZhciBjbGFzc0Zyb20gPSByZXF1aXJlKCcuLi8uLi91dGlsL2luaGVyaXQnKTtcbnZhciBCYXNlID0ge307XG5cbi8vIEludGVyZmFjZSB0aGF0IGFsbCBzdHJhdGVnaWVzIG5lZWQgdG8gaW1wbGVtZW50XG5tb2R1bGUuZXhwb3J0cyA9IGNsYXNzRnJvbShCYXNlLCB7XG4gICAgY29uc3RydWN0b3I6IGZ1bmN0aW9uIChvcHRpb25zKSB7XG5cbiAgICB9LFxuXG4gICAgcmVzZXQ6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgLy8gcmV0dXJuIGEgbmV3bHkgY3JlYXRlZCBydW5cbiAgICAgICAgcmV0dXJuICQuRGVmZXJyZWQoKS5yZXNvbHZlKCkucHJvbWlzZSgpO1xuICAgIH0sXG5cbiAgICBnZXRSdW46IGZ1bmN0aW9uIChydW5TZXJ2aWNlKSB7XG4gICAgICAgIC8vIHJldHVybiBhIHVzYWJsZSBydW5cbiAgICAgICAgcmV0dXJuICQuRGVmZXJyZWQoKS5yZXNvbHZlKHJ1blNlcnZpY2UpLnByb21pc2UoKTtcbiAgICB9XG59KTtcbiIsIi8qKlxuICogVGhlIGByZXVzZS1hY3Jvc3Mtc2Vzc2lvbnNgIHN0cmF0ZWd5IHJldHVybnMgdGhlIGxhdGVzdCAobW9zdCByZWNlbnQpIHJ1biBmb3IgdGhpcyB1c2VyLCB3aGV0aGVyIGl0IGlzIGluIG1lbW9yeSBvciBub3QuIElmIHRoZXJlIGFyZSBubyBydW5zIGZvciB0aGlzIHVzZXIsIGl0IGNyZWF0ZXMgYSBuZXcgb25lLlxuICpcbiAqIFRoaXMgc3RyYXRlZ3kgaXMgdXNlZnVsIGlmIGVuZCB1c2VycyBhcmUgdXNpbmcgeW91ciBwcm9qZWN0IGZvciBhbiBleHRlbmRlZCBwZXJpb2Qgb2YgdGltZSwgcG9zc2libHkgb3ZlciBzZXZlcmFsIHNlc3Npb25zLiBUaGlzIGlzIG1vc3QgY29tbW9uIGluIGNhc2VzIHdoZXJlIGEgdXNlciBvZiB5b3VyIHByb2plY3QgZXhlY3V0ZXMgdGhlIG1vZGVsIHN0ZXAgYnkgc3RlcCAoYXMgb3Bwb3NlZCB0byBhIHByb2plY3Qgd2hlcmUgdGhlIG1vZGVsIGlzIGV4ZWN1dGVkIGNvbXBsZXRlbHksIGZvciBleGFtcGxlLCBhIFZlbnNpbSBtb2RlbCB0aGF0IGlzIGltbWVkaWF0ZWx5IHN0ZXBwZWQgdG8gdGhlIGVuZCkuXG4gKlxuICogU3BlY2lmaWNhbGx5LCB0aGUgc3RyYXRlZ3kgaXM6XG4gKiBcbiAqICogQ2hlY2sgaWYgdGhlcmUgYXJlIGFueSBydW5zIGZvciB0aGlzIGVuZCB1c2VyLlxuICogICAgICogSWYgdGhlcmUgYXJlIG5vIHJ1bnMgKGVpdGhlciBpbiBtZW1vcnkgb3IgaW4gdGhlIGRhdGFiYXNlKSwgY3JlYXRlIGEgbmV3IG9uZS5cbiAqICAgICAqIElmIHRoZXJlIGFyZSBydW5zLCB0YWtlIHRoZSBsYXRlc3QgKG1vc3QgcmVjZW50KSBvbmUuXG4gKlxuICogQG5hbWUgcGVyc2lzdGVudC1zaW5nbGUtcGxheWVyXG4gKi9cblxuJ3VzZSBzdHJpY3QnO1xuXG52YXIgY2xhc3NGcm9tID0gcmVxdWlyZSgnLi4vLi4vdXRpbC9pbmhlcml0Jyk7XG52YXIgSWRlbnRpdHlTdHJhdGVneSA9IHJlcXVpcmUoJy4vbm9uZS1zdHJhdGVneScpO1xudmFyIGluamVjdEZpbHRlcnNGcm9tU2Vzc2lvbiA9IHJlcXVpcmUoJy4uL3N0cmF0ZWd5LXV0aWxzJykuaW5qZWN0RmlsdGVyc0Zyb21TZXNzaW9uO1xudmFyIGluamVjdFNjb3BlRnJvbVNlc3Npb24gPSByZXF1aXJlKCcuLi9zdHJhdGVneS11dGlscycpLmluamVjdFNjb3BlRnJvbVNlc3Npb247XG5cbnZhciBkZWZhdWx0cyA9IHtcbiAgICAvKipcbiAgICAgKiAoT3B0aW9uYWwpIEFkZGl0aW9uYWwgY3JpdGVyaWEgdG8gdXNlIHdoaWxlIHNlbGVjdGluZyB0aGUgbGFzdCBydW5cbiAgICAgKiBAdHlwZSB7T2JqZWN0fVxuICAgICAqL1xuICAgIGZpbHRlcjoge30sXG59O1xuXG52YXIgU3RyYXRlZ3kgPSBjbGFzc0Zyb20oSWRlbnRpdHlTdHJhdGVneSwge1xuICAgIGNvbnN0cnVjdG9yOiBmdW5jdGlvbiBTdHJhdGVneShvcHRpb25zKSB7XG4gICAgICAgIHZhciBzdHJhdGVneU9wdGlvbnMgPSBvcHRpb25zID8gb3B0aW9ucy5zdHJhdGVneU9wdGlvbnMgOiB7fTtcbiAgICAgICAgdGhpcy5vcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sIGRlZmF1bHRzLCBzdHJhdGVneU9wdGlvbnMpO1xuICAgIH0sXG5cbiAgICByZXNldDogZnVuY3Rpb24gKHJ1blNlcnZpY2UsIHVzZXJTZXNzaW9uLCBvcHRpb25zKSB7XG4gICAgICAgIHZhciBvcHQgPSBpbmplY3RTY29wZUZyb21TZXNzaW9uKHJ1blNlcnZpY2UuZ2V0Q3VycmVudENvbmZpZygpLCB1c2VyU2Vzc2lvbik7XG4gICAgICAgIHJldHVybiBydW5TZXJ2aWNlXG4gICAgICAgICAgICAuY3JlYXRlKG9wdCwgb3B0aW9ucylcbiAgICAgICAgICAgIC50aGVuKGZ1bmN0aW9uIChydW4pIHtcbiAgICAgICAgICAgICAgICBydW4uZnJlc2hseUNyZWF0ZWQgPSB0cnVlO1xuICAgICAgICAgICAgICAgIHJldHVybiBydW47XG4gICAgICAgICAgICB9KTtcbiAgICB9LFxuXG4gICAgZ2V0UnVuOiBmdW5jdGlvbiAocnVuU2VydmljZSwgdXNlclNlc3Npb24sIHJ1blNlc3Npb24sIG9wdGlvbnMpIHtcbiAgICAgICAgdmFyIGZpbHRlciA9IGluamVjdEZpbHRlcnNGcm9tU2Vzc2lvbih0aGlzLm9wdGlvbnMuZmlsdGVyLCB1c2VyU2Vzc2lvbik7XG4gICAgICAgIHZhciBtZSA9IHRoaXM7XG4gICAgICAgIHJldHVybiBydW5TZXJ2aWNlLnF1ZXJ5KGZpbHRlciwgeyBcbiAgICAgICAgICAgIC8vIHN0YXJ0cmVjb3JkOiAwLCAvL1RPRE86IFVuY29tbWVudCB3aGVuIEVQSUNFTlRFUi0yNTY5IGlzIGZpeGVkXG4gICAgICAgICAgICAvLyBlbmRyZWNvcmQ6IDAsXG4gICAgICAgICAgICBzb3J0OiAnY3JlYXRlZCcsIFxuICAgICAgICAgICAgZGlyZWN0aW9uOiAnZGVzYydcbiAgICAgICAgfSkudGhlbihmdW5jdGlvbiAocnVucykge1xuICAgICAgICAgICAgaWYgKCFydW5zLmxlbmd0aCkge1xuICAgICAgICAgICAgICAgIHJldHVybiBtZS5yZXNldChydW5TZXJ2aWNlLCB1c2VyU2Vzc2lvbiwgb3B0aW9ucyk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICByZXR1cm4gcnVuc1swXTtcbiAgICAgICAgfSk7XG4gICAgfVxufSk7XG5cbm1vZHVsZS5leHBvcnRzID0gU3RyYXRlZ3k7XG4iLCIvKipcbiAqIFRoZSBgcmV1c2UtbGFzdC1pbml0aWFsaXplZGAgc3RyYXRlZ3kgbG9va3MgZm9yIHRoZSBtb3N0IHJlY2VudCBydW4gdGhhdCBtYXRjaGVzIHBhcnRpY3VsYXIgY3JpdGVyaWE7IGlmIGl0IGNhbm5vdCBmaW5kIG9uZSwgaXQgY3JlYXRlcyBhIG5ldyBydW4gYW5kIGltbWVkaWF0ZWx5IGV4ZWN1dGVzIGEgc2V0IG9mIFwiaW5pdGlhbGl6YXRpb25cIiBvcGVyYXRpb25zLiBcbiAqXG4gKiBUaGlzIHN0cmF0ZWd5IGlzIHVzZWZ1bCBpZiB5b3UgaGF2ZSBhIHRpbWUtYmFzZWQgbW9kZWwgYW5kIGFsd2F5cyB3YW50IHRoZSBydW4geW91J3JlIG9wZXJhdGluZyBvbiB0byBzdGFydCBhdCBhIHBhcnRpY3VsYXIgc3RlcC4gRm9yIGV4YW1wbGU6XG4gKlxuICogICAgICB2YXIgcm0gPSBuZXcgRi5tYW5hZ2VyLlJ1bk1hbmFnZXIoe1xuICogICAgICAgICAgc3RyYXRlZ3k6ICdyZXVzZS1sYXN0LWluaXRpYWxpemVkJyxcbiAqICAgICAgICAgIHN0cmF0ZWd5T3B0aW9uczoge1xuICogICAgICAgICAgICAgIGluaXRPcGVyYXRpb246IFt7IHN0ZXA6IDEwIH1dXG4gKiAgICAgICAgICB9XG4gKiAgICAgIH0pO1xuICogXG4gKiBUaGlzIHN0cmF0ZWd5IGlzIGFsc28gdXNlZnVsIGlmIHlvdSBoYXZlIGEgY3VzdG9tIGluaXRpYWxpemF0aW9uIGZ1bmN0aW9uIGluIHlvdXIgbW9kZWwsIGFuZCB3YW50IHRvIG1ha2Ugc3VyZSBpdCdzIGFsd2F5cyBleGVjdXRlZCBmb3IgbmV3IHJ1bnMuXG4gKlxuICogU3BlY2lmaWNhbGx5LCB0aGUgc3RyYXRlZ3kgaXM6XG4gKlxuICogKiBMb29rIGZvciB0aGUgbW9zdCByZWNlbnQgcnVuIHRoYXQgbWF0Y2hlcyB0aGUgKG9wdGlvbmFsKSBgZmxhZ2AgY3JpdGVyaWFcbiAqICogSWYgdGhlcmUgYXJlIG5vIHJ1bnMgdGhhdCBtYXRjaCB0aGUgYGZsYWdgIGNyaXRlcmlhLCBjcmVhdGUgYSBuZXcgcnVuLiBJbW1lZGlhdGVseSBcImluaXRpYWxpemVcIiB0aGlzIG5ldyBydW4gYnk6XG4gKiAgICAgKiAgQ2FsbGluZyB0aGUgbW9kZWwgb3BlcmF0aW9uKHMpIHNwZWNpZmllZCBpbiB0aGUgYGluaXRPcGVyYXRpb25gIGFycmF5LlxuICogICAgICogIE9wdGlvbmFsbHksIHNldHRpbmcgYSBgZmxhZ2AgaW4gdGhlIHJ1bi5cbiAqXG4gKi9cblxuJ3VzZSBzdHJpY3QnO1xudmFyIGNsYXNzRnJvbSA9IHJlcXVpcmUoJy4uLy4uL3V0aWwvaW5oZXJpdCcpO1xudmFyIGluamVjdEZpbHRlcnNGcm9tU2Vzc2lvbiA9IHJlcXVpcmUoJy4uL3N0cmF0ZWd5LXV0aWxzJykuaW5qZWN0RmlsdGVyc0Zyb21TZXNzaW9uO1xudmFyIGluamVjdFNjb3BlRnJvbVNlc3Npb24gPSByZXF1aXJlKCcuLi9zdHJhdGVneS11dGlscycpLmluamVjdFNjb3BlRnJvbVNlc3Npb247XG5cbnZhciBCYXNlID0ge307XG5cbnZhciBkZWZhdWx0cyA9IHtcbiAgICAvKipcbiAgICAgKiBPcGVyYXRpb25zIHRvIGV4ZWN1dGUgaW4gdGhlIG1vZGVsIGZvciBpbml0aWFsaXphdGlvbiB0byBiZSBjb25zaWRlcmVkIGNvbXBsZXRlLlxuICAgICAqIEB0eXBlIHtBcnJheX0gQ2FuIGJlIGluIGFueSBvZiB0aGUgZm9ybWF0cyBbUnVuIFNlcnZpY2UncyBgc2VyaWFsKClgXSguLi9ydW4tYXBpLXNlcnZpY2UvI3NlcmlhbCkgc3VwcG9ydHMuXG4gICAgICovXG4gICAgaW5pdE9wZXJhdGlvbjogW10sXG5cbiAgICAvKipcbiAgICAgKiAoT3B0aW9uYWwpIEZsYWcgdG8gc2V0IGluIHJ1biBhZnRlciBpbml0aWFsaXphdGlvbiBvcGVyYXRpb25zIGFyZSBydW4uIFlvdSB0eXBpY2FsbHkgd291bGQgbm90IG92ZXJyaWRlIHRoaXMgdW5sZXNzIHlvdSBuZWVkZWQgdG8gc2V0IGFkZGl0aW9uYWwgcHJvcGVydGllcyBhcyB3ZWxsLlxuICAgICAqIEB0eXBlIHtPYmplY3R9XG4gICAgICovXG4gICAgZmxhZzogbnVsbCxcbn07XG5tb2R1bGUuZXhwb3J0cyA9IGNsYXNzRnJvbShCYXNlLCB7XG4gICAgY29uc3RydWN0b3I6IGZ1bmN0aW9uIChvcHRpb25zKSB7XG4gICAgICAgIHZhciBzdHJhdGVneU9wdGlvbnMgPSBvcHRpb25zID8gb3B0aW9ucy5zdHJhdGVneU9wdGlvbnMgOiB7fTtcbiAgICAgICAgdGhpcy5vcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sIGRlZmF1bHRzLCBzdHJhdGVneU9wdGlvbnMpO1xuICAgICAgICBpZiAoIXRoaXMub3B0aW9ucy5pbml0T3BlcmF0aW9uIHx8ICF0aGlzLm9wdGlvbnMuaW5pdE9wZXJhdGlvbi5sZW5ndGgpIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcignU3BlY2lmeWluZyBhbiBpbml0IGZ1bmN0aW9uIGlzIHJlcXVpcmVkIGZvciB0aGlzIHN0cmF0ZWd5Jyk7XG4gICAgICAgIH1cbiAgICAgICAgaWYgKCF0aGlzLm9wdGlvbnMuZmxhZykge1xuICAgICAgICAgICAgdGhpcy5vcHRpb25zLmZsYWcgPSB7XG4gICAgICAgICAgICAgICAgaXNJbml0Q29tcGxldGU6IHRydWVcbiAgICAgICAgICAgIH07XG4gICAgICAgIH1cbiAgICB9LFxuXG4gICAgcmVzZXQ6IGZ1bmN0aW9uIChydW5TZXJ2aWNlLCB1c2VyU2Vzc2lvbiwgb3B0aW9ucykge1xuICAgICAgICB2YXIgb3B0ID0gaW5qZWN0U2NvcGVGcm9tU2Vzc2lvbihydW5TZXJ2aWNlLmdldEN1cnJlbnRDb25maWcoKSwgdXNlclNlc3Npb24pO1xuICAgICAgICB2YXIgbWUgPSB0aGlzO1xuICAgICAgICByZXR1cm4gcnVuU2VydmljZS5jcmVhdGUob3B0LCBvcHRpb25zKS50aGVuKGZ1bmN0aW9uIChjcmVhdGVSZXNwb25zZSkge1xuICAgICAgICAgICAgcmV0dXJuIHJ1blNlcnZpY2Uuc2VyaWFsKFtdLmNvbmNhdChtZS5vcHRpb25zLmluaXRPcGVyYXRpb24pKS50aGVuKGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gY3JlYXRlUmVzcG9uc2U7XG4gICAgICAgICAgICB9KTtcbiAgICAgICAgfSkudGhlbihmdW5jdGlvbiAoY3JlYXRlUmVzcG9uc2UpIHtcbiAgICAgICAgICAgIHJldHVybiBydW5TZXJ2aWNlLnNhdmUobWUub3B0aW9ucy5mbGFnKS50aGVuKGZ1bmN0aW9uIChwYXRjaFJlc3BvbnNlKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuICQuZXh0ZW5kKHRydWUsIHt9LCBjcmVhdGVSZXNwb25zZSwgcGF0Y2hSZXNwb25zZSk7XG4gICAgICAgICAgICB9KTtcbiAgICAgICAgfSk7XG4gICAgfSxcblxuICAgIGdldFJ1bjogZnVuY3Rpb24gKHJ1blNlcnZpY2UsIHVzZXJTZXNzaW9uLCBydW5TZXNzaW9uLCBvcHRpb25zKSB7XG4gICAgICAgIHZhciBzZXNzaW9uRmlsdGVyID0gaW5qZWN0RmlsdGVyc0Zyb21TZXNzaW9uKHRoaXMub3B0aW9ucy5mbGFnLCB1c2VyU2Vzc2lvbik7XG4gICAgICAgIHZhciBydW5vcHRzID0gcnVuU2VydmljZS5nZXRDdXJyZW50Q29uZmlnKCk7XG4gICAgICAgIHZhciBmaWx0ZXIgPSAkLmV4dGVuZCh0cnVlLCB7IHRyYXNoZWQ6IGZhbHNlIH0sIHNlc3Npb25GaWx0ZXIsIHsgbW9kZWw6IHJ1bm9wdHMubW9kZWwgfSk7XG4gICAgICAgIHZhciBtZSA9IHRoaXM7XG4gICAgICAgIHJldHVybiBydW5TZXJ2aWNlLnF1ZXJ5KGZpbHRlciwgeyBcbiAgICAgICAgICAgIC8vIHN0YXJ0cmVjb3JkOiAwLCAgLy9UT0RPOiBVbmNvbW1lbnQgd2hlbiBFUElDRU5URVItMjU2OSBpcyBmaXhlZFxuICAgICAgICAgICAgLy8gZW5kcmVjb3JkOiAwLFxuICAgICAgICAgICAgc29ydDogJ2NyZWF0ZWQnLCBcbiAgICAgICAgICAgIGRpcmVjdGlvbjogJ2Rlc2MnXG4gICAgICAgIH0pLnRoZW4oZnVuY3Rpb24gKHJ1bnMpIHtcbiAgICAgICAgICAgIGlmICghcnVucy5sZW5ndGgpIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gbWUucmVzZXQocnVuU2VydmljZSwgdXNlclNlc3Npb24sIG9wdGlvbnMpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgcmV0dXJuIHJ1bnNbMF07XG4gICAgICAgIH0pO1xuICAgIH1cbn0pOyIsIi8qKlxuICogVGhlIGByZXVzZS1uZXZlcmAgc3RyYXRlZ3kgYWx3YXlzIGNyZWF0ZXMgYSBuZXcgcnVuIGZvciB0aGlzIGVuZCB1c2VyIGlycmVzcGVjdGl2ZSBvZiBjdXJyZW50IHN0YXRlLiBUaGlzIGlzIGVxdWl2YWxlbnQgdG8gY2FsbGluZyBgRi5zZXJ2aWNlLlJ1bi5jcmVhdGUoKWAgZnJvbSB0aGUgW1J1biBTZXJ2aWNlXSguLi9ydW4tYXBpLXNlcnZpY2UvKSBldmVyeSB0aW1lLiBcbiAqIFxuICogVGhpcyBzdHJhdGVneSBtZWFucyB0aGF0IGV2ZXJ5IHRpbWUgeW91ciBlbmQgdXNlcnMgcmVmcmVzaCB0aGVpciBicm93c2VycywgdGhleSBnZXQgYSBuZXcgcnVuLiBcbiAqIFxuICogVGhpcyBzdHJhdGVneSBjYW4gYmUgdXNlZnVsIGZvciBiYXNpYywgc2luZ2xlLXBhZ2UgcHJvamVjdHMuIFRoaXMgc3RyYXRlZ3kgaXMgYWxzbyB1c2VmdWwgZm9yIHByb3RvdHlwaW5nIG9yIHByb2plY3QgZGV2ZWxvcG1lbnQ6IGl0IGNyZWF0ZXMgYSBuZXcgcnVuIGVhY2ggdGltZSB5b3UgcmVmcmVzaCB0aGUgcGFnZSwgYW5kIHlvdSBjYW4gZWFzaWx5IGNoZWNrIHRoZSBvdXRwdXRzIG9mIHRoZSBtb2RlbC4gSG93ZXZlciwgdHlwaWNhbGx5IHlvdSB3aWxsIHVzZSBvbmUgb2YgdGhlIG90aGVyIHN0cmF0ZWdpZXMgZm9yIGEgcHJvZHVjdGlvbiBwcm9qZWN0LlxuICpcbiAqIEBuYW1lIGFsd2F5cy1uZXdcbiAqL1xuXG4ndXNlIHN0cmljdCc7XG5cbnZhciBjbGFzc0Zyb20gPSByZXF1aXJlKCcuLi8uLi91dGlsL2luaGVyaXQnKTtcbnZhciBDb25kaXRpb25hbFN0cmF0ZWd5ID0gcmVxdWlyZSgnLi9jb25kaXRpb25hbC1jcmVhdGlvbi1zdHJhdGVneScpO1xuXG52YXIgX19zdXBlciA9IENvbmRpdGlvbmFsU3RyYXRlZ3kucHJvdG90eXBlO1xuXG52YXIgU3RyYXRlZ3kgPSBjbGFzc0Zyb20oQ29uZGl0aW9uYWxTdHJhdGVneSwge1xuICAgIGNvbnN0cnVjdG9yOiBmdW5jdGlvbiAob3B0aW9ucykge1xuICAgICAgICBfX3N1cGVyLmNvbnN0cnVjdG9yLmNhbGwodGhpcywgdGhpcy5jcmVhdGVJZiwgb3B0aW9ucyk7XG4gICAgfSxcblxuICAgIGNyZWF0ZUlmOiBmdW5jdGlvbiAocnVuLCBoZWFkZXJzKSB7XG4gICAgICAgIC8vIGFsd2F5cyBjcmVhdGUgYSBuZXcgcnVuIVxuICAgICAgICByZXR1cm4gdHJ1ZTtcbiAgICB9XG59KTtcblxubW9kdWxlLmV4cG9ydHMgPSBTdHJhdGVneTtcbiIsIi8qKlxuICogVGhlIGByZXVzZS1wZXItc2Vzc2lvbmAgc3RyYXRlZ3kgY3JlYXRlcyBhIG5ldyBydW4gd2hlbiB0aGUgY3VycmVudCBvbmUgaXMgbm90IGluIHRoZSBicm93c2VyIGNvb2tpZS5cbiAqIFxuICogVXNpbmcgdGhpcyBzdHJhdGVneSBtZWFucyB0aGF0IHdoZW4gZW5kIHVzZXJzIG5hdmlnYXRlIGJldHdlZW4gcGFnZXMgaW4geW91ciBwcm9qZWN0LCBvciByZWZyZXNoIHRoZWlyIGJyb3dzZXJzLCB0aGV5IHdpbGwgc3RpbGwgYmUgd29ya2luZyB3aXRoIHRoZSBzYW1lIHJ1bi4gSG93ZXZlciwgaWYgZW5kIHVzZXJzIGxvZyBvdXQgYW5kIHJldHVybiB0byB0aGUgcHJvamVjdCBhdCBhIGxhdGVyIGRhdGUsIGEgbmV3IHJ1biBpcyBjcmVhdGVkLlxuICpcbiAqIFRoaXMgc3RyYXRlZ3kgaXMgdXNlZnVsIGlmIHlvdXIgcHJvamVjdCBpcyBzdHJ1Y3R1cmVkIHN1Y2ggdGhhdCBpbW1lZGlhdGVseSBhZnRlciBhIHJ1biBpcyBjcmVhdGVkLCB0aGUgbW9kZWwgaXMgZXhlY3V0ZWQgY29tcGxldGVseSAoZm9yIGV4YW1wbGUsIGEgVmVuc2ltIG1vZGVsIHRoYXQgaXMgc3RlcHBlZCB0byB0aGUgZW5kIGFzIHNvb24gYXMgaXQgaXMgY3JlYXRlZCkuIEluIGNvbnRyYXN0LCBpZiBlbmQgdXNlcnMgcGxheSB3aXRoIHlvdXIgcHJvamVjdCBmb3IgYW4gZXh0ZW5kZWQgcGVyaW9kIG9mIHRpbWUsIGV4ZWN1dGluZyB0aGUgbW9kZWwgc3RlcCBieSBzdGVwLCB0aGUgYHJldXNlLWFjcm9zcy1zZXNzaW9uc2Agc3RyYXRlZ3kgaXMgcHJvYmFibHkgYSBiZXR0ZXIgY2hvaWNlIChpdCBhbGxvd3MgZW5kIHVzZXJzIHRvIHBpY2sgdXAgd2hlcmUgdGhleSBsZWZ0IG9mZiwgcmF0aGVyIHRoYW4gc3RhcnRpbmcgZnJvbSBzY3JhdGNoIGVhY2ggYnJvd3NlciBzZXNzaW9uKS5cbiAqIFxuICogU3BlY2lmaWNhbGx5LCB0aGUgc3RyYXRlZ3kgaXM6XG4gKlxuICogKiBDaGVjayB0aGUgYHNlc3Npb25LZXlgIGNvb2tpZS5cbiAqICAgICAqIFRoaXMgY29va2llIGlzIHNldCBieSB0aGUgW1J1biBNYW5hZ2VyXSguLi9ydW4tbWFuYWdlci8pIGFuZCBjb25maWd1cmFibGUgdGhyb3VnaCBpdHMgb3B0aW9ucy4gXG4gKiAgICAgKiBJZiB0aGUgY29va2llIGV4aXN0cywgdXNlIHRoZSBydW4gaWQgc3RvcmVkIHRoZXJlLiBcbiAqICAgICAqIElmIHRoZSBjb29raWUgZG9lcyBub3QgZXhpc3QsIGNyZWF0ZSBhIG5ldyBydW4gZm9yIHRoaXMgZW5kIHVzZXIuXG4gKlxuICogQG5hbWUgbmV3LWlmLW1pc3NpbmdcbiAqL1xuXG4ndXNlIHN0cmljdCc7XG5cbnZhciBjbGFzc0Zyb20gPSByZXF1aXJlKCcuLi8uLi91dGlsL2luaGVyaXQnKTtcbnZhciBDb25kaXRpb25hbFN0cmF0ZWd5ID0gcmVxdWlyZSgnLi9jb25kaXRpb25hbC1jcmVhdGlvbi1zdHJhdGVneScpO1xuXG52YXIgX19zdXBlciA9IENvbmRpdGlvbmFsU3RyYXRlZ3kucHJvdG90eXBlO1xuXG4vKlxuKiAgY3JlYXRlIGEgbmV3IHJ1biBvbmx5IGlmIG5vdGhpbmcgaXMgc3RvcmVkIGluIHRoZSBjb29raWVcbiogIHRoaXMgaXMgdXNlZnVsIGZvciBiYXNlUnVucy5cbiovXG52YXIgU3RyYXRlZ3kgPSBjbGFzc0Zyb20oQ29uZGl0aW9uYWxTdHJhdGVneSwge1xuICAgIGNvbnN0cnVjdG9yOiBmdW5jdGlvbiAob3B0aW9ucykge1xuICAgICAgICBfX3N1cGVyLmNvbnN0cnVjdG9yLmNhbGwodGhpcywgdGhpcy5jcmVhdGVJZiwgb3B0aW9ucyk7XG4gICAgfSxcblxuICAgIGNyZWF0ZUlmOiBmdW5jdGlvbiAocnVuLCBoZWFkZXJzKSB7XG4gICAgICAgIC8vIGlmIHdlIGFyZSBoZXJlLCBpdCBtZWFucyB0aGF0IHRoZSBydW4gZXhpc3RzLi4uIHNvIHdlIGRvbid0IG5lZWQgYSBuZXcgb25lXG4gICAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9XG59KTtcblxubW9kdWxlLmV4cG9ydHMgPSBTdHJhdGVneTtcbiIsIi8qKlxuICogIyMgU2F2ZWQgUnVucyBNYW5hZ2VyXG4gKlxuICogVGhlIFNhdmVkIFJ1bnMgTWFuYWdlciBpcyBhIHNwZWNpZmljIHR5cGUgb2YgW1J1biBNYW5hZ2VyXSguLi8uLi9ydW4tbWFuYWdlci8pIHdoaWNoIHByb3ZpZGVzIGFjY2VzcyB0byBhIGxpc3Qgb2YgcnVucyAocmF0aGVyIHRoYW4ganVzdCBvbmUgcnVuKS4gSXQgYWxzbyBwcm92aWRlcyB1dGlsaXR5IGZ1bmN0aW9ucyBmb3IgZGVhbGluZyB3aXRoIG11bHRpcGxlIHJ1bnMgKGUuZy4gc2F2aW5nLCBkZWxldGluZywgbGlzdGluZykuXG4gKlxuICogQW4gaW5zdGFuY2Ugb2YgYSBTYXZlZCBSdW5zIE1hbmFnZXIgaXMgaW5jbHVkZWQgYXV0b21hdGljYWxseSBpbiBldmVyeSBpbnN0YW5jZSBvZiBhIFtTY2VuYXJpbyBNYW5hZ2VyXSguLi8pLCBhbmQgaXMgYWNjZXNzaWJsZSBmcm9tIHRoZSBTY2VuYXJpbyBNYW5hZ2VyIGF0IGAuc2F2ZWRSdW5zYC4gU2VlIFttb3JlIGluZm9ybWF0aW9uXSguLi8jcHJvcGVydGllcykgb24gdXNpbmcgYC5zYXZlZFJ1bnNgIHdpdGhpbiB0aGUgU2NlbmFyaW8gTWFuYWdlci5cbiAqXG4gKi9cbid1c2Ugc3RyaWN0JztcblxudmFyIFJ1blNlcnZpY2UgPSByZXF1aXJlKCcuLi9zZXJ2aWNlL3J1bi1hcGktc2VydmljZScpO1xudmFyIFNlc3Npb25NYW5hZ2VyID0gcmVxdWlyZSgnLi4vc3RvcmUvc2Vzc2lvbi1tYW5hZ2VyJyk7XG5cbnZhciBpbmplY3RGaWx0ZXJzRnJvbVNlc3Npb24gPSByZXF1aXJlKCcuL3N0cmF0ZWd5LXV0aWxzJykuaW5qZWN0RmlsdGVyc0Zyb21TZXNzaW9uO1xuXG52YXIgU2F2ZWRSdW5zTWFuYWdlciA9IGZ1bmN0aW9uIChjb25maWcpIHtcbiAgICB2YXIgZGVmYXVsdHMgPSB7XG4gICAgICAgIC8qKlxuICAgICAgICAgKiBJZiBzZXQsIHdpbGwgb25seSBwdWxsIHJ1bnMgZnJvbSBjdXJyZW50IGdyb3VwLiBEZWZhdWx0cyB0byBgdHJ1ZWAuXG4gICAgICAgICAqIEB0eXBlIHtCb29sZWFufVxuICAgICAgICAgKi9cbiAgICAgICAgc2NvcGVCeUdyb3VwOiB0cnVlLFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBJZiBzZXQsIHdpbGwgb25seSBwdWxsIHJ1bnMgZnJvbSBjdXJyZW50IHVzZXIuIERlZmF1bHRzIHRvIGB0cnVlYC5cbiAgICAgICAgICpcbiAgICAgICAgICogRm9yIG11bHRpcGxheWVyIHJ1biBjb21wYXJpc29uIHByb2plY3RzLCBzZXQgdGhpcyB0byBmYWxzZSBzbyB0aGF0IGFsbCBlbmQgdXNlcnMgaW4gYSBncm91cCBjYW4gdmlldyB0aGUgc2hhcmVkIHNldCBvZiBzYXZlZCBydW5zLlxuICAgICAgICAgKiBAdHlwZSB7Qm9vbGVhbn1cbiAgICAgICAgICovXG4gICAgICAgIHNjb3BlQnlVc2VyOiB0cnVlLFxuICAgIH07XG5cbiAgICB0aGlzLnNlc3Npb25NYW5hZ2VyID0gbmV3IFNlc3Npb25NYW5hZ2VyKCk7XG5cbiAgICB2YXIgb3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LCBkZWZhdWx0cywgY29uZmlnKTtcbiAgICBpZiAob3B0aW9ucy5ydW4pIHtcbiAgICAgICAgaWYgKG9wdGlvbnMucnVuIGluc3RhbmNlb2YgUnVuU2VydmljZSkge1xuICAgICAgICAgICAgdGhpcy5ydW5TZXJ2aWNlID0gb3B0aW9ucy5ydW47XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICB0aGlzLnJ1blNlcnZpY2UgPSBuZXcgUnVuU2VydmljZShvcHRpb25zLnJ1bik7XG4gICAgICAgIH1cbiAgICAgICAgdGhpcy5vcHRpb25zID0gb3B0aW9ucztcbiAgICB9IGVsc2Uge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ05vIHJ1biBvcHRpb25zIHBhc3NlZCB0byBTYXZlZFJ1bnNNYW5hZ2VyJyk7XG4gICAgfVxufTtcblxuU2F2ZWRSdW5zTWFuYWdlci5wcm90b3R5cGUgPSB7XG4gICAgLyoqXG4gICAgICogTWFya3MgYSBydW4gYXMgc2F2ZWQuIFxuICAgICAqXG4gICAgICogTm90ZSB0aGF0IHdoaWxlIGFueSBydW4gY2FuIGJlIHNhdmVkLCBvbmx5IHJ1bnMgd2hpY2ggYWxzbyBtYXRjaCB0aGUgY29uZmlndXJhdGlvbiBvcHRpb25zIGBzY29wZUJ5R3JvdXBgIGFuZCBgc2NvcGVCeVVzZXJgIGFyZSByZXR1cm5lZCBieSB0aGUgYGdldFJ1bnMoKWAgbWV0aG9kLlxuICAgICAqXG4gICAgICogKipFeGFtcGxlKipcbiAgICAgKlxuICAgICAqICAgICAgdmFyIHNtID0gbmV3IEYubWFuYWdlci5TY2VuYXJpb01hbmFnZXIoKTtcbiAgICAgKiAgICAgIHNtLnNhdmVkUnVucy5zYXZlKCcwMDAwMDE1YTRjZDE3MDAyMDljZDBhN2QyMDdmNDRiYWMyODknKTtcbiAgICAgKlxuICAgICAqIEBwYXJhbSAge1N0cmluZ3xSdW5TZXJ2aWNlfSBydW4gUnVuIHRvIHNhdmUuIFBhc3MgaW4gZWl0aGVyIHRoZSBydW4gaWQsIGFzIGEgc3RyaW5nLCBvciB0aGUgW1J1biBTZXJ2aWNlXSguLi8uLi9ydW4tYXBpLXNlcnZpY2UvKS5cbiAgICAgKiBAcGFyYW0gIHtPYmplY3R9IG90aGVyRmllbGRzIChPcHRpb25hbCkgQW55IG90aGVyIG1ldGEtZGF0YSB0byBzYXZlIHdpdGggdGhlIHJ1bi5cbiAgICAgKiBAcmV0dXJuIHtQcm9taXNlfVxuICAgICAqL1xuICAgIHNhdmU6IGZ1bmN0aW9uIChydW4sIG90aGVyRmllbGRzKSB7XG4gICAgICAgIHZhciBwYXJhbSA9ICQuZXh0ZW5kKHRydWUsIHt9LCBvdGhlckZpZWxkcywgeyBzYXZlZDogdHJ1ZSwgdHJhc2hlZDogZmFsc2UgfSk7XG4gICAgICAgIHJldHVybiB0aGlzLm1hcmsocnVuLCBwYXJhbSk7XG4gICAgfSxcbiAgICAvKipcbiAgICAgKiBNYXJrcyBhIHJ1biBhcyByZW1vdmVkOyB0aGUgaW52ZXJzZSBvZiBtYXJraW5nIGFzIHNhdmVkLlxuICAgICAqXG4gICAgICogKipFeGFtcGxlKipcbiAgICAgKlxuICAgICAqICAgICAgdmFyIHNtID0gbmV3IEYubWFuYWdlci5TY2VuYXJpb01hbmFnZXIoKTtcbiAgICAgKiAgICAgIHNtLnNhdmVkUnVucy5yZW1vdmUoJzAwMDAwMTVhNGNkMTcwMDIwOWNkMGE3ZDIwN2Y0NGJhYzI4OScpO1xuICAgICAqXG4gICAgICogQHBhcmFtICB7U3RyaW5nfFJ1blNlcnZpY2V9IHJ1biBSdW4gdG8gcmVtb3ZlLiBQYXNzIGluIGVpdGhlciB0aGUgcnVuIGlkLCBhcyBhIHN0cmluZywgb3IgdGhlIFtSdW4gU2VydmljZV0oLi4vLi4vcnVuLWFwaS1zZXJ2aWNlLykuXG4gICAgICogQHBhcmFtICB7T2JqZWN0fSBvdGhlckZpZWxkcyAoT3B0aW9uYWwpIGFueSBvdGhlciBtZXRhLWRhdGEgdG8gc2F2ZSB3aXRoIHRoZSBydW4uXG4gICAgICogQHJldHVybiB7UHJvbWlzZX1cbiAgICAgKi9cbiAgICByZW1vdmU6IGZ1bmN0aW9uIChydW4sIG90aGVyRmllbGRzKSB7XG4gICAgICAgIHZhciBwYXJhbSA9ICQuZXh0ZW5kKHRydWUsIHt9LCBvdGhlckZpZWxkcywgeyBzYXZlZDogZmFsc2UsIHRyYXNoZWQ6IHRydWUgfSk7XG4gICAgICAgIHJldHVybiB0aGlzLm1hcmsocnVuLCBwYXJhbSk7XG4gICAgfSxcblxuXG4gICAgLyoqXG4gICAgICogU2V0cyBhZGRpdGlvbmFsIGZpZWxkcyBvbiBhIHJ1bi4gVGhpcyBpcyBhIGNvbnZlbmllbmNlIG1ldGhvZCBmb3IgW1J1blNlcnZpY2Ujc2F2ZV0oLi4vLi4vcnVuLWFwaS1zZXJ2aWNlLyNzYXZlKS5cbiAgICAgKlxuICAgICAqICoqRXhhbXBsZSoqXG4gICAgICpcbiAgICAgKiAgICAgIHZhciBzbSA9IG5ldyBGLm1hbmFnZXIuU2NlbmFyaW9NYW5hZ2VyKCk7XG4gICAgICogICAgICBzbS5zYXZlZFJ1bnMubWFyaygnMDAwMDAxNWE0Y2QxNzAwMjA5Y2QwYTdkMjA3ZjQ0YmFjMjg5JywgXG4gICAgICogICAgICAgICAgeyAnbXlSdW5OYW1lJzogJ3NhbXBsZSBwb2xpY3kgZGVjaXNpb25zJyB9KTtcbiAgICAgKlxuICAgICAqIEBwYXJhbSAge1N0cmluZ3xSdW5TZXJ2aWNlfSBydW4gIFJ1biB0byBvcGVyYXRlIG9uLiBQYXNzIGluIGVpdGhlciB0aGUgcnVuIGlkLCBhcyBhIHN0cmluZywgb3IgdGhlIFtSdW4gU2VydmljZV0oLi4vLi4vcnVuLWFwaS1zZXJ2aWNlLykuXG4gICAgICogQHBhcmFtICB7T2JqZWN0fSB0b01hcmsgRmllbGRzIHRvIHNldCwgYXMgbmFtZSA6IHZhbHVlIHBhaXJzLlxuICAgICAqIEByZXR1cm4ge1Byb21pc2V9XG4gICAgICovXG4gICAgbWFyazogZnVuY3Rpb24gKHJ1biwgdG9NYXJrKSB7XG4gICAgICAgIHZhciBycztcbiAgICAgICAgdmFyIGV4aXN0aW5nT3B0aW9ucyA9IHRoaXMucnVuU2VydmljZS5nZXRDdXJyZW50Q29uZmlnKCk7XG4gICAgICAgIGlmIChydW4gaW5zdGFuY2VvZiBSdW5TZXJ2aWNlKSB7XG4gICAgICAgICAgICBycyA9IHJ1bjtcbiAgICAgICAgfSBlbHNlIGlmIChydW4gJiYgKHR5cGVvZiBydW4gPT09ICdzdHJpbmcnKSkge1xuICAgICAgICAgICAgcnMgPSBuZXcgUnVuU2VydmljZSgkLmV4dGVuZCh0cnVlLCB7fSwgZXhpc3RpbmdPcHRpb25zLCB7IGlkOiBydW4sIGF1dG9SZXN0b3JlOiBmYWxzZSB9KSk7XG4gICAgICAgIH0gZWxzZSBpZiAoJC5pc0FycmF5KHJ1bikpIHtcbiAgICAgICAgICAgIHZhciBtZSA9IHRoaXM7XG4gICAgICAgICAgICB2YXIgcHJvbXMgPSBydW4ubWFwKGZ1bmN0aW9uIChyKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIG1lLm1hcmsociwgdG9NYXJrKTtcbiAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgcmV0dXJuICQud2hlbi5hcHBseShudWxsLCBwcm9tcyk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ0ludmFsaWQgcnVuIG9iamVjdCBwcm92aWRlZCcpO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiBycy5zYXZlKHRvTWFyayk7XG4gICAgfSxcblxuICAgIC8qKlxuICAgICAqIFJldHVybnMgYSBsaXN0IG9mIHNhdmVkIHJ1bnMuXG4gICAgICpcbiAgICAgKiAqKkV4YW1wbGUqKlxuICAgICAqXG4gICAgICogICAgICB2YXIgc20gPSBuZXcgRi5tYW5hZ2VyLlNjZW5hcmlvTWFuYWdlcigpO1xuICAgICAqICAgICAgc20uc2F2ZWRSdW5zLmdldFJ1bnMoKS50aGVuKGZ1bmN0aW9uIChydW5zKSB7XG4gICAgICogICAgICAgICAgZm9yICh2YXIgaT0wOyBpPHJ1bnMubGVuZ3RoOyBpKyspIHtcbiAgICAgKiAgICAgICAgICAgICAgY29uc29sZS5sb2coJ3J1biBpZCBvZiBzYXZlZCBydW46ICcsIHJ1bnNbaV0uaWQpO1xuICAgICAqICAgICAgICAgIH1cbiAgICAgKiAgICAgIH0pO1xuICAgICAqXG4gICAgICogQHBhcmFtICB7QXJyYXl9IHZhcmlhYmxlcyAoT3B0aW9uYWwpIElmIHByb3ZpZGVkLCBpbiB0aGUgcmV0dXJuZWQgbGlzdCBvZiBydW5zLCBlYWNoIHJ1biB3aWxsIGhhdmUgYSBgLnZhcmlhYmxlc2AgcHJvcGVydHkgd2l0aCB0aGVzZSBzZXQuXG4gICAgICogQHBhcmFtICB7T2JqZWN0fSBmaWx0ZXIgICAgKE9wdGlvbmFsKSBBbnkgZmlsdGVycyB0byBhcHBseSB3aGlsZSBmZXRjaGluZyB0aGUgcnVuLiBTZWUgW1J1blNlcnZpY2UjZmlsdGVyXSguLi8uLi9ydW4tYXBpLXNlcnZpY2UvI2ZpbHRlcikgZm9yIGRldGFpbHMuXG4gICAgICogQHBhcmFtICB7T2JqZWN0fSBtb2RpZmllcnMgKE9wdGlvbmFsKSBVc2UgZm9yIHBhZ2luZy9zb3J0aW5nIGV0Yy4gU2VlIFtSdW5TZXJ2aWNlI2ZpbHRlcl0oLi4vLi4vcnVuLWFwaS1zZXJ2aWNlLyNmaWx0ZXIpIGZvciBkZXRhaWxzLlxuICAgICAqIEByZXR1cm4ge1Byb21pc2V9XG4gICAgICovXG4gICAgZ2V0UnVuczogZnVuY3Rpb24gKHZhcmlhYmxlcywgZmlsdGVyLCBtb2RpZmllcnMpIHtcbiAgICAgICAgdmFyIHNlc3Npb24gPSB0aGlzLnNlc3Npb25NYW5hZ2VyLmdldFNlc3Npb24odGhpcy5ydW5TZXJ2aWNlLmdldEN1cnJlbnRDb25maWcoKSk7XG5cbiAgICAgICAgdmFyIHJ1bm9wdHMgPSB0aGlzLnJ1blNlcnZpY2UuZ2V0Q3VycmVudENvbmZpZygpO1xuICAgICAgICB2YXIgc2NvcGVkRmlsdGVyID0gaW5qZWN0RmlsdGVyc0Zyb21TZXNzaW9uKCQuZXh0ZW5kKHRydWUsIHt9LCB7XG4gICAgICAgICAgICBzYXZlZDogdHJ1ZSwgXG4gICAgICAgICAgICB0cmFzaGVkOiBmYWxzZSxcbiAgICAgICAgICAgIG1vZGVsOiBydW5vcHRzLm1vZGVsLFxuICAgICAgICB9LCBmaWx0ZXIpLCBzZXNzaW9uLCB0aGlzLm9wdGlvbnMpO1xuXG4gICAgICAgIHZhciBvcE1vZGlmaWVycyA9ICQuZXh0ZW5kKHRydWUsIHt9LCB7XG4gICAgICAgICAgICBzb3J0OiAnY3JlYXRlZCcsXG4gICAgICAgICAgICBkaXJlY3Rpb246ICdhc2MnLFxuICAgICAgICB9LCBtb2RpZmllcnMpO1xuICAgICAgICBpZiAodmFyaWFibGVzKSB7XG4gICAgICAgICAgICBvcE1vZGlmaWVycy5pbmNsdWRlID0gW10uY29uY2F0KHZhcmlhYmxlcyk7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIHRoaXMucnVuU2VydmljZS5xdWVyeShzY29wZWRGaWx0ZXIsIG9wTW9kaWZpZXJzKTtcbiAgICB9XG59O1xubW9kdWxlLmV4cG9ydHMgPSBTYXZlZFJ1bnNNYW5hZ2VyO1xuIiwiLyoqXG4qICMjIFNjZW5hcmlvIE1hbmFnZXJcbipcbiogSW4gc29tZSBwcm9qZWN0cywgb2Z0ZW4gY2FsbGVkIFwidHVybi1ieS10dXJuXCIgcHJvamVjdHMsIGVuZCB1c2VycyBhZHZhbmNlIHRocm91Z2ggdGhlIHByb2plY3QncyBtb2RlbCBzdGVwLWJ5LXN0ZXAsIHdvcmtpbmcgZWl0aGVyIGluZGl2aWR1YWxseSBvciB0b2dldGhlciB0byBtYWtlIGRlY2lzaW9ucyBhdCBlYWNoIHN0ZXAuIFxuKlxuKiBJbiBvdGhlciBwcm9qZWN0cywgb2Z0ZW4gY2FsbGVkIFwicnVuIGNvbXBhcmlzb25cIiBvciBcInNjZW5hcmlvIGNvbXBhcmlzb25cIiBwcm9qZWN0cywgZW5kIHVzZXJzIHNldCBzb21lIGluaXRpYWwgZGVjaXNpb25zLCB0aGVuIHNpbXVsYXRlIHRoZSBtb2RlbCB0byBpdHMgZW5kLiBUeXBpY2FsbHkgZW5kIHVzZXJzIHdpbGwgZG8gdGhpcyBzZXZlcmFsIHRpbWVzLCBjcmVhdGluZyBzZXZlcmFsIHJ1bnMsIGFuZCBjb21wYXJlIHRoZSByZXN1bHRzLiBcbipcbiogVGhlIFNjZW5hcmlvIE1hbmFnZXIgbWFrZXMgaXQgZWFzeSB0byBjcmVhdGUgdGhlc2UgXCJydW4gY29tcGFyaXNvblwiIHByb2plY3RzLiBFYWNoIFNjZW5hcmlvIE1hbmFnZXIgYWxsb3dzIHlvdSB0byBjb21wYXJlIHRoZSByZXN1bHRzIG9mIHNldmVyYWwgcnVucy4gVGhpcyBpcyBtb3N0bHkgdXNlZnVsIGZvciB0aW1lLWJhc2VkIG1vZGVsczsgYnkgZGVmYXVsdCwgeW91IGNhbiB1c2UgdGhlIFNjZW5hcmlvIE1hbmFnZXIgd2l0aCBbVmVuc2ltXSguLi8uLi8uLi9tb2RlbF9jb2RlL3ZlbnNpbS8pLCBbUG93ZXJzaW1dKC4uLy4uLy4uL21vZGVsX2NvZGUvcG93ZXJzaW0vKSwgYW5kIFtTaW1MYW5nXSguLi8uLi8uLi9tb2RlbF9jb2RlL2ZvcmlvX3NpbWxhbmcpLiAoWW91IGNhbiB1c2UgdGhlIFNjZW5hcmlvIE1hbmFnZXIgd2l0aCBvdGhlciBsYW5ndWFnZXMgYXMgd2VsbCwgYnkgdXNpbmcgdGhlIFNjZW5hcmlvIE1hbmFnZXIncyBbY29uZmlndXJhdGlvbiBvcHRpb25zXSgjY29uZmlndXJhdGlvbi1vcHRpb25zKSB0byBjaGFuZ2UgdGhlIGBhZHZhbmNlT3BlcmF0aW9uYC4pXG4qXG4qIFRoZSBTY2VuYXJpbyBNYW5hZ2VyIGNhbiBiZSB0aG91Z2h0IG9mIGFzIGEgY29sbGVjdGlvbiBvZiBbUnVuIE1hbmFnZXJzXSguLi9ydW4tbWFuYWdlci8pIHdpdGggcHJlLWNvbmZpZ3VyZWQgW3N0cmF0ZWdpZXNdKC4uL3N0cmF0ZWdpZXMvKS4gSnVzdCBhcyB0aGUgUnVuIE1hbmFnZXIgcHJvdmlkZXMgdXNlIGNhc2UgLWJhc2VkIGFic3RyYWN0aW9ucyBhbmQgdXRpbGl0aWVzIGZvciBtYW5hZ2luZyB0aGUgW1J1biBTZXJ2aWNlXSguLi9ydW4tYXBpLXNlcnZpY2UvKSwgdGhlIFNjZW5hcmlvIE1hbmFnZXIgZG9lcyB0aGUgc2FtZSBmb3IgdGhlIFJ1biBNYW5hZ2VyLlxuKlxuKiBUaGVyZSBhcmUgdHlwaWNhbGx5IHRocmVlIGNvbXBvbmVudHMgdG8gYnVpbGRpbmcgYSBydW4gY29tcGFyaXNvbjpcbipcbiogKiBBIGBjdXJyZW50YCBydW4gaW4gd2hpY2ggdG8gbWFrZSBkZWNpc2lvbnM7IHRoaXMgaXMgZGVmaW5lZCBhcyBhIHJ1biB0aGF0IGhhc24ndCBiZWVuIGFkdmFuY2VkIHlldCwgYW5kIHNvIGNhbiBiZSB1c2VkIHRvIHNldCBpbml0aWFsIGRlY2lzaW9ucy4gVGhlIGN1cnJlbnQgcnVuIG1haW50YWlucyBzdGF0ZSBhY3Jvc3MgZGlmZmVyZW50IHNlc3Npb25zLlxuKiAqIEEgbGlzdCBvZiBgc2F2ZWRgIHJ1bnMsIHRoYXQgaXMsIGFsbCBydW5zIHRoYXQgeW91IHdhbnQgdG8gdXNlIGZvciBjb21wYXJpc29ucy5cbiogKiBBIGBiYXNlbGluZWAgcnVuIHRvIGNvbXBhcmUgYWdhaW5zdDsgdGhpcyBpcyBkZWZpbmVkIGFzIGEgcnVuIFwiYWR2YW5jZWQgdG8gdGhlIGVuZFwiIG9mIHlvdXIgbW9kZWwgdXNpbmcganVzdCB0aGUgbW9kZWwgZGVmYXVsdHMuIENvbXBhcmluZyBhZ2FpbnN0IGEgYmFzZWxpbmUgcnVuIGlzIG9wdGlvbmFsOyB5b3UgY2FuIFtjb25maWd1cmVdKCNjb25maWd1cmF0aW9uLW9wdGlvbnMpIHRoZSBTY2VuYXJpbyBNYW5hZ2VyIHRvIG5vdCBpbmNsdWRlIG9uZS5cbipcbiogVG8gc2F0aXNmeSB0aGVzZSBuZWVkcyBhIFNjZW5hcmlvIE1hbmFnZXIgaW5zdGFuY2UgaGFzIHRocmVlIFJ1biBNYW5hZ2VyczogW2Jhc2VsaW5lXSguL2Jhc2VsaW5lLyksIFtjdXJyZW50XSguL2N1cnJlbnQvKSwgYW5kIFtzYXZlZFJ1bnNdKC4vc2F2ZWQvKS5cbipcbiogIyMjIFVzaW5nIHRoZSBTY2VuYXJpbyBNYW5hZ2VyIHRvIGNyZWF0ZSBhIHJ1biBjb21wYXJpc29uIHByb2plY3RcbipcbiogVG8gdXNlIHRoZSBTY2VuYXJpbyBNYW5hZ2VyLCBpbnN0YW50aWF0ZSBpdCwgdGhlbiBhY2Nlc3MgaXRzIFJ1biBNYW5hZ2VycyBhcyBuZWVkZWQgdG8gY3JlYXRlIHlvdXIgcHJvamVjdCdzIHVzZXIgaW50ZXJmYWNlOlxuKlxuKiAqKkV4YW1wbGUqKlxuKlxuKiAgICAgICB2YXIgc20gPSBuZXcgRi5tYW5hZ2VyLlNjZW5hcmlvTWFuYWdlcih7XG4qICAgICAgICAgICBydW46IHtcbiogICAgICAgICAgICAgICBtb2RlbDogJ215bW9kZWwudm1mJ1xuKiAgICAgICAgICAgfVxuKiAgICAgICB9KTtcbipcbiogICAgICAgLy8gVGhlIGN1cnJlbnQgaXMgYW4gaW5zdGFuY2Ugb2YgYSBSdW4gTWFuYWdlcixcbiogICAgICAgLy8gd2l0aCBhIHN0cmF0ZWd5IHdoaWNoIHBpY2tzIHVwIHRoZSBtb3N0IHJlY2VudCB1bnNhdmVkIHJ1bi5cbiogICAgICAgLy8gSXQgaXMgdHlwaWNhbGx5IHVzZWQgdG8gc3RvcmUgdGhlIGRlY2lzaW9ucyBiZWluZyBtYWRlIGJ5IHRoZSBlbmQgdXNlci4gXG4qICAgICAgIHZhciBjdXJyZW50Uk0gPSBzbS5jdXJyZW50O1xuKlxuKiAgICAgICAvLyBUaGUgUnVuIE1hbmFnZXIgb3BlcmF0aW9uLCB3aGljaCByZXRyaWV2ZXMgdGhlIGN1cnJlbnQgcnVuLlxuKiAgICAgICBzbS5jdXJyZW50LmdldFJ1bigpO1xuKiAgICAgICAvLyBUaGUgUnVuIE1hbmFnZXIgb3BlcmF0aW9uLCB3aGljaCByZXNldHMgdGhlIGRlY2lzaW9ucyBtYWRlIG9uIHRoZSBjdXJyZW50IHJ1bi5cbiogICAgICAgc20uY3VycmVudC5yZXNldCgpO1xuKiAgICAgICAvLyBBIHNwZWNpYWwgbWV0aG9kIG9uIHRoZSBjdXJyZW50IHJ1bixcbiogICAgICAgLy8gd2hpY2ggY2xvbmVzIHRoZSBjdXJyZW50IHJ1biwgdGhlbiBhZHZhbmNlcyBhbmQgc2F2ZXMgdGhpcyBjbG9uZVxuKiAgICAgICAvLyAoaXQgYmVjb21lcyBwYXJ0IG9mIHRoZSBzYXZlZCBydW5zIGxpc3QpLlxuKiAgICAgICAvLyBUaGUgY3VycmVudCBydW4gaXMgdW5jaGFuZ2VkIGFuZCBjYW4gY29udGludWUgdG8gYmUgdXNlZFxuKiAgICAgICAvLyB0byBzdG9yZSBkZWNpc2lvbnMgYmVpbmcgbWFkZSBieSB0aGUgZW5kIHVzZXIuXG4qICAgICAgIHNtLmN1cnJlbnQuc2F2ZUFuZEFkdmFuY2UoKTtcbipcbiogICAgICAgLy8gVGhlIHNhdmVkUnVucyBpcyBhbiBpbnN0YW5jZSBvZiBhIFNhdmVkIFJ1bnMgTWFuYWdlciBcbiogICAgICAgLy8gKGl0c2VsZiBhIHZhcmlhbnQgb2YgYSBSdW4gTWFuYWdlcikuXG4qICAgICAgIC8vIEl0IGlzIHR5cGljYWxseSBkaXNwbGF5ZWQgaW4gdGhlIHByb2plY3QncyBVSSBhcyBwYXJ0IG9mIGEgcnVuIGNvbXBhcmlzb24gdGFibGUgb3IgY2hhcnQuXG4qICAgICAgIHZhciBzYXZlZFJNID0gc20uc2F2ZWRSdW5zO1xuKiAgICAgICAvLyBNYXJrIGEgcnVuIGFzIHNhdmVkLCBhZGRpbmcgaXQgdG8gdGhlIHNldCBvZiBzYXZlZCBydW5zLlxuKiAgICAgICBzbS5zYXZlZFJ1bnMuc2F2ZShydW4pO1xuKiAgICAgICAvLyBNYXJrIGEgcnVuIGFzIHJlbW92ZWQsIHJlbW92aW5nIGl0IGZyb20gdGhlIHNldCBvZiBzYXZlZCBydW5zLlxuKiAgICAgICBzbS5zYXZlZFJ1bnMucmVtb3ZlKHJ1bik7XG4qICAgICAgIC8vIExpc3QgdGhlIHNhdmVkIHJ1bnMsIG9wdGlvbmFsbHkgaW5jbHVkaW5nIHNvbWUgc3BlY2lmaWMgbW9kZWwgdmFyaWFibGVzIGZvciBlYWNoLlxuKiAgICAgICBzbS5zYXZlZFJ1bnMuZ2V0UnVucygpO1xuKlxuKiAgICAgICAvLyBUaGUgYmFzZWxpbmUgaXMgYW4gaW5zdGFuY2Ugb2YgYSBSdW4gTWFuYWdlcixcbiogICAgICAgLy8gd2l0aCBhIHN0cmF0ZWd5IHdoaWNoIGxvY2F0ZXMgdGhlIG1vc3QgcmVjZW50IGJhc2VsaW5lIHJ1blxuKiAgICAgICAvLyAodGhhdCBpcywgZmxhZ2dlZCBhcyBgc2F2ZWRgIGFuZCBub3QgYHRyYXNoZWRgKSwgb3IgY3JlYXRlcyBhIG5ldyBvbmUuXG4qICAgICAgIC8vIEl0IGlzIHR5cGljYWxseSBkaXNwbGF5ZWQgaW4gdGhlIHByb2plY3QncyBVSSBhcyBwYXJ0IG9mIGEgcnVuIGNvbXBhcmlzb24gdGFibGUgb3IgY2hhcnQuXG4qICAgICAgIHZhciBiYXNlbGluZVJNID0gc20uYmFzZWxpbmU7XG4qXG4qICAgICAgIC8vIFRoZSBSdW4gTWFuYWdlciBvcGVyYXRpb24sIHdoaWNoIHJldHJpZXZlcyB0aGUgYmFzZWxpbmUgcnVuLlxuKiAgICAgICBzbS5iYXNlbGluZS5nZXRSdW4oKTtcbiogICAgICAgLy8gVGhlIFJ1biBNYW5hZ2VyIG9wZXJhdGlvbiwgd2hpY2ggcmVzZXRzIHRoZSBiYXNlbGluZSBydW4uXG4qICAgICAgIC8vIFVzZWZ1bCBpZiB0aGUgbW9kZWwgaGFzIGNoYW5nZWQgc2luY2UgdGhlIGJhc2VsaW5lIHJ1biB3YXMgY3JlYXRlZC5cbiogICAgICAgc20uYmFzZWxpbmUucmVzZXQoKTsgXG4qL1xuXG4ndXNlIHN0cmljdCc7XG5cbi8vIFNlZSBpbnRlZ3JhdGlvbi10ZXN0LXNjZW5hcmlvLW1hbmFnZXIgZm9yIHVzYWdlIGV4YW1wbGVzXG52YXIgUnVuTWFuYWdlciA9IHJlcXVpcmUoJy4vcnVuLW1hbmFnZXInKTtcbnZhciBTYXZlZFJ1bnNNYW5hZ2VyID0gcmVxdWlyZSgnLi9zYXZlZC1ydW5zLW1hbmFnZXInKTtcbnZhciBzdHJhdGVneVV0aWxzID0gcmVxdWlyZSgnLi9zdHJhdGVneS11dGlscycpO1xudmFyIHJ1dGlsID0gcmVxdWlyZSgnLi4vdXRpbC9ydW4tdXRpbCcpO1xuXG52YXIgTm9uZVN0cmF0ZWd5ID0gcmVxdWlyZSgnLi9ydW4tc3RyYXRlZ2llcy9ub25lLXN0cmF0ZWd5Jyk7XG5cbnZhciBTdGF0ZVNlcnZpY2UgPSByZXF1aXJlKCcuLi9zZXJ2aWNlL3N0YXRlLWFwaS1hZGFwdGVyJyk7XG52YXIgUnVuU2VydmljZSA9IHJlcXVpcmUoJy4uL3NlcnZpY2UvcnVuLWFwaS1zZXJ2aWNlJyk7XG5cbnZhciBCYXNlbGluZVN0cmF0ZWd5ID0gcmVxdWlyZSgnLi9zY2VuYXJpby1zdHJhdGVnaWVzL2Jhc2VsaW5lLXN0cmF0ZWd5Jyk7XG52YXIgTGFzdFVuc2F2ZWRTdHJhdGVneSA9IHJlcXVpcmUoJy4vc2NlbmFyaW8tc3RyYXRlZ2llcy9yZXVzZS1sYXN0LXVuc2F2ZWQnKTtcblxudmFyIGRlZmF1bHRzID0ge1xuICAgIC8qKlxuICAgICAqIE9wZXJhdGlvbnMgdG8gcGVyZm9ybSBvbiBlYWNoIHJ1biB0byBpbmRpY2F0ZSB0aGF0IHRoZSBydW4gaXMgY29tcGxldGUuIE9wZXJhdGlvbnMgYXJlIGV4ZWN1dGVkIFtzZXJpYWxseV0oLi4vcnVuLWFwaS1zZXJ2aWNlLyNzZXJpYWwpLiBEZWZhdWx0cyB0byBjYWxsaW5nIHRoZSBtb2RlbCBvcGVyYXRpb24gYHN0ZXBUbygnZW5kJylgLCB3aGljaCBhZHZhbmNlcyBWZW5zaW0sIFBvd2Vyc2ltLCBhbmQgU2ltTGFuZyBtb2RlbHMgdG8gdGhlIGVuZC4gXG4gICAgICogQHR5cGUge0FycmF5fVxuICAgICAqL1xuICAgIGFkdmFuY2VPcGVyYXRpb246IFt7IG5hbWU6ICdzdGVwVG8nLCBwYXJhbXM6IFsnZW5kJ10gfV0sXG5cbiAgICAvKipcbiAgICAgKiBBZGRpdGlvbmFsIG9wdGlvbnMgdG8gcGFzcyB0aHJvdWdoIHRvIHJ1biBjcmVhdGlvbiAoZm9yIGUuZy4sIGBmaWxlc2AsIGV0Yy4pLiBEZWZhdWx0cyB0byBlbXB0eSBvYmplY3QuXG4gICAgICogQHR5cGUge09iamVjdH1cbiAgICAgKi9cbiAgICBydW46IHt9LFxuXG4gICAgLyoqXG4gICAgICogV2hldGhlciBvciBub3QgdG8gaW5jbHVkZSBhIGJhc2VsaW5lIHJ1biBpbiB0aGlzIFNjZW5hcmlvIE1hbmFnZXIuIERlZmF1bHRzIHRvIGB0cnVlYC5cbiAgICAgKiBAdHlwZSB7Qm9vbGVhbn1cbiAgICAgKi9cbiAgICBpbmNsdWRlQmFzZUxpbmU6IHRydWUsXG5cbiAgICAvKipcbiAgICAgKiBBZGRpdGlvbmFsIGNvbmZpZ3VyYXRpb24gZm9yIHRoZSBgYmFzZWxpbmVgIHJ1bi4gXG4gICAgICpcbiAgICAgKiAqIGBiYXNlbGluZS5ydW5OYW1lYDogTmFtZSBvZiB0aGUgYmFzZWxpbmUgcnVuLiBEZWZhdWx0cyB0byAnQmFzZWxpbmUnLiBcbiAgICAgKiAqIGBiYXNlbGluZS5ydW5gOiBBZGRpdGlvbmFsIG9wdGlvbnMgdG8gcGFzcyB0aHJvdWdoIHRvIHJ1biBjcmVhdGlvbiwgc3BlY2lmaWNhbGx5IGZvciB0aGUgYmFzZWxpbmUgcnVuLiBUaGVzZSB3aWxsIG92ZXJyaWRlIGFueSBvcHRpb25zIHByb3ZpZGVkIHVuZGVyIGBydW5gLiBEZWZhdWx0cyB0byBlbXB0eSBvYmplY3QuIFxuICAgICAqIEB0eXBlIHtPYmplY3R9XG4gICAgICovXG4gICAgYmFzZWxpbmU6IHtcbiAgICAgICAgcnVuTmFtZTogJ0Jhc2VsaW5lJyxcbiAgICAgICAgcnVuOiB7fVxuICAgIH0sXG5cbiAgICAvKipcbiAgICAgKiBBZGRpdGlvbmFsIGNvbmZpZ3VyYXRpb24gZm9yIHRoZSBgY3VycmVudGAgcnVuLiBcbiAgICAgKlxuICAgICAqICogYGN1cnJlbnQucnVuYDogQWRkaXRpb25hbCBvcHRpb25zIHRvIHBhc3MgdGhyb3VnaCB0byBydW4gY3JlYXRpb24sIHNwZWNpZmljYWxseSBmb3IgdGhlIGN1cnJlbnQgcnVuLiBUaGVzZSB3aWxsIG92ZXJyaWRlIGFueSBvcHRpb25zIHByb3ZpZGVkIHVuZGVyIGBydW5gLiBEZWZhdWx0cyB0byBlbXB0eSBvYmplY3QuXG4gICAgICogQHR5cGUge09iamVjdH1cbiAgICAgKi9cbiAgICBjdXJyZW50OiB7XG4gICAgICAgIHJ1bjoge31cbiAgICB9LFxuXG4gICAgLyoqXG4gICAgICogT3B0aW9ucyB0byBwYXNzIHRocm91Z2ggdG8gdGhlIGBzYXZlZFJ1bnNgIGxpc3QuIFNlZSB0aGUgW1NhdmVkIFJ1bnMgTWFuYWdlcl0oLi9zYXZlZC8pIGZvciBjb21wbGV0ZSBkZXNjcmlwdGlvbiBvZiBhdmFpbGFibGUgb3B0aW9ucy4gRGVmYXVsdHMgdG8gZW1wdHkgb2JqZWN0LlxuICAgICAqIEB0eXBlIHtPYmplY3R9XG4gICAgICovXG4gICAgc2F2ZWRSdW5zOiB7fVxufTtcblxuZnVuY3Rpb24gY29va2llTmFtZUZyb21PcHRpb25zKHByZWZpeCwgY29uZmlnKSB7XG4gICAgdmFyIGtleSA9IFsnYWNjb3VudCcsICdwcm9qZWN0JywgJ21vZGVsJ10ucmVkdWNlKGZ1bmN0aW9uIChhY2N1bSwga2V5KSB7XG4gICAgICAgIHJldHVybiBjb25maWdba2V5XSA/IGFjY3VtICsgJy0nICsgY29uZmlnW2tleV0gOiBhY2N1bTsgXG4gICAgfSwgcHJlZml4KTtcbiAgICByZXR1cm4ga2V5O1xufVxuXG5mdW5jdGlvbiBTY2VuYXJpb01hbmFnZXIoY29uZmlnKSB7XG4gICAgdmFyIG9wdHMgPSAkLmV4dGVuZCh0cnVlLCB7fSwgZGVmYXVsdHMsIGNvbmZpZyk7XG4gICAgaWYgKGNvbmZpZyAmJiBjb25maWcuYWR2YW5jZU9wZXJhdGlvbikge1xuICAgICAgICBvcHRzLmFkdmFuY2VPcGVyYXRpb24gPSBjb25maWcuYWR2YW5jZU9wZXJhdGlvbjsgLy9qcXVlcnkuZXh0ZW5kIGRvZXMgYSBwb29yIGpvYiB0cnlpbmcgdG8gbWVyZ2UgYXJyYXlzXG4gICAgfVxuXG4gICAgdmFyIEJhc2VsaW5lU3RyYXRlZ3lUb1VzZSA9IG9wdHMuaW5jbHVkZUJhc2VMaW5lID8gQmFzZWxpbmVTdHJhdGVneSA6IE5vbmVTdHJhdGVneTtcbiAgICAvKipcbiAgICAgKiBBIFtSdW4gTWFuYWdlcl0oLi4vcnVuLW1hbmFnZXIvKSBpbnN0YW5jZSBjb250YWluaW5nIGEgJ2Jhc2VsaW5lJyBydW4gdG8gY29tcGFyZSBhZ2FpbnN0OyB0aGlzIGlzIGRlZmluZWQgYXMgYSBydW4gXCJhZHZhbmNlZCB0byB0aGUgZW5kXCIgb2YgeW91ciBtb2RlbCB1c2luZyBqdXN0IHRoZSBtb2RlbCBkZWZhdWx0cy4gQnkgZGVmYXVsdCB0aGUgXCJhZHZhbmNlXCIgb3BlcmF0aW9uIGlzIGFzc3VtZWQgdG8gYmUgYHN0ZXBUbzogZW5kYCwgd2hpY2ggd29ya3MgZm9yIHRpbWUtYmFzZWQgbW9kZWxzIGluIFtWZW5zaW1dKC4uLy4uLy4uL21vZGVsX2NvZGUvdmVuc2ltLyksIFtQb3dlcnNpbV0oLi4vLi4vLi4vbW9kZWxfY29kZS9wb3dlcnNpbS8pLCBhbmQgW1NpbUxhbmddKC4uLy4uLy4uL21vZGVsX2NvZGUvZm9yaW9fc2ltbGFuZykuIElmIHlvdSdyZSB1c2luZyBhIGRpZmZlcmVudCBsYW5ndWFnZSwgb3IgbmVlZCB0byBjaGFuZ2UgdGhpcywganVzdCBwYXNzIGluIGEgZGlmZmVyZW50IGBhZHZhbmNlT3BlcmF0aW9uYCBvcHRpb24gd2hpbGUgY3JlYXRpbmcgdGhlIFNjZW5hcmlvIE1hbmFnZXIuIFRoZSBiYXNlbGluZSBydW4gaXMgdHlwaWNhbGx5IGRpc3BsYXllZCBpbiB0aGUgcHJvamVjdCdzIFVJIGFzIHBhcnQgb2YgYSBydW4gY29tcGFyaXNvbiB0YWJsZSBvciBjaGFydC5cbiAgICAgKiBAcmV0dXJuIHtSdW5NYW5hZ2VyfVxuICAgICAqL1xuICAgIHRoaXMuYmFzZWxpbmUgPSBuZXcgUnVuTWFuYWdlcih7XG4gICAgICAgIHN0cmF0ZWd5OiBCYXNlbGluZVN0cmF0ZWd5VG9Vc2UsXG4gICAgICAgIHNlc3Npb25LZXk6IGNvb2tpZU5hbWVGcm9tT3B0aW9ucy5iaW5kKG51bGwsICdzbS1iYXNlbGluZS1ydW4nKSxcbiAgICAgICAgcnVuOiBzdHJhdGVneVV0aWxzLm1lcmdlUnVuT3B0aW9ucyhvcHRzLnJ1biwgb3B0cy5iYXNlbGluZS5ydW4pLFxuICAgICAgICBzdHJhdGVneU9wdGlvbnM6IHtcbiAgICAgICAgICAgIGJhc2VsaW5lTmFtZTogb3B0cy5iYXNlbGluZS5ydW5OYW1lLFxuICAgICAgICAgICAgaW5pdE9wZXJhdGlvbjogb3B0cy5hZHZhbmNlT3BlcmF0aW9uXG4gICAgICAgIH1cbiAgICB9KTtcblxuICAgIC8qKlxuICAgICAqIEEgW1NhdmVkUnVuc01hbmFnZXJdKC4uL3NhdmVkLXJ1bnMtbWFuYWdlci8pIGluc3RhbmNlIGNvbnRhaW5pbmcgYSBsaXN0IG9mIHNhdmVkIHJ1bnMsIHRoYXQgaXMsIGFsbCBydW5zIHRoYXQgeW91IHdhbnQgdG8gdXNlIGZvciBjb21wYXJpc29ucy4gVGhlIHNhdmVkIHJ1bnMgYXJlIHR5cGljYWxseSBkaXNwbGF5ZWQgaW4gdGhlIHByb2plY3QncyBVSSBhcyBwYXJ0IG9mIGEgcnVuIGNvbXBhcmlzb24gdGFibGUgb3IgY2hhcnQuXG4gICAgICogQHJldHVybiB7U2F2ZWRSdW5zTWFuYWdlcn1cbiAgICAgKi9cbiAgICB0aGlzLnNhdmVkUnVucyA9IG5ldyBTYXZlZFJ1bnNNYW5hZ2VyKCQuZXh0ZW5kKHRydWUsIHt9LCB7XG4gICAgICAgIHJ1bjogb3B0cy5ydW4sXG4gICAgfSwgb3B0cy5zYXZlZFJ1bnMpKTtcblxuICAgIHZhciBvcmlnR2V0UnVucyA9IHRoaXMuc2F2ZWRSdW5zLmdldFJ1bnM7XG4gICAgdmFyIG1lID0gdGhpcztcbiAgICB0aGlzLnNhdmVkUnVucy5nZXRSdW5zID0gZnVuY3Rpb24gKCkge1xuICAgICAgICB2YXIgYXJncyA9IEFycmF5LmFwcGx5KG51bGwsIGFyZ3VtZW50cyk7XG4gICAgICAgIHJldHVybiBtZS5iYXNlbGluZS5nZXRSdW4oKS50aGVuKGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIHJldHVybiBvcmlnR2V0UnVucy5hcHBseShtZS5zYXZlZFJ1bnMsIGFyZ3MpO1xuICAgICAgICB9KTtcbiAgICB9O1xuXG4gICAgLyoqXG4gICAgICogQSBbUnVuIE1hbmFnZXJdKC4uL3J1bi1tYW5hZ2VyLykgaW5zdGFuY2UgY29udGFpbmluZyBhICdjdXJyZW50JyBydW47IHRoaXMgaXMgZGVmaW5lZCBhcyBhIHJ1biB0aGF0IGhhc24ndCBiZWVuIGFkdmFuY2VkIHlldCwgYW5kIHNvIGNhbiBiZSB1c2VkIHRvIHNldCBpbml0aWFsIGRlY2lzaW9ucy4gVGhlIGN1cnJlbnQgcnVuIGlzIHR5cGljYWxseSB1c2VkIHRvIHN0b3JlIHRoZSBkZWNpc2lvbnMgYmVpbmcgbWFkZSBieSB0aGUgZW5kIHVzZXIuXG4gICAgICogQHJldHVybiB7UnVuTWFuYWdlcn1cbiAgICAgKi9cbiAgICB0aGlzLmN1cnJlbnQgPSBuZXcgUnVuTWFuYWdlcih7XG4gICAgICAgIHN0cmF0ZWd5OiBMYXN0VW5zYXZlZFN0cmF0ZWd5LFxuICAgICAgICBzZXNzaW9uS2V5OiBjb29raWVOYW1lRnJvbU9wdGlvbnMuYmluZChudWxsLCAnc20tY3VycmVudC1ydW4nKSxcbiAgICAgICAgcnVuOiBzdHJhdGVneVV0aWxzLm1lcmdlUnVuT3B0aW9ucyhvcHRzLnJ1biwgb3B0cy5jdXJyZW50LnJ1bilcbiAgICB9KTtcblxuICAgIC8qKlxuICAgICAqIENsb25lcyB0aGUgY3VycmVudCBydW4sIGFkdmFuY2VzIHRoaXMgY2xvbmUgYnkgY2FsbGluZyB0aGUgYGFkdmFuY2VPcGVyYXRpb25gLCBhbmQgc2F2ZXMgdGhlIGNsb25lZCBydW4gKGl0IGJlY29tZXMgcGFydCBvZiB0aGUgYHNhdmVkUnVuc2AgbGlzdCkuIEFkZGl0aW9uYWxseSwgYWRkcyBhbnkgcHJvdmlkZWQgbWV0YWRhdGEgdG8gdGhlIGNsb25lZCBydW47IHR5cGljYWxseSB1c2VkIGZvciBuYW1pbmcgdGhlIHJ1bi4gVGhlIGN1cnJlbnQgcnVuIGlzIHVuY2hhbmdlZCBhbmQgY2FuIGNvbnRpbnVlIHRvIGJlIHVzZWQgdG8gc3RvcmUgZGVjaXNpb25zIGJlaW5nIG1hZGUgYnkgdGhlIGVuZCB1c2VyLlxuICAgICAqXG4gICAgICogQXZhaWxhYmxlIG9ubHkgZm9yIHRoZSBTY2VuYXJpbyBNYW5hZ2VyJ3MgYGN1cnJlbnRgIHByb3BlcnR5IChSdW4gTWFuYWdlcikuIFxuICAgICAqXG4gICAgICogKipFeGFtcGxlKipcbiAgICAgKlxuICAgICAqICAgICAgdmFyIHNtID0gbmV3IEYubWFuYWdlci5TY2VuYXJpb01hbmFnZXIoKTtcbiAgICAgKiAgICAgIHNtLmN1cnJlbnQuc2F2ZUFuZEFkdmFuY2UoeydteVJ1bk5hbWUnOiAnc2FtcGxlIHBvbGljeSBkZWNpc2lvbnMnfSk7XG4gICAgICpcbiAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAqIEBwYXJhbSAge09iamVjdH0gbWV0YWRhdGEgICBNZXRhZGF0YSB0byBzYXZlLCBmb3IgZXhhbXBsZSwgdGhlIHJ1biBuYW1lLlxuICAgICAqIEByZXR1cm4ge1Byb21pc2V9XG4gICAgICovXG4gICAgdGhpcy5jdXJyZW50LnNhdmVBbmRBZHZhbmNlID0gZnVuY3Rpb24gKG1ldGFkYXRhKSB7XG4gICAgICAgIGZ1bmN0aW9uIGNsb25lKHJ1bikge1xuICAgICAgICAgICAgdmFyIHNhID0gbmV3IFN0YXRlU2VydmljZSgpO1xuICAgICAgICAgICAgdmFyIGFkdmFuY2VPcG5zID0gcnV0aWwubm9ybWFsaXplT3BlcmF0aW9ucyhvcHRzLmFkdmFuY2VPcGVyYXRpb24pOyBcbiAgICAgICAgICAgIC8vcnVuIGknbSBjbG9uaW5nIHNob3VsZG4ndCBoYXZlIHRoZSBhZHZhbmNlIG9wZXJhdGlvbnMgdGhlcmUgYnkgZGVmYXVsdCwgYnV0IGp1c3QgaW4gY2FzZVxuICAgICAgICAgICAgcmV0dXJuIHNhLmNsb25lKHsgcnVuSWQ6IHJ1bi5pZCwgZXhjbHVkZTogYWR2YW5jZU9wbnMub3BzIH0pLnRoZW4oZnVuY3Rpb24gKHJlc3BvbnNlKSB7XG4gICAgICAgICAgICAgICAgdmFyIHJzID0gbmV3IFJ1blNlcnZpY2UobWUuY3VycmVudC5ydW4uZ2V0Q3VycmVudENvbmZpZygpKTtcbiAgICAgICAgICAgICAgICByZXR1cm4gcnMubG9hZChyZXNwb25zZS5ydW4pO1xuICAgICAgICAgICAgfSk7XG4gICAgICAgIH1cbiAgICAgICAgZnVuY3Rpb24gbWFya1NhdmVkKHJ1bikge1xuICAgICAgICAgICAgcmV0dXJuIG1lLnNhdmVkUnVucy5zYXZlKHJ1bi5pZCwgbWV0YWRhdGEpLnRoZW4oZnVuY3Rpb24gKHNhdmVkUmVzcG9uc2UpIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gJC5leHRlbmQodHJ1ZSwge30sIHJ1biwgc2F2ZWRSZXNwb25zZSk7XG4gICAgICAgICAgICB9KTtcbiAgICAgICAgfVxuICAgICAgICBmdW5jdGlvbiBhZHZhbmNlKHJ1bikge1xuICAgICAgICAgICAgdmFyIHJzID0gbmV3IFJ1blNlcnZpY2UocnVuKTtcbiAgICAgICAgICAgIHJldHVybiBycy5zZXJpYWwob3B0cy5hZHZhbmNlT3BlcmF0aW9uKS50aGVuKGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gcnVuO1xuICAgICAgICAgICAgfSk7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIG1lLmN1cnJlbnRcbiAgICAgICAgICAgICAgICAuZ2V0UnVuKClcbiAgICAgICAgICAgICAgICAudGhlbihjbG9uZSlcbiAgICAgICAgICAgICAgICAudGhlbihhZHZhbmNlKVxuICAgICAgICAgICAgICAgIC50aGVuKG1hcmtTYXZlZCk7XG4gICAgfTtcbn1cblxubW9kdWxlLmV4cG9ydHMgPSBTY2VuYXJpb01hbmFnZXI7XG4iLCIvKipcbiAqICMjIEJhc2VsaW5lXG4gKlxuICogQW4gaW5zdGFuY2Ugb2YgYSBbUnVuIE1hbmFnZXJdKC4uLy4uL3J1bi1tYW5hZ2VyLykgd2l0aCBhIGJhc2VsaW5lIHN0cmF0ZWd5IGlzIGluY2x1ZGVkIGF1dG9tYXRpY2FsbHkgaW4gZXZlcnkgaW5zdGFuY2Ugb2YgYSBbU2NlbmFyaW8gTWFuYWdlcl0oLi4vKSwgYW5kIGlzIGFjY2Vzc2libGUgZnJvbSB0aGUgU2NlbmFyaW8gTWFuYWdlciBhdCBgLmJhc2VsaW5lYC5cbiAqXG4gKiBBIGJhc2VsaW5lIGlzIGRlZmluZWQgYXMgYSBydW4gXCJhZHZhbmNlZCB0byB0aGUgZW5kXCIgdXNpbmcganVzdCB0aGUgbW9kZWwgZGVmYXVsdHMuIFRoZSBiYXNlbGluZSBydW4gaXMgdHlwaWNhbGx5IGRpc3BsYXllZCBpbiB0aGUgcHJvamVjdCdzIFVJIGFzIHBhcnQgb2YgYSBydW4gY29tcGFyaXNvbiB0YWJsZSBvciBjaGFydC5cbiAqXG4gKiBUaGUgYGJhc2VsaW5lYCBzdHJhdGVneSBsb29rcyBmb3IgdGhlIG1vc3QgcmVjZW50IHJ1biBuYW1lZCBhcyAnQmFzZWxpbmUnIChvciBuYW1lZCBhcyBzcGVjaWZpZWQgaW4gdGhlIGBiYXNlbGluZS5ydW5OYW1lYCBbY29uZmlndXJhdGlvbiBvcHRpb24gb2YgdGhlIFNjZW5hcmlvIE1hbmFnZXJdKC4uLyNjb25maWd1cmF0aW9uLW9wdGlvbnMpKSB0aGF0IGlzIGZsYWdnZWQgYXMgYHNhdmVkYCBhbmQgbm90IGB0cmFzaGVkYC4gSWYgdGhlIHN0cmF0ZWd5IGNhbm5vdCBmaW5kIHN1Y2ggYSBydW4sIGl0IGNyZWF0ZXMgYSBuZXcgcnVuIGFuZCBpbW1lZGlhdGVseSBleGVjdXRlcyBhIHNldCBvZiBpbml0aWFsaXphdGlvbiBvcGVyYXRpb25zLiBcbiAqXG4gKiBDb21wYXJpbmcgYWdhaW5zdCBhIGJhc2VsaW5lIHJ1biBpcyBvcHRpb25hbCBpbiBhIFNjZW5hcmlvIE1hbmFnZXI7IHlvdSBjYW4gW2NvbmZpZ3VyZV0oLi4vI2NvbmZpZ3VyYXRpb24tb3B0aW9ucykgeW91ciBTY2VuYXJpbyBNYW5hZ2VyIHRvIG5vdCBpbmNsdWRlIG9uZS4gU2VlIFttb3JlIGluZm9ybWF0aW9uXSguLi8jcHJvcGVydGllcykgb24gdXNpbmcgYC5iYXNlbGluZWAgd2l0aGluIHRoZSBTY2VuYXJpbyBNYW5hZ2VyLlxuICpcbiAqIFNlZSBhbHNvOiBbYWRkaXRpb25hbCBpbmZvcm1hdGlvbiBvbiBydW4gc3RyYXRlZ2llc10oLi4vLi4vc3RyYXRlZ2llcy8pLlxuICpcbiAqL1xuXG4ndXNlIHN0cmljdCc7XG5cbnZhciBSZXVzZWluaXRTdHJhdGVneSA9IHJlcXVpcmUoJy4uL3J1bi1zdHJhdGVnaWVzL3JldXNlLWxhc3QtaW5pdGlhbGl6ZWQnKTtcblxubW9kdWxlLmV4cG9ydHMgPSBmdW5jdGlvbiAob3B0aW9ucykge1xuICAgIHZhciBkZWZhdWx0cyA9IHtcbiAgICAgICAgYmFzZWxpbmVOYW1lOiAnQmFzZWxpbmUnLFxuICAgICAgICBpbml0T3BlcmF0aW9uOiBbeyBzdGVwVG86ICdlbmQnIH1dXG4gICAgfTtcbiAgICB2YXIgc3RyYXRlZ3lPcHRpb25zID0gb3B0aW9ucyA/IG9wdGlvbnMuc3RyYXRlZ3lPcHRpb25zIDoge307XG4gICAgdmFyIG9wdHMgPSAkLmV4dGVuZCh7fSwgZGVmYXVsdHMsIHN0cmF0ZWd5T3B0aW9ucyk7XG4gICAgcmV0dXJuIG5ldyBSZXVzZWluaXRTdHJhdGVneSh7XG4gICAgICAgIHN0cmF0ZWd5T3B0aW9uczoge1xuICAgICAgICAgICAgaW5pdE9wZXJhdGlvbjogb3B0cy5pbml0T3BlcmF0aW9uLFxuICAgICAgICAgICAgZmxhZzoge1xuICAgICAgICAgICAgICAgIHNhdmVkOiB0cnVlLFxuICAgICAgICAgICAgICAgIHRyYXNoZWQ6IGZhbHNlLFxuICAgICAgICAgICAgICAgIG5hbWU6IG9wdHMuYmFzZWxpbmVOYW1lXG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICB9KTtcbn07XG4iLCIvKipcbiAqICMjIEN1cnJlbnQgKHJldXNlLWxhc3QtdW5zYXZlZClcbiAqXG4gKiBBbiBpbnN0YW5jZSBvZiBhIFtSdW4gTWFuYWdlcl0oLi4vLi4vcnVuLW1hbmFnZXIvKSB3aXRoIHRoaXMgc3RyYXRlZ3kgaXMgaW5jbHVkZWQgYXV0b21hdGljYWxseSBpbiBldmVyeSBpbnN0YW5jZSBvZiBhIFtTY2VuYXJpbyBNYW5hZ2VyXSguLi8pLCBhbmQgaXMgYWNjZXNzaWJsZSBmcm9tIHRoZSBTY2VuYXJpbyBNYW5hZ2VyIGF0IGAuY3VycmVudGAuXG4gKlxuICogVGhlIGByZXVzZS1sYXN0LXVuc2F2ZWRgIHN0cmF0ZWd5IHJldHVybnMgdGhlIG1vc3QgcmVjZW50IHJ1biB0aGF0IGlzIG5vdCBmbGFnZ2VkIGFzIGB0cmFzaGVkYCBhbmQgYWxzbyBub3QgZmxhZ2dlZCBhcyBgc2F2ZWRgLlxuICogXG4gKiBVc2luZyB0aGlzIHN0cmF0ZWd5IG1lYW5zIHRoYXQgZW5kIHVzZXJzIGNvbnRpbnVlIHdvcmtpbmcgd2l0aCB0aGUgbW9zdCByZWNlbnQgcnVuIHRoYXQgaGFzIG5vdCBiZWVuIGV4cGxpY2l0bHkgZmxhZ2dlZCBieSB0aGUgcHJvamVjdC4gSG93ZXZlciwgaWYgdGhlcmUgYXJlIG5vIHJ1bnMgZm9yIHRoaXMgZW5kIHVzZXIsIGEgbmV3IHJ1biBpcyBjcmVhdGVkLlxuICogXG4gKiBTcGVjaWZpY2FsbHksIHRoZSBzdHJhdGVneSBpczpcbiAqXG4gKiAqIENoZWNrIHRoZSBgc2F2ZWRgIGFuZCBgdHJhc2hlZGAgZmllbGRzIG9mIHRoZSBydW4gdG8gZGV0ZXJtaW5lIGlmIHRoZSBydW4gaGFzIGJlZW4gZXhwbGljaXRseSBzYXZlZCBvciBleHBsaWNpdGx5IGZsYWdnZWQgYXMgbm8gbG9uZ2VyIHVzZWZ1bC5cbiAqICAgICAqIFJldHVybiB0aGUgbW9zdCByZWNlbnQgcnVuIHRoYXQgaXMgbm90IGB0cmFzaGVkYCBhbmQgYWxzbyBub3QgYHNhdmVkYC5cbiAqICAgICAqIElmIHRoZXJlIGFyZSBubyBydW5zLCBjcmVhdGUgYSBuZXcgcnVuIGZvciB0aGlzIGVuZCB1c2VyLiBcbiAqXG4gKiBTZWUgW21vcmUgaW5mb3JtYXRpb25dKC4uLyNwcm9wZXJ0aWVzKSBvbiB1c2luZyBgLmN1cnJlbnRgIHdpdGhpbiB0aGUgU2NlbmFyaW8gTWFuYWdlci5cbiAqXG4gKiBTZWUgYWxzbzogW2FkZGl0aW9uYWwgaW5mb3JtYXRpb24gb24gcnVuIHN0cmF0ZWdpZXNdKC4uLy4uL3N0cmF0ZWdpZXMvKS5cbiAqL1xuXG4ndXNlIHN0cmljdCc7XG52YXIgY2xhc3NGcm9tID0gcmVxdWlyZSgnLi4vLi4vdXRpbC9pbmhlcml0Jyk7XG52YXIgaW5qZWN0RmlsdGVyc0Zyb21TZXNzaW9uID0gcmVxdWlyZSgnLi4vc3RyYXRlZ3ktdXRpbHMnKS5pbmplY3RGaWx0ZXJzRnJvbVNlc3Npb247XG52YXIgaW5qZWN0U2NvcGVGcm9tU2Vzc2lvbiA9IHJlcXVpcmUoJy4uL3N0cmF0ZWd5LXV0aWxzJykuaW5qZWN0U2NvcGVGcm9tU2Vzc2lvbjtcblxudmFyIEJhc2UgPSB7fTtcblxuLy9UT0RPOiBNYWtlIGEgbW9yZSBnZW5lcmljIHZlcnNpb24gb2YgdGhpcyBjYWxsZWQgJ3JldXNlLWJ5LW1hdGNoaW5nLWZpbHRlcic7XG5tb2R1bGUuZXhwb3J0cyA9IGNsYXNzRnJvbShCYXNlLCB7XG4gICAgY29uc3RydWN0b3I6IGZ1bmN0aW9uIChvcHRpb25zKSB7XG4gICAgICAgIHZhciBzdHJhdGVneU9wdGlvbnMgPSBvcHRpb25zID8gb3B0aW9ucy5zdHJhdGVneU9wdGlvbnMgOiB7fTtcbiAgICAgICAgdGhpcy5vcHRpb25zID0gc3RyYXRlZ3lPcHRpb25zO1xuICAgIH0sXG5cbiAgICByZXNldDogZnVuY3Rpb24gKHJ1blNlcnZpY2UsIHVzZXJTZXNzaW9uLCBvcHRpb25zKSB7XG4gICAgICAgIHZhciBvcHQgPSBpbmplY3RTY29wZUZyb21TZXNzaW9uKHJ1blNlcnZpY2UuZ2V0Q3VycmVudENvbmZpZygpLCB1c2VyU2Vzc2lvbik7XG4gICAgICAgIHJldHVybiBydW5TZXJ2aWNlLmNyZWF0ZShvcHQsIG9wdGlvbnMpLnRoZW4oZnVuY3Rpb24gKGNyZWF0ZVJlc3BvbnNlKSB7XG4gICAgICAgICAgICByZXR1cm4gJC5leHRlbmQodHJ1ZSwge30sIGNyZWF0ZVJlc3BvbnNlLCB7IGZyZXNobHlDcmVhdGVkOiB0cnVlIH0pO1xuICAgICAgICB9KTtcbiAgICB9LFxuXG4gICAgZ2V0UnVuOiBmdW5jdGlvbiAocnVuU2VydmljZSwgdXNlclNlc3Npb24sIG9wdHMpIHtcbiAgICAgICAgdmFyIHJ1bm9wdHMgPSBydW5TZXJ2aWNlLmdldEN1cnJlbnRDb25maWcoKTtcbiAgICAgICAgdmFyIGZpbHRlciA9IGluamVjdEZpbHRlcnNGcm9tU2Vzc2lvbih7IFxuICAgICAgICAgICAgc2F2ZWQ6IGZhbHNlLFxuICAgICAgICAgICAgdHJhc2hlZDogZmFsc2UsIC8vVE9ETzogY2hhbmdlIHRvICchPXRydWUnIG9uY2UgRVBJQ0VOVEVSLTI1MDAgaXMgZml4ZWQsXG4gICAgICAgICAgICBtb2RlbDogcnVub3B0cy5tb2RlbCxcbiAgICAgICAgfSwgdXNlclNlc3Npb24pO1xuICAgICAgICB2YXIgbWUgPSB0aGlzO1xuICAgICAgICB2YXIgb3V0cHV0TW9kaWZpZXJzID0geyBcbiAgICAgICAgICAgIC8vIHN0YXJ0cmVjb3JkOiAwLCAgLy9UT0RPOiBVbmNvbW1lbnQgd2hlbiBFUElDRU5URVItMjU2OSBpcyBmaXhlZFxuICAgICAgICAgICAgLy8gZW5kcmVjb3JkOiAwLFxuICAgICAgICAgICAgc29ydDogJ2NyZWF0ZWQnLCBcbiAgICAgICAgICAgIGRpcmVjdGlvbjogJ2Rlc2MnXG4gICAgICAgIH07XG4gICAgICAgIHJldHVybiBydW5TZXJ2aWNlLnF1ZXJ5KGZpbHRlciwgb3V0cHV0TW9kaWZpZXJzKS50aGVuKGZ1bmN0aW9uIChydW5zKSB7XG4gICAgICAgICAgICBpZiAoIXJ1bnMubGVuZ3RoKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIG1lLnJlc2V0KHJ1blNlcnZpY2UsIHVzZXJTZXNzaW9uKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHJldHVybiBydW5zWzBdO1xuICAgICAgICB9KTtcbiAgICB9XG59LCB7IHJlcXVpcmVzQXV0aDogZmFsc2UgfSk7IiwiJ3VzZSBzdHJpY3QnO1xuXG5cbm1vZHVsZS5leHBvcnRzID0ge1xuICAgIHJlc2V0OiBmdW5jdGlvbiAocGFyYW1zLCBvcHRpb25zLCBtYW5hZ2VyKSB7XG4gICAgICAgIHJldHVybiBtYW5hZ2VyLnJlc2V0KG9wdGlvbnMpO1xuICAgIH1cbn07XG4iLCIndXNlIHN0cmljdCc7XG5cbnZhciBSdW5TZXJ2aWNlID0gcmVxdWlyZSgnLi4vc2VydmljZS9ydW4tYXBpLXNlcnZpY2UnKTtcblxubW9kdWxlLmV4cG9ydHMgPSB7XG4gICAgbWVyZ2VSdW5PcHRpb25zOiBmdW5jdGlvbiAocnVuLCBvcHRpb25zKSB7XG4gICAgICAgIGlmIChydW4gaW5zdGFuY2VvZiBSdW5TZXJ2aWNlKSB7XG4gICAgICAgICAgICBydW4udXBkYXRlQ29uZmlnKG9wdGlvbnMpO1xuICAgICAgICAgICAgcmV0dXJuIHJ1bjtcbiAgICAgICAgfSBcbiAgICAgICAgcmV0dXJuICQuZXh0ZW5kKHRydWUsIHt9LCBydW4sIG9wdGlvbnMpO1xuICAgIH0sXG5cbiAgICBpbmplY3RGaWx0ZXJzRnJvbVNlc3Npb246IGZ1bmN0aW9uIChjdXJyZW50RmlsdGVyLCBzZXNzaW9uLCBvcHRpb25zKSB7XG4gICAgICAgIHZhciBkZWZhdWx0cyA9IHtcbiAgICAgICAgICAgIHNjb3BlQnlHcm91cDogdHJ1ZSxcbiAgICAgICAgICAgIHNjb3BlQnlVc2VyOiB0cnVlLFxuICAgICAgICB9O1xuICAgICAgICB2YXIgb3B0cyA9ICQuZXh0ZW5kKHRydWUsIHt9LCBkZWZhdWx0cywgb3B0aW9ucyk7XG5cbiAgICAgICAgdmFyIGZpbHRlciA9ICQuZXh0ZW5kKHRydWUsIHt9LCBjdXJyZW50RmlsdGVyKTtcbiAgICAgICAgaWYgKG9wdHMuc2NvcGVCeUdyb3VwICYmIHNlc3Npb24gJiYgc2Vzc2lvbi5ncm91cE5hbWUpIHtcbiAgICAgICAgICAgIGZpbHRlclsnc2NvcGUuZ3JvdXAnXSA9IHNlc3Npb24uZ3JvdXBOYW1lO1xuICAgICAgICB9XG4gICAgICAgIGlmIChvcHRzLnNjb3BlQnlVc2VyICYmIHNlc3Npb24gJiYgc2Vzc2lvbi51c2VySWQpIHtcbiAgICAgICAgICAgIGZpbHRlclsndXNlci5pZCddID0gc2Vzc2lvbi51c2VySWQ7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIGZpbHRlcjtcbiAgICB9LFxuXG4gICAgaW5qZWN0U2NvcGVGcm9tU2Vzc2lvbjogZnVuY3Rpb24gKGN1cnJlbnRQYXJhbXMsIHNlc3Npb24pIHtcbiAgICAgICAgdmFyIGdyb3VwID0gc2Vzc2lvbiAmJiBzZXNzaW9uLmdyb3VwTmFtZTtcbiAgICAgICAgdmFyIHBhcmFtcyA9ICQuZXh0ZW5kKHRydWUsIHt9LCBjdXJyZW50UGFyYW1zKTtcbiAgICAgICAgaWYgKGdyb3VwKSB7XG4gICAgICAgICAgICAkLmV4dGVuZChwYXJhbXMsIHtcbiAgICAgICAgICAgICAgICBzY29wZTogeyBncm91cDogZ3JvdXAgfVxuICAgICAgICAgICAgfSk7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIHBhcmFtcztcbiAgICB9XG59OyIsIi8qKlxuKiAjIyBXb3JsZCBNYW5hZ2VyXG4qXG4qIEFzIGRpc2N1c3NlZCB1bmRlciB0aGUgW1dvcmxkIEFQSSBBZGFwdGVyXSguLi93b3JsZC1hcGktYWRhcHRlci8pLCBhIFtydW5dKC4uLy4uLy4uL2dsb3NzYXJ5LyNydW4pIGlzIGEgY29sbGVjdGlvbiBvZiBlbmQgdXNlciBpbnRlcmFjdGlvbnMgd2l0aCBhIHByb2plY3QgYW5kIGl0cyBtb2RlbC4gRm9yIGJ1aWxkaW5nIG11bHRpcGxheWVyIHNpbXVsYXRpb25zIHlvdSB0eXBpY2FsbHkgd2FudCBtdWx0aXBsZSBlbmQgdXNlcnMgdG8gc2hhcmUgdGhlIHNhbWUgc2V0IG9mIGludGVyYWN0aW9ucywgYW5kIHdvcmsgd2l0aGluIGEgY29tbW9uIHN0YXRlLiBFcGljZW50ZXIgYWxsb3dzIHlvdSB0byBjcmVhdGUgXCJ3b3JsZHNcIiB0byBoYW5kbGUgc3VjaCBjYXNlcy5cbipcbiogVGhlIFdvcmxkIE1hbmFnZXIgcHJvdmlkZXMgYW4gZWFzeSB3YXkgdG8gdHJhY2sgYW5kIGFjY2VzcyB0aGUgY3VycmVudCB3b3JsZCBhbmQgcnVuIGZvciBwYXJ0aWN1bGFyIGVuZCB1c2Vycy4gSXQgaXMgdHlwaWNhbGx5IHVzZWQgaW4gcGFnZXMgdGhhdCBlbmQgdXNlcnMgd2lsbCBpbnRlcmFjdCB3aXRoLiAoVGhlIHJlbGF0ZWQgW1dvcmxkIEFQSSBBZGFwdGVyXSguLi93b3JsZC1hcGktYWRhcHRlci8pIGhhbmRsZXMgY3JlYXRpbmcgbXVsdGlwbGF5ZXIgd29ybGRzLCBhbmQgYWRkaW5nIGFuZCByZW1vdmluZyBlbmQgdXNlcnMgYW5kIHJ1bnMgZnJvbSBhIHdvcmxkLiBCZWNhdXNlIG9mIHRoaXMsIHR5cGljYWxseSB0aGUgV29ybGQgQWRhcHRlciBpcyB1c2VkIGZvciBmYWNpbGl0YXRvciBwYWdlcyBpbiB5b3VyIHByb2plY3QuKVxuKlxuKiAjIyMgVXNpbmcgdGhlIFdvcmxkIE1hbmFnZXJcbipcbiogVG8gdXNlIHRoZSBXb3JsZCBNYW5hZ2VyLCBpbnN0YW50aWF0ZSBpdC4gVGhlbiwgbWFrZSBjYWxscyB0byBhbnkgb2YgdGhlIG1ldGhvZHMgeW91IG5lZWQuXG4qXG4qIFdoZW4geW91IGluc3RhbnRpYXRlIGEgV29ybGQgTWFuYWdlciwgdGhlIHdvcmxkJ3MgYWNjb3VudCBpZCwgcHJvamVjdCBpZCwgYW5kIGdyb3VwIGFyZSBhdXRvbWF0aWNhbGx5IHRha2VuIGZyb20gdGhlIHNlc3Npb24gKHRoYW5rcyB0byB0aGUgW0F1dGhlbnRpY2F0aW9uIFNlcnZpY2VdKC4uL2F1dGgtYXBpLXNlcnZpY2UpKS5cbipcbiogTm90ZSB0aGF0IHRoZSBXb3JsZCBNYW5hZ2VyIGRvZXMgKm5vdCogY3JlYXRlIHdvcmxkcyBhdXRvbWF0aWNhbGx5LiAoVGhpcyBpcyBkaWZmZXJlbnQgdGhhbiB0aGUgW1J1biBNYW5hZ2VyXSguLi9ydW4tbWFuYWdlcikuKSBIb3dldmVyLCB5b3UgY2FuIHBhc3MgaW4gc3BlY2lmaWMgb3B0aW9ucyB0byBhbnkgcnVucyBjcmVhdGVkIGJ5IHRoZSBtYW5hZ2VyLCB1c2luZyBhIGBydW5gIG9iamVjdC5cbipcbiogVGhlIHBhcmFtZXRlcnMgZm9yIGNyZWF0aW5nIGEgV29ybGQgTWFuYWdlciBhcmU6XG4qXG4qICAgKiBgYWNjb3VudGA6IFRoZSAqKlRlYW0gSUQqKiBpbiB0aGUgRXBpY2VudGVyIHVzZXIgaW50ZXJmYWNlIGZvciB0aGlzIHByb2plY3QuXG4qICAgKiBgcHJvamVjdGA6IFRoZSAqKlByb2plY3QgSUQqKiBmb3IgdGhpcyBwcm9qZWN0LlxuKiAgICogYGdyb3VwYDogVGhlICoqR3JvdXAgTmFtZSoqIGZvciB0aGlzIHdvcmxkLlxuKiAgICogYHJ1bmA6IE9wdGlvbnMgdG8gdXNlIHdoZW4gY3JlYXRpbmcgbmV3IHJ1bnMgd2l0aCB0aGUgbWFuYWdlciwgZS5nLiBgcnVuOiB7IGZpbGVzOiBbJ2RhdGEueGxzJ10gfWAuXG4qICAgKiBgcnVuLm1vZGVsYDogVGhlIG5hbWUgb2YgdGhlIHByaW1hcnkgbW9kZWwgZmlsZSBmb3IgdGhpcyBwcm9qZWN0LiBSZXF1aXJlZCBpZiB5b3UgaGF2ZSBub3QgYWxyZWFkeSBwYXNzZWQgaXQgaW4gYXMgcGFydCBvZiB0aGUgYG9wdGlvbnNgIHBhcmFtZXRlciBmb3IgYW4gZW5jbG9zaW5nIGNhbGwuXG4qXG4qIEZvciBleGFtcGxlOlxuKlxuKiAgICAgICB2YXIgd01nciA9IG5ldyBGLm1hbmFnZXIuV29ybGRNYW5hZ2VyKHtcbiogICAgICAgICAgYWNjb3VudDogJ2FjbWUtc2ltdWxhdGlvbnMnLFxuKiAgICAgICAgICBwcm9qZWN0OiAnc3VwcGx5LWNoYWluLWdhbWUnLFxuKiAgICAgICAgICBydW46IHsgbW9kZWw6ICdzdXBwbHktY2hhaW4ucHknIH0sXG4qICAgICAgICAgIGdyb3VwOiAndGVhbTEnXG4qICAgICAgIH0pO1xuKlxuKiAgICAgICB3TWdyLmdldEN1cnJlbnRSdW4oKTtcbiovXG5cbid1c2Ugc3RyaWN0JztcblxudmFyIFdvcmxkQXBpID0gcmVxdWlyZSgnLi4vc2VydmljZS93b3JsZC1hcGktYWRhcHRlcicpO1xudmFyIFJ1bk1hbmFnZXIgPSByZXF1aXJlKCcuL3J1bi1tYW5hZ2VyJyk7XG52YXIgQXV0aE1hbmFnZXIgPSByZXF1aXJlKCcuL2F1dGgtbWFuYWdlcicpO1xudmFyIHdvcmxkQXBpO1xuXG5mdW5jdGlvbiBidWlsZFN0cmF0ZWd5KHdvcmxkSWQsIGR0ZCkge1xuXG4gICAgcmV0dXJuIGZ1bmN0aW9uIEN0b3Iob3B0aW9ucykge1xuICAgICAgICB0aGlzLm9wdGlvbnMgPSBvcHRpb25zO1xuXG4gICAgICAgICQuZXh0ZW5kKHRoaXMsIHtcbiAgICAgICAgICAgIHJlc2V0OiBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdub3QgaW1wbGVtZW50ZC4gTmVlZCBhcGkgY2hhbmdlcycpO1xuICAgICAgICAgICAgfSxcblxuICAgICAgICAgICAgZ2V0UnVuOiBmdW5jdGlvbiAocnVuU2VydmljZSkge1xuICAgICAgICAgICAgICAgIHZhciBtZSA9IHRoaXM7XG4gICAgICAgICAgICAgICAgLy9nZXQgb3IgY3JlYXRlIVxuICAgICAgICAgICAgICAgIC8vIE1vZGVsIGlzIHJlcXVpcmVkIGluIHRoZSBvcHRpb25zXG4gICAgICAgICAgICAgICAgdmFyIG1vZGVsID0gdGhpcy5vcHRpb25zLnJ1bi5tb2RlbCB8fCB0aGlzLm9wdGlvbnMubW9kZWw7XG4gICAgICAgICAgICAgICAgcmV0dXJuIHdvcmxkQXBpLmdldEN1cnJlbnRSdW5JZCh7IG1vZGVsOiBtb2RlbCwgZmlsdGVyOiB3b3JsZElkIH0pXG4gICAgICAgICAgICAgICAgICAgIC50aGVuKGZ1bmN0aW9uIChydW5JZCkge1xuICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIHJ1blNlcnZpY2UubG9hZChydW5JZCk7XG4gICAgICAgICAgICAgICAgICAgIH0pXG4gICAgICAgICAgICAgICAgICAgIC50aGVuKGZ1bmN0aW9uIChydW4pIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGR0ZC5yZXNvbHZlV2l0aChtZSwgW3J1bl0pO1xuICAgICAgICAgICAgICAgICAgICB9KVxuICAgICAgICAgICAgICAgICAgICAuZmFpbChkdGQucmVqZWN0KTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICApO1xuICAgIH07XG59XG5cblxubW9kdWxlLmV4cG9ydHMgPSBmdW5jdGlvbiAob3B0aW9ucykge1xuICAgIHRoaXMub3B0aW9ucyA9IG9wdGlvbnMgfHwgeyBydW46IHt9LCB3b3JsZDoge30gfTtcblxuICAgICQuZXh0ZW5kKHRydWUsIHRoaXMub3B0aW9ucywgdGhpcy5vcHRpb25zLnJ1bik7XG4gICAgJC5leHRlbmQodHJ1ZSwgdGhpcy5vcHRpb25zLCB0aGlzLm9wdGlvbnMud29ybGQpO1xuXG4gICAgd29ybGRBcGkgPSBuZXcgV29ybGRBcGkodGhpcy5vcHRpb25zKTtcbiAgICB0aGlzLl9hdXRoID0gbmV3IEF1dGhNYW5hZ2VyKCk7XG4gICAgdmFyIG1lID0gdGhpcztcblxuICAgIHZhciBhcGkgPSB7XG5cbiAgICAgICAgLyoqXG4gICAgICAgICogUmV0dXJucyB0aGUgY3VycmVudCB3b3JsZCAob2JqZWN0KSBhbmQgYW4gaW5zdGFuY2Ugb2YgdGhlIFtXb3JsZCBBUEkgQWRhcHRlcl0oLi4vd29ybGQtYXBpLWFkYXB0ZXIvKS5cbiAgICAgICAgKlxuICAgICAgICAqICoqRXhhbXBsZSoqXG4gICAgICAgICpcbiAgICAgICAgKiAgICAgICB3TWdyLmdldEN1cnJlbnRXb3JsZCgpXG4gICAgICAgICogICAgICAgICAgIC50aGVuKGZ1bmN0aW9uKHdvcmxkLCB3b3JsZEFkYXB0ZXIpIHtcbiAgICAgICAgKiAgICAgICAgICAgICAgIGNvbnNvbGUubG9nKHdvcmxkLmlkKTtcbiAgICAgICAgKiAgICAgICAgICAgICAgIHdvcmxkQWRhcHRlci5nZXRDdXJyZW50UnVuSWQoKTtcbiAgICAgICAgKiAgICAgICAgICAgfSk7XG4gICAgICAgICpcbiAgICAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAqIEBwYXJhbSB7c3RyaW5nfSB1c2VySWQgKE9wdGlvbmFsKSBUaGUgaWQgb2YgdGhlIHVzZXIgd2hvc2Ugd29ybGQgaXMgYmVpbmcgYWNjZXNzZWQuIERlZmF1bHRzIHRvIHRoZSB1c2VyIGluIHRoZSBjdXJyZW50IHNlc3Npb24uXG4gICAgICAgICogQHBhcmFtIHtzdHJpbmd9IGdyb3VwTmFtZSAoT3B0aW9uYWwpIFRoZSBuYW1lIG9mIHRoZSBncm91cCB3aG9zZSB3b3JsZCBpcyBiZWluZyBhY2Nlc3NlZC4gRGVmYXVsdHMgdG8gdGhlIGdyb3VwIGZvciB0aGUgdXNlciBpbiB0aGUgY3VycmVudCBzZXNzaW9uLlxuICAgICAgICAqIEByZXR1cm4ge1Byb21pc2V9XG4gICAgICAgICovXG4gICAgICAgIGdldEN1cnJlbnRXb3JsZDogZnVuY3Rpb24gKHVzZXJJZCwgZ3JvdXBOYW1lKSB7XG4gICAgICAgICAgICB2YXIgc2Vzc2lvbiA9IHRoaXMuX2F1dGguZ2V0Q3VycmVudFVzZXJTZXNzaW9uSW5mbygpO1xuICAgICAgICAgICAgaWYgKCF1c2VySWQpIHtcbiAgICAgICAgICAgICAgICB1c2VySWQgPSBzZXNzaW9uLnVzZXJJZDtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGlmICghZ3JvdXBOYW1lKSB7XG4gICAgICAgICAgICAgICAgZ3JvdXBOYW1lID0gc2Vzc2lvbi5ncm91cE5hbWU7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICByZXR1cm4gd29ybGRBcGkuZ2V0Q3VycmVudFdvcmxkRm9yVXNlcih1c2VySWQsIGdyb3VwTmFtZSk7XG4gICAgICAgIH0sXG5cbiAgICAgICAgLyoqXG4gICAgICAgICogUmV0dXJucyB0aGUgY3VycmVudCBydW4gKG9iamVjdCkgYW5kIGFuIGluc3RhbmNlIG9mIHRoZSBbUnVuIEFQSSBTZXJ2aWNlXSguLi9ydW4tYXBpLXNlcnZpY2UvKS5cbiAgICAgICAgKlxuICAgICAgICAqICoqRXhhbXBsZSoqXG4gICAgICAgICpcbiAgICAgICAgKiAgICAgICB3TWdyLmdldEN1cnJlbnRSdW4oJ215TW9kZWwucHknKVxuICAgICAgICAqICAgICAgICAgICAudGhlbihmdW5jdGlvbihydW4sIHJ1blNlcnZpY2UpIHtcbiAgICAgICAgKiAgICAgICAgICAgICAgIGNvbnNvbGUubG9nKHJ1bi5pZCk7XG4gICAgICAgICogICAgICAgICAgICAgICBydW5TZXJ2aWNlLmRvKCdzdGFydEdhbWUnKTtcbiAgICAgICAgKiAgICAgICAgICAgfSk7XG4gICAgICAgICpcbiAgICAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAqIEBwYXJhbSB7c3RyaW5nfSBtb2RlbCAoT3B0aW9uYWwpIFRoZSBuYW1lIG9mIHRoZSBtb2RlbCBmaWxlLiBSZXF1aXJlZCBpZiBub3QgYWxyZWFkeSBwYXNzZWQgaW4gYXMgYHJ1bi5tb2RlbGAgd2hlbiB0aGUgV29ybGQgTWFuYWdlciBpcyBjcmVhdGVkLlxuICAgICAgICAqIEByZXR1cm4ge1Byb21pc2V9XG4gICAgICAgICovXG4gICAgICAgIGdldEN1cnJlbnRSdW46IGZ1bmN0aW9uIChtb2RlbCkge1xuICAgICAgICAgICAgdmFyIGR0ZCA9ICQuRGVmZXJyZWQoKTtcbiAgICAgICAgICAgIHZhciBzZXNzaW9uID0gdGhpcy5fYXV0aC5nZXRDdXJyZW50VXNlclNlc3Npb25JbmZvKCk7XG4gICAgICAgICAgICB2YXIgY3VyVXNlcklkID0gc2Vzc2lvbi51c2VySWQ7XG4gICAgICAgICAgICB2YXIgY3VyR3JvdXBOYW1lID0gc2Vzc2lvbi5ncm91cE5hbWU7XG5cbiAgICAgICAgICAgIGZ1bmN0aW9uIGdldEFuZFJlc3RvcmVMYXRlc3RSdW4od29ybGQpIHtcbiAgICAgICAgICAgICAgICBpZiAoIXdvcmxkKSB7XG4gICAgICAgICAgICAgICAgICAgIHJldHVybiBkdGQucmVqZWN0KHsgZXJyb3I6ICdUaGUgdXNlciBpcyBub3QgcGFydCBvZiBhbnkgd29ybGQhJyB9KTtcbiAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICB2YXIgY3VycmVudFdvcmxkSWQgPSB3b3JsZC5pZDtcbiAgICAgICAgICAgICAgICB2YXIgcnVuT3B0cyA9ICQuZXh0ZW5kKHRydWUsIG1lLm9wdGlvbnMsIHsgbW9kZWw6IG1vZGVsIH0pO1xuICAgICAgICAgICAgICAgIHZhciBzdHJhdGVneSA9IGJ1aWxkU3RyYXRlZ3koY3VycmVudFdvcmxkSWQsIGR0ZCk7XG4gICAgICAgICAgICAgICAgdmFyIG9wdCA9ICQuZXh0ZW5kKHRydWUsIHt9LCB7XG4gICAgICAgICAgICAgICAgICAgIHN0cmF0ZWd5OiBzdHJhdGVneSxcbiAgICAgICAgICAgICAgICAgICAgcnVuOiBydW5PcHRzXG4gICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgICAgdmFyIHJtID0gbmV3IFJ1bk1hbmFnZXIob3B0KTtcbiAgICAgICAgICAgICAgICByZXR1cm4gcm0uZ2V0UnVuKClcbiAgICAgICAgICAgICAgICAgICAgLnRoZW4oZnVuY3Rpb24gKHJ1bikge1xuICAgICAgICAgICAgICAgICAgICAgICAgZHRkLnJlc29sdmUocnVuLCBybS5ydW5TZXJ2aWNlLCBybSk7XG4gICAgICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICB0aGlzLmdldEN1cnJlbnRXb3JsZChjdXJVc2VySWQsIGN1ckdyb3VwTmFtZSlcbiAgICAgICAgICAgICAgICAudGhlbihnZXRBbmRSZXN0b3JlTGF0ZXN0UnVuKTtcblxuICAgICAgICAgICAgcmV0dXJuIGR0ZC5wcm9taXNlKCk7XG4gICAgICAgIH1cbiAgICB9O1xuXG4gICAgJC5leHRlbmQodGhpcywgYXBpKTtcbn07XG4iLCIvKipcbiAqICMjIEZpbGUgQVBJIFNlcnZpY2VcbiAqXG4gKiBUaGUgRmlsZSBBUEkgU2VydmljZSBhbGxvd3MgeW91IHRvIHVwbG9hZCBhbmQgZG93bmxvYWQgZmlsZXMgZGlyZWN0bHkgb250byBFcGljZW50ZXIsIGFuYWxvZ291cyB0byB1c2luZyB0aGUgRmlsZSBNYW5hZ2VyIFVJIGluIEVwaWNlbnRlciBkaXJlY3RseSBvciBTRlRQaW5nIGZpbGVzIGluLiBJdCBpcyBiYXNlZCBvbiB0aGUgRXBpY2VudGVyIEZpbGUgQVBJLlxuICpcbiAqICAgICAgIHZhciBmYSA9IG5ldyBGLnNlcnZpY2UuRmlsZSh7XG4gKiAgICAgICAgICBhY2NvdW50OiAnYWNtZS1zaW11bGF0aW9ucycsXG4gKiAgICAgICAgICBwcm9qZWN0OiAnc3VwcGx5LWNoYWluLWdhbWUnLFxuICogICAgICAgfSk7XG4gKiAgICAgICBmYS5jcmVhdGUoJ3Rlc3QudHh0JywgJ3RoZXNlIGFyZSBteSBmaWxlY29udGVudHMnKTtcbiAqXG4gKiAgICAgICAvLyBhbHRlcm5hdGl2ZWx5LCBjcmVhdGUgYSBuZXcgZmlsZSB1c2luZyBhIGZpbGUgdXBsb2FkZWQgdGhyb3VnaCBhIGZpbGUgaW5wdXRcbiAqICAgICAgIC8vIDxpbnB1dCBpZD1cImZpbGV1cGxvYWRcIiB0eXBlPVwiZmlsZVwiPlxuICogICAgICAgLy9cbiAqICAgICAgICQoJyNmaWxldXBsb2FkJykub24oJ2NoYW5nZScsIGZ1bmN0aW9uIChlKSB7XG4gKiAgICAgICAgICB2YXIgZmlsZSA9IGUudGFyZ2V0LmZpbGVzWzBdO1xuICogICAgICAgICAgdmFyIGRhdGEgPSBuZXcgRm9ybURhdGEoKTtcbiAqICAgICAgICAgIGRhdGEuYXBwZW5kKCdmaWxlJywgZmlsZSwgZmlsZS5uYW1lKTtcbiAqICAgICAgICAgIGZhLmNyZWF0ZShmaWxlLm5hbWUsIGRhdGEpO1xuICogICAgICAgfSk7XG4gKi9cblxuJ3VzZSBzdHJpY3QnO1xuXG52YXIgQ29uZmlnU2VydmljZSA9IHJlcXVpcmUoJy4vY29uZmlndXJhdGlvbi1zZXJ2aWNlJyk7XG52YXIgVHJhbnNwb3J0RmFjdG9yeSA9IHJlcXVpcmUoJy4uL3RyYW5zcG9ydC9odHRwLXRyYW5zcG9ydC1mYWN0b3J5Jyk7XG52YXIgU2Vzc2lvbk1hbmFnZXIgPSByZXF1aXJlKCcuLi9zdG9yZS9zZXNzaW9uLW1hbmFnZXInKTtcblxubW9kdWxlLmV4cG9ydHMgPSBmdW5jdGlvbiAoY29uZmlnKSB7XG4gICAgdmFyIGRlZmF1bHRzID0ge1xuICAgICAgICAvKipcbiAgICAgICAgICogRm9yIHByb2plY3RzIHRoYXQgcmVxdWlyZSBhdXRoZW50aWNhdGlvbiwgcGFzcyBpbiB0aGUgdXNlciBhY2Nlc3MgdG9rZW4gKGRlZmF1bHRzIHRvIGVtcHR5IHN0cmluZykuIElmIHRoZSB1c2VyIGlzIGFscmVhZHkgbG9nZ2VkIGluIHRvIEVwaWNlbnRlciwgdGhlIHVzZXIgYWNjZXNzIHRva2VuIGlzIGFscmVhZHkgc2V0IGluIGEgY29va2llIGFuZCBhdXRvbWF0aWNhbGx5IGxvYWRlZCBmcm9tIHRoZXJlLiAoU2VlIFttb3JlIGJhY2tncm91bmQgb24gYWNjZXNzIHRva2Vuc10oLi4vLi4vLi4vcHJvamVjdF9hY2Nlc3MvKSkuXG4gICAgICAgICAqIEBzZWUgW0F1dGhlbnRpY2F0aW9uIEFQSSBTZXJ2aWNlXSguLi9hdXRoLWFwaS1zZXJ2aWNlLykgZm9yIGdldHRpbmcgdG9rZW5zLlxuICAgICAgICAgKiBAdHlwZSB7U3RyaW5nfVxuICAgICAgICAgKi9cbiAgICAgICAgdG9rZW46IHVuZGVmaW5lZCxcblxuICAgICAgICAvKipcbiAgICAgICAgICogVGhlIGFjY291bnQgaWQuIEluIHRoZSBFcGljZW50ZXIgVUksIHRoaXMgaXMgdGhlICoqVGVhbSBJRCoqIChmb3IgdGVhbSBwcm9qZWN0cykgb3IgKipVc2VyIElEKiogKGZvciBwZXJzb25hbCBwcm9qZWN0cykuIERlZmF1bHRzIHRvIHVuZGVmaW5lZC5cbiAgICAgICAgICogQHR5cGUge1N0cmluZ31cbiAgICAgICAgICovXG4gICAgICAgIGFjY291bnQ6IHVuZGVmaW5lZCxcblxuICAgICAgICAvKipcbiAgICAgICAgICogVGhlIHByb2plY3QgaWQuIERlZmF1bHRzIHRvIHVuZGVmaW5lZC5cbiAgICAgICAgICogQHR5cGUge1N0cmluZ31cbiAgICAgICAgICovXG4gICAgICAgIHByb2plY3Q6IHVuZGVmaW5lZCxcblxuICAgICAgICAvKipcbiAgICAgICAgICogVGhlIGZvbGRlciB0eXBlLiAgT25lIG9mIGBtb2RlbGAgfCBgc3RhdGljYCB8IGBub2RlYC5cbiAgICAgICAgICogQHR5cGUge1N0cmluZ31cbiAgICAgICAgICovXG4gICAgICAgIGZvbGRlclR5cGU6ICdzdGF0aWMnLFxuXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIE9wdGlvbnMgdG8gcGFzcyBvbiB0byB0aGUgdW5kZXJseWluZyB0cmFuc3BvcnQgbGF5ZXIuIEFsbCBqcXVlcnkuYWpheCBvcHRpb25zIGF0IGh0dHA6Ly9hcGkuanF1ZXJ5LmNvbS9qUXVlcnkuYWpheC8gYXJlIGF2YWlsYWJsZS4gRGVmYXVsdHMgdG8gZW1wdHkgb2JqZWN0LlxuICAgICAgICAgKiBAdHlwZSB7T2JqZWN0fVxuICAgICAgICAgKi9cbiAgICAgICAgdHJhbnNwb3J0OiB7fVxuICAgIH07XG5cbiAgICB0aGlzLnNlc3Npb25NYW5hZ2VyID0gbmV3IFNlc3Npb25NYW5hZ2VyKCk7XG4gICAgdmFyIHNlcnZpY2VPcHRpb25zID0gdGhpcy5zZXNzaW9uTWFuYWdlci5nZXRNZXJnZWRPcHRpb25zKGRlZmF1bHRzLCBjb25maWcpO1xuICAgIHZhciB1cmxDb25maWcgPSBuZXcgQ29uZmlnU2VydmljZShzZXJ2aWNlT3B0aW9ucykuZ2V0KCdzZXJ2ZXInKTtcbiAgICBpZiAoc2VydmljZU9wdGlvbnMuYWNjb3VudCkge1xuICAgICAgICB1cmxDb25maWcuYWNjb3VudFBhdGggPSBzZXJ2aWNlT3B0aW9ucy5hY2NvdW50O1xuICAgIH1cbiAgICBpZiAoc2VydmljZU9wdGlvbnMucHJvamVjdCkge1xuICAgICAgICB1cmxDb25maWcucHJvamVjdFBhdGggPSBzZXJ2aWNlT3B0aW9ucy5wcm9qZWN0O1xuICAgIH1cblxuICAgIHZhciBodHRwT3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LCBzZXJ2aWNlT3B0aW9ucy50cmFuc3BvcnQsIHtcbiAgICAgICAgdXJsOiB1cmxDb25maWcuZ2V0QVBJUGF0aCgnZmlsZScpXG4gICAgfSk7XG5cbiAgICBpZiAoc2VydmljZU9wdGlvbnMudG9rZW4pIHtcbiAgICAgICAgaHR0cE9wdGlvbnMuaGVhZGVycyA9IHtcbiAgICAgICAgICAgIEF1dGhvcml6YXRpb246ICdCZWFyZXIgJyArIHNlcnZpY2VPcHRpb25zLnRva2VuXG4gICAgICAgIH07XG4gICAgfVxuICAgIHZhciBodHRwID0gbmV3IFRyYW5zcG9ydEZhY3RvcnkoaHR0cE9wdGlvbnMpO1xuXG4gICAgZnVuY3Rpb24gdXBsb2FkQm9keShmaWxlTmFtZSwgY29udGVudHMpIHtcbiAgICAgICAgdmFyIGJvdW5kYXJ5ID0gJy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLTdkYTI0ZjJlNTAwNDYnO1xuXG4gICAgICAgIHJldHVybiB7XG4gICAgICAgICAgICBib2R5OiAnLS0nICsgYm91bmRhcnkgKyAnXFxyXFxuJyArXG4gICAgICAgICAgICAgICAgICAgICdDb250ZW50LURpc3Bvc2l0aW9uOiBmb3JtLWRhdGE7IG5hbWU9XCJmaWxlXCI7JyArXG4gICAgICAgICAgICAgICAgICAgICdmaWxlbmFtZT1cIicgKyBmaWxlTmFtZSArICdcIlxcclxcbicgK1xuICAgICAgICAgICAgICAgICAgICAnQ29udGVudC10eXBlOiB0ZXh0L2h0bWxcXHJcXG5cXHJcXG4nICtcbiAgICAgICAgICAgICAgICAgICAgY29udGVudHMgKyAnXFxyXFxuJyArXG4gICAgICAgICAgICAgICAgICAgICctLScgKyBib3VuZGFyeSArICctLScsXG4gICAgICAgICAgICBib3VuZGFyeTogYm91bmRhcnlcbiAgICAgICAgfTtcbiAgICB9XG5cbiAgICBmdW5jdGlvbiB1cGxvYWRGaWxlT3B0aW9ucyhmaWxlUGF0aCwgY29udGVudHMsIG9wdGlvbnMpIHtcbiAgICAgICAgZmlsZVBhdGggPSBmaWxlUGF0aC5zcGxpdCgnLycpO1xuICAgICAgICB2YXIgZmlsZU5hbWUgPSBmaWxlUGF0aC5wb3AoKTtcbiAgICAgICAgZmlsZVBhdGggPSBmaWxlUGF0aC5qb2luKCcvJyk7XG4gICAgICAgIHZhciBwYXRoID0gc2VydmljZU9wdGlvbnMuZm9sZGVyVHlwZSArICcvJyArIGZpbGVQYXRoO1xuXG4gICAgICAgIHZhciBleHRyYVBhcmFtcyA9IHt9O1xuICAgICAgICBpZiAoY29udGVudHMgaW5zdGFuY2VvZiBGb3JtRGF0YSkge1xuICAgICAgICAgICAgZXh0cmFQYXJhbXMgPSB7XG4gICAgICAgICAgICAgICAgZGF0YTogY29udGVudHMsXG4gICAgICAgICAgICAgICAgcHJvY2Vzc0RhdGE6IGZhbHNlLFxuICAgICAgICAgICAgICAgIGNvbnRlbnRUeXBlOiBmYWxzZSxcbiAgICAgICAgICAgIH07XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICB2YXIgdXBsb2FkID0gdXBsb2FkQm9keShmaWxlTmFtZSwgY29udGVudHMpO1xuICAgICAgICAgICAgZXh0cmFQYXJhbXMgPSB7XG4gICAgICAgICAgICAgICAgZGF0YTogdXBsb2FkLmJvZHksXG4gICAgICAgICAgICAgICAgY29udGVudFR5cGU6ICdtdWx0aXBhcnQvZm9ybS1kYXRhOyBib3VuZGFyeT0nICsgdXBsb2FkLmJvdW5kYXJ5XG4gICAgICAgICAgICB9O1xuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuICQuZXh0ZW5kKHRydWUsIHt9LCBzZXJ2aWNlT3B0aW9ucywgb3B0aW9ucywge1xuICAgICAgICAgICAgdXJsOiB1cmxDb25maWcuZ2V0QVBJUGF0aCgnZmlsZScpICsgcGF0aCxcbiAgICAgICAgfSwgZXh0cmFQYXJhbXMpO1xuICAgIH1cblxuICAgIHZhciBwdWJsaWNBc3luY0FQSSA9IHtcbiAgICAgICAgLyoqXG4gICAgICAgICAqIEdldCBhIGRpcmVjdG9yeSBsaXN0aW5nLCBvciBjb250ZW50cyBvZiBhIGZpbGUuXG4gICAgICAgICAqIEBwYXJhbSB7U3RyaW5nfSBmaWxlUGF0aCAgUGF0aCB0byB0aGUgZmlsZVxuICAgICAgICAgKiBAcGFyYW0ge09iamVjdH0gb3B0aW9ucyAoT3B0aW9uYWwpIE92ZXJyaWRlcyBmb3IgY29uZmlndXJhdGlvbiBvcHRpb25zLlxuICAgICAgICAgKiBAcmV0dXJuIHtQcm9taXNlfVxuICAgICAgICAgKi9cbiAgICAgICAgZ2V0Q29udGVudHM6IGZ1bmN0aW9uIChmaWxlUGF0aCwgb3B0aW9ucykge1xuICAgICAgICAgICAgdmFyIHBhdGggPSBzZXJ2aWNlT3B0aW9ucy5mb2xkZXJUeXBlICsgJy8nICsgZmlsZVBhdGg7XG4gICAgICAgICAgICB2YXIgaHR0cE9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSwgc2VydmljZU9wdGlvbnMsIG9wdGlvbnMsIHtcbiAgICAgICAgICAgICAgICB1cmw6IHVybENvbmZpZy5nZXRBUElQYXRoKCdmaWxlJykgKyBwYXRoXG4gICAgICAgICAgICB9KTtcbiAgICAgICAgICAgIHJldHVybiBodHRwLmdldCgnJywgaHR0cE9wdGlvbnMpO1xuICAgICAgICB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBSZXBsYWNlcyB0aGUgZmlsZSBhdCB0aGUgZ2l2ZW4gZmlsZSBwYXRoLlxuICAgICAgICAgKiBAcGFyYW0gIHtTdHJpbmd9IGZpbGVQYXRoIFBhdGggdG8gdGhlIGZpbGVcbiAgICAgICAgICogQHBhcmFtICB7U3RyaW5nIHwgRm9ybURhdGEgfSBjb250ZW50cyBDb250ZW50cyB0byB3cml0ZSB0byBmaWxlXG4gICAgICAgICAqIEBwYXJhbSAge09iamVjdH0gb3B0aW9ucyAgKE9wdGlvbmFsKSBPdmVycmlkZXMgZm9yIGNvbmZpZ3VyYXRpb24gb3B0aW9uc1xuICAgICAgICAgKiBAcmV0dXJuIHtQcm9taXNlfVxuICAgICAgICAgKi9cbiAgICAgICAgcmVwbGFjZTogZnVuY3Rpb24gKGZpbGVQYXRoLCBjb250ZW50cywgb3B0aW9ucykge1xuICAgICAgICAgICAgdmFyIGh0dHBPcHRpb25zID0gdXBsb2FkRmlsZU9wdGlvbnMoZmlsZVBhdGgsIGNvbnRlbnRzLCBvcHRpb25zKTtcbiAgICAgICAgICAgIHJldHVybiBodHRwLnB1dChodHRwT3B0aW9ucy5kYXRhLCBodHRwT3B0aW9ucyk7XG4gICAgICAgIH0sXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIENyZWF0ZXMgYSBmaWxlIGluIHRoZSBnaXZlbiBmaWxlIHBhdGguXG4gICAgICAgICAqIEBwYXJhbSAge1N0cmluZ30gZmlsZVBhdGggUGF0aCB0byB0aGUgZmlsZVxuICAgICAgICAgKiBAcGFyYW0gIHtTdHJpbmcgfCBGb3JtRGF0YSB9IGNvbnRlbnRzIENvbnRlbnRzIHRvIHdyaXRlIHRvIGZpbGVcbiAgICAgICAgICogQHBhcmFtICB7Qm9vbGVhbn0gcmVwbGFjZUV4aXN0aW5nIFJlcGxhY2UgZmlsZSBpZiBpdCBhbHJlYWR5IGV4aXN0czsgZGVmYXVsdHMgdG8gZmFsc2VcbiAgICAgICAgICogQHBhcmFtICB7T2JqZWN0fSBvcHRpb25zIChPcHRpb25hbCkgT3ZlcnJpZGVzIGZvciBjb25maWd1cmF0aW9uIG9wdGlvbnNcbiAgICAgICAgICogQHJldHVybiB7UHJvbWlzZX1cbiAgICAgICAgICovXG4gICAgICAgIGNyZWF0ZTogZnVuY3Rpb24gKGZpbGVQYXRoLCBjb250ZW50cywgcmVwbGFjZUV4aXN0aW5nLCBvcHRpb25zKSB7XG4gICAgICAgICAgICB2YXIgaHR0cE9wdGlvbnMgPSB1cGxvYWRGaWxlT3B0aW9ucyhmaWxlUGF0aCwgY29udGVudHMsIG9wdGlvbnMpO1xuICAgICAgICAgICAgdmFyIHByb20gPSBodHRwLnBvc3QoaHR0cE9wdGlvbnMuZGF0YSwgaHR0cE9wdGlvbnMpO1xuICAgICAgICAgICAgdmFyIG1lID0gdGhpcztcbiAgICAgICAgICAgIGlmIChyZXBsYWNlRXhpc3RpbmcgPT09IHRydWUpIHtcbiAgICAgICAgICAgICAgICBwcm9tID0gcHJvbS50aGVuKG51bGwsIGZ1bmN0aW9uICh4aHIpIHtcbiAgICAgICAgICAgICAgICAgICAgdmFyIGNvbmZsaWN0U3RhdHVzID0gNDA5O1xuICAgICAgICAgICAgICAgICAgICBpZiAoeGhyLnN0YXR1cyA9PT0gY29uZmxpY3RTdGF0dXMpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybiBtZS5yZXBsYWNlKGZpbGVQYXRoLCBjb250ZW50cywgb3B0aW9ucyk7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHJldHVybiBwcm9tO1xuICAgICAgICB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBSZW1vdmVzIHRoZSBmaWxlLlxuICAgICAgICAgKiBAcGFyYW0gIHtTdHJpbmd9IGZpbGVQYXRoIFBhdGggdG8gdGhlIGZpbGVcbiAgICAgICAgICogQHBhcmFtICB7T2JqZWN0fSBvcHRpb25zICAoT3B0aW9uYWwpIE92ZXJyaWRlcyBmb3IgY29uZmlndXJhdGlvbiBvcHRpb25zXG4gICAgICAgICAqIEByZXR1cm4ge1Byb21pc2V9XG4gICAgICAgICAqL1xuICAgICAgICByZW1vdmU6IGZ1bmN0aW9uIChmaWxlUGF0aCwgb3B0aW9ucykge1xuICAgICAgICAgICAgdmFyIHBhdGggPSBzZXJ2aWNlT3B0aW9ucy5mb2xkZXJUeXBlICsgJy8nICsgZmlsZVBhdGg7XG4gICAgICAgICAgICB2YXIgaHR0cE9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSwgc2VydmljZU9wdGlvbnMsIG9wdGlvbnMsIHtcbiAgICAgICAgICAgICAgICB1cmw6IHVybENvbmZpZy5nZXRBUElQYXRoKCdmaWxlJykgKyBwYXRoXG4gICAgICAgICAgICB9KTtcbiAgICAgICAgICAgIHJldHVybiBodHRwLmRlbGV0ZShudWxsLCBodHRwT3B0aW9ucyk7XG4gICAgICAgIH0sXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIFJlbmFtZXMgdGhlIGZpbGUuXG4gICAgICAgICAqIEBwYXJhbSAge1N0cmluZ30gZmlsZVBhdGggUGF0aCB0byB0aGUgZmlsZVxuICAgICAgICAgKiBAcGFyYW0gIHtTdHJpbmd9IG5ld05hbWUgIE5ldyBuYW1lIG9mIGZpbGVcbiAgICAgICAgICogQHBhcmFtICB7T2JqZWN0fSBvcHRpb25zICAoT3B0aW9uYWwpIE92ZXJyaWRlcyBmb3IgY29uZmlndXJhdGlvbiBvcHRpb25zXG4gICAgICAgICAqIEByZXR1cm4ge1Byb21pc2V9XG4gICAgICAgICAqL1xuICAgICAgICByZW5hbWU6IGZ1bmN0aW9uIChmaWxlUGF0aCwgbmV3TmFtZSwgb3B0aW9ucykge1xuICAgICAgICAgICAgdmFyIHBhdGggPSBzZXJ2aWNlT3B0aW9ucy5mb2xkZXJUeXBlICsgJy8nICsgZmlsZVBhdGg7XG4gICAgICAgICAgICB2YXIgaHR0cE9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSwgc2VydmljZU9wdGlvbnMsIG9wdGlvbnMsIHtcbiAgICAgICAgICAgICAgICB1cmw6IHVybENvbmZpZy5nZXRBUElQYXRoKCdmaWxlJykgKyBwYXRoXG4gICAgICAgICAgICB9KTtcbiAgICAgICAgICAgIHJldHVybiBodHRwLnBhdGNoKHsgbmFtZTogbmV3TmFtZSB9LCBodHRwT3B0aW9ucyk7XG4gICAgICAgIH1cbiAgICB9O1xuXG4gICAgJC5leHRlbmQodGhpcywgcHVibGljQXN5bmNBUEkpO1xufTtcbiIsIi8qKlxuICogIyMgQXNzZXQgQVBJIEFkYXB0ZXJcbiAqXG4gKiBUaGUgQXNzZXQgQVBJIEFkYXB0ZXIgYWxsb3dzIHlvdSB0byBzdG9yZSBhc3NldHMgLS0gcmVzb3VyY2VzIG9yIGZpbGVzIG9mIGFueSBraW5kIC0tIHVzZWQgYnkgYSBwcm9qZWN0IHdpdGggYSBzY29wZSB0aGF0IGlzIHNwZWNpZmljIHRvIHByb2plY3QsIGdyb3VwLCBvciBlbmQgdXNlci5cbiAqXG4gKiBBc3NldHMgYXJlIHVzZWQgd2l0aCBbdGVhbSBwcm9qZWN0c10oLi4vLi4vLi4vcHJvamVjdF9hZG1pbi8jdGVhbSkuIE9uZSBjb21tb24gdXNlIGNhc2UgaXMgaGF2aW5nIGVuZCB1c2VycyBpbiBhIFtncm91cF0oLi4vLi4vLi4vZ2xvc3NhcnkvI2dyb3Vwcykgb3IgaW4gYSBbbXVsdGlwbGF5ZXIgd29ybGRdKC4uLy4uLy4uL2dsb3NzYXJ5LyN3b3JsZCkgdXBsb2FkIGRhdGEgLS0gdmlkZW9zIGNyZWF0ZWQgZHVyaW5nIGdhbWUgcGxheSwgcHJvZmlsZSBwaWN0dXJlcyBmb3IgY3VzdG9taXppbmcgdGhlaXIgZXhwZXJpZW5jZSwgZXRjLiAtLSBhcyBwYXJ0IG9mIHBsYXlpbmcgdGhyb3VnaCB0aGUgcHJvamVjdC5cbiAqXG4gKiBSZXNvdXJjZXMgY3JlYXRlZCB1c2luZyB0aGUgQXNzZXQgQWRhcHRlciBhcmUgc2NvcGVkOlxuICpcbiAqICAqIFByb2plY3QgYXNzZXRzIGFyZSB3cml0YWJsZSBvbmx5IGJ5IFt0ZWFtIG1lbWJlcnNdKC4uLy4uLy4uL2dsb3NzYXJ5LyN0ZWFtKSwgdGhhdCBpcywgRXBpY2VudGVyIGF1dGhvcnMuXG4gKiAgKiBHcm91cCBhc3NldHMgYXJlIHdyaXRhYmxlIGJ5IGFueW9uZSB3aXRoIGFjY2VzcyB0byB0aGUgcHJvamVjdCB0aGF0IGlzIHBhcnQgb2YgdGhhdCBwYXJ0aWN1bGFyIFtncm91cF0oLi4vLi4vLi4vZ2xvc3NhcnkvI2dyb3VwcykuIFRoaXMgaW5jbHVkZXMgYWxsIFt0ZWFtIG1lbWJlcnNdKC4uLy4uLy4uL2dsb3NzYXJ5LyN0ZWFtKSAoRXBpY2VudGVyIGF1dGhvcnMpIGFuZCBhbnkgW2VuZCB1c2Vyc10oLi4vLi4vLi4vZ2xvc3NhcnkvI3VzZXJzKSB3aG8gYXJlIG1lbWJlcnMgb2YgdGhlIGdyb3VwIC0tIGJvdGggZmFjaWxpdGF0b3JzIGFuZCBzdGFuZGFyZCBlbmQgdXNlcnMuXG4gKiAgKiBVc2VyIGFzc2V0cyBhcmUgd3JpdGFibGUgYnkgdGhlIHNwZWNpZmljIGVuZCB1c2VyLCBhbmQgYnkgdGhlIGZhY2lsaXRhdG9yIG9mIHRoZSBncm91cC5cbiAqICAqIEFsbCBhc3NldHMgYXJlIHJlYWRhYmxlIGJ5IGFueW9uZSB3aXRoIHRoZSBleGFjdCBVUkkuXG4gKlxuICogVG8gdXNlIHRoZSBBc3NldCBBZGFwdGVyLCBpbnN0YW50aWF0ZSBpdCBhbmQgdGhlbiBhY2Nlc3MgdGhlIG1ldGhvZHMgcHJvdmlkZWQuIEluc3RhbnRpYXRpbmcgcmVxdWlyZXMgdGhlIGFjY291bnQgaWQgKCoqVGVhbSBJRCoqIGluIHRoZSBFcGljZW50ZXIgdXNlciBpbnRlcmZhY2UpIGFuZCBwcm9qZWN0IGlkICgqKlByb2plY3QgSUQqKikuIFRoZSBncm91cCBuYW1lIGlzIHJlcXVpcmVkIGZvciBhc3NldHMgd2l0aCBhIGdyb3VwIHNjb3BlLCBhbmQgdGhlIGdyb3VwIG5hbWUgYW5kIHVzZXJJZCBhcmUgcmVxdWlyZWQgZm9yIGFzc2V0cyB3aXRoIGEgdXNlciBzY29wZS4gSWYgbm90IGluY2x1ZGVkLCB0aGV5IGFyZSB0YWtlbiBmcm9tIHRoZSBsb2dnZWQgaW4gdXNlcidzIHNlc3Npb24gaW5mb3JtYXRpb24gaWYgbmVlZGVkLlxuICpcbiAqIFdoZW4gY3JlYXRpbmcgYW4gYXNzZXQsIHlvdSBjYW4gcGFzcyBpbiB0ZXh0IChlbmNvZGVkIGRhdGEpIHRvIHRoZSBgY3JlYXRlKClgIGNhbGwuIEFsdGVybmF0aXZlbHksIHlvdSBjYW4gbWFrZSB0aGUgYGNyZWF0ZSgpYCBjYWxsIGFzIHBhcnQgb2YgYW4gSFRNTCBmb3JtIGFuZCBwYXNzIGluIGEgZmlsZSB1cGxvYWRlZCB2aWEgdGhlIGZvcm0uXG4gKlxuICogICAgICAgLy8gaW5zdGFudGlhdGUgdGhlIEFzc2V0IEFkYXB0ZXJcbiAqICAgICAgIHZhciBhYSA9IG5ldyBGLnNlcnZpY2UuQXNzZXQoe1xuICogICAgICAgICAgYWNjb3VudDogJ2FjbWUtc2ltdWxhdGlvbnMnLFxuICogICAgICAgICAgcHJvamVjdDogJ3N1cHBseS1jaGFpbi1nYW1lJyxcbiAqICAgICAgICAgIGdyb3VwOiAndGVhbTEnLFxuICogICAgICAgICAgdXNlcklkOiAnMTIzNDUnXG4gKiAgICAgICB9KTtcbiAqXG4gKiAgICAgICAvLyBjcmVhdGUgYSBuZXcgYXNzZXQgdXNpbmcgZW5jb2RlZCB0ZXh0XG4gKiAgICAgICBhYS5jcmVhdGUoJ3Rlc3QudHh0Jywge1xuICogICAgICAgICAgIGVuY29kaW5nOiAnQkFTRV82NCcsXG4gKiAgICAgICAgICAgZGF0YTogJ1ZHaHBjeUJwY3lCaElIUmxjM1FnWm1sc1pTND0nLFxuICogICAgICAgICAgIGNvbnRlbnRUeXBlOiAndGV4dC9wbGFpbidcbiAqICAgICAgIH0sIHsgc2NvcGU6ICd1c2VyJyB9KTtcbiAqXG4gKiAgICAgICAvLyBhbHRlcm5hdGl2ZWx5LCBjcmVhdGUgYSBuZXcgYXNzZXQgdXNpbmcgYSBmaWxlIHVwbG9hZGVkIHRocm91Z2ggYSBmb3JtXG4gKiAgICAgICAvLyB0aGlzIHNhbXBsZSBjb2RlIGdvZXMgd2l0aCBhbiBodG1sIGZvcm0gdGhhdCBsb29rcyBsaWtlIHRoaXM6XG4gKiAgICAgICAvL1xuICogICAgICAgLy8gPGZvcm0gaWQ9XCJ1cGxvYWQtZmlsZVwiPlxuICogICAgICAgLy8gICA8aW5wdXQgaWQ9XCJmaWxlXCIgdHlwZT1cImZpbGVcIj5cbiAqICAgICAgIC8vICAgPGlucHV0IGlkPVwiZmlsZW5hbWVcIiB0eXBlPVwidGV4dFwiIHZhbHVlPVwibXlGaWxlLnR4dFwiPlxuICogICAgICAgLy8gICA8YnV0dG9uIHR5cGU9XCJzdWJtaXRcIj5VcGxvYWQgbXlGaWxlPC9idXR0b24+XG4gKiAgICAgICAvLyA8L2Zvcm0+XG4gKiAgICAgICAvL1xuICogICAgICAgJCgnI3VwbG9hZC1maWxlJykub24oJ3N1Ym1pdCcsIGZ1bmN0aW9uIChlKSB7XG4gKiAgICAgICAgICBlLnByZXZlbnREZWZhdWx0KCk7XG4gKiAgICAgICAgICB2YXIgZmlsZW5hbWUgPSAkKCcjZmlsZW5hbWUnKS52YWwoKTtcbiAqICAgICAgICAgIHZhciBkYXRhID0gbmV3IEZvcm1EYXRhKCk7XG4gKiAgICAgICAgICB2YXIgaW5wdXRDb250cm9sID0gJCgnI2ZpbGUnKVswXTtcbiAqICAgICAgICAgIGRhdGEuYXBwZW5kKCdmaWxlJywgaW5wdXRDb250cm9sLmZpbGVzWzBdLCBmaWxlbmFtZSk7XG4gKlxuICogICAgICAgICAgYWEuY3JlYXRlKGZpbGVuYW1lLCBkYXRhLCB7IHNjb3BlOiAndXNlcicgfSk7XG4gKiAgICAgICB9KTtcbiAqXG4gKi9cblxuJ3VzZSBzdHJpY3QnO1xuXG52YXIgQ29uZmlnU2VydmljZSA9IHJlcXVpcmUoJy4vY29uZmlndXJhdGlvbi1zZXJ2aWNlJyk7XG52YXIgVHJhbnNwb3J0RmFjdG9yeSA9IHJlcXVpcmUoJy4uL3RyYW5zcG9ydC9odHRwLXRyYW5zcG9ydC1mYWN0b3J5Jyk7XG52YXIgX3BpY2sgPSByZXF1aXJlKCcuLi91dGlsL29iamVjdC11dGlsJykuX3BpY2s7XG52YXIgU2Vzc2lvbk1hbmFnZXIgPSByZXF1aXJlKCcuLi9zdG9yZS9zZXNzaW9uLW1hbmFnZXInKTtcblxudmFyIGFwaUVuZHBvaW50ID0gJ2Fzc2V0JztcblxubW9kdWxlLmV4cG9ydHMgPSBmdW5jdGlvbiAoY29uZmlnKSB7XG4gICAgdmFyIGRlZmF1bHRzID0ge1xuICAgICAgICAvKipcbiAgICAgICAgICogRm9yIHByb2plY3RzIHRoYXQgcmVxdWlyZSBhdXRoZW50aWNhdGlvbiwgcGFzcyBpbiB0aGUgdXNlciBhY2Nlc3MgdG9rZW4gKGRlZmF1bHRzIHRvIGVtcHR5IHN0cmluZykuIElmIHRoZSB1c2VyIGlzIGFscmVhZHkgbG9nZ2VkIGluIHRvIEVwaWNlbnRlciwgdGhlIHVzZXIgYWNjZXNzIHRva2VuIGlzIGFscmVhZHkgc2V0IGluIGEgY29va2llIGFuZCBhdXRvbWF0aWNhbGx5IGxvYWRlZCBmcm9tIHRoZXJlLiAoU2VlIFttb3JlIGJhY2tncm91bmQgb24gYWNjZXNzIHRva2Vuc10oLi4vLi4vLi4vcHJvamVjdF9hY2Nlc3MvKSkuXG4gICAgICAgICAqIEBzZWUgW0F1dGhlbnRpY2F0aW9uIEFQSSBTZXJ2aWNlXSguLi9hdXRoLWFwaS1zZXJ2aWNlLykgZm9yIGdldHRpbmcgdG9rZW5zLlxuICAgICAgICAgKiBAdHlwZSB7U3RyaW5nfVxuICAgICAgICAgKi9cbiAgICAgICAgdG9rZW46IHVuZGVmaW5lZCxcbiAgICAgICAgLyoqXG4gICAgICAgICAqIFRoZSBhY2NvdW50IGlkLiBJbiB0aGUgRXBpY2VudGVyIFVJLCB0aGlzIGlzIHRoZSAqKlRlYW0gSUQqKiAoZm9yIHRlYW0gcHJvamVjdHMpLiBJZiBsZWZ0IHVuZGVmaW5lZCwgdGFrZW4gZnJvbSB0aGUgVVJMLlxuICAgICAgICAgKiBAdHlwZSB7U3RyaW5nfVxuICAgICAgICAgKi9cbiAgICAgICAgYWNjb3VudDogdW5kZWZpbmVkLFxuICAgICAgICAvKipcbiAgICAgICAgICogVGhlIHByb2plY3QgaWQuIElmIGxlZnQgdW5kZWZpbmVkLCB0YWtlbiBmcm9tIHRoZSBVUkwuXG4gICAgICAgICAqIEB0eXBlIHtTdHJpbmd9XG4gICAgICAgICAqL1xuICAgICAgICBwcm9qZWN0OiB1bmRlZmluZWQsXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBUaGUgZ3JvdXAgbmFtZS4gRGVmYXVsdHMgdG8gc2Vzc2lvbidzIGBncm91cE5hbWVgLlxuICAgICAgICAgKiBAdHlwZSB7U3RyaW5nfVxuICAgICAgICAgKi9cbiAgICAgICAgZ3JvdXA6IHVuZGVmaW5lZCxcbiAgICAgICAgLyoqXG4gICAgICAgICAqIFRoZSB1c2VyIGlkLiBEZWZhdWx0cyB0byBzZXNzaW9uJ3MgYHVzZXJJZGAuXG4gICAgICAgICAqIEB0eXBlIHtTdHJpbmd9XG4gICAgICAgICAqL1xuICAgICAgICB1c2VySWQ6IHVuZGVmaW5lZCxcbiAgICAgICAgLyoqXG4gICAgICAgICAqIFRoZSBzY29wZSBmb3IgdGhlIGFzc2V0LiBWYWxpZCB2YWx1ZXMgYXJlOiBgdXNlcmAsIGBncm91cGAsIGFuZCBgcHJvamVjdGAuIFNlZSBhYm92ZSBmb3IgdGhlIHJlcXVpcmVkIHBlcm1pc3Npb25zIHRvIHdyaXRlIHRvIGVhY2ggc2NvcGUuIERlZmF1bHRzIHRvIGB1c2VyYCwgbWVhbmluZyB0aGUgY3VycmVudCBlbmQgdXNlciBvciBhIGZhY2lsaXRhdG9yIGluIHRoZSBlbmQgdXNlcidzIGdyb3VwIGNhbiBlZGl0IHRoZSBhc3NldC5cbiAgICAgICAgICogQHR5cGUge1N0cmluZ31cbiAgICAgICAgICovXG4gICAgICAgIHNjb3BlOiAndXNlcicsXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBEZXRlcm1pbmVzIGlmIGEgcmVxdWVzdCB0byBsaXN0IHRoZSBhc3NldHMgaW4gYSBzY29wZSBpbmNsdWRlcyB0aGUgY29tcGxldGUgVVJMIGZvciBlYWNoIGFzc2V0IChgdHJ1ZWApLCBvciBvbmx5IHRoZSBmaWxlIG5hbWVzIG9mIHRoZSBhc3NldHMgKGBmYWxzZWApLiBEZWZhdWx0cyB0byBgdHJ1ZWAuXG4gICAgICAgICAqIEB0eXBlIHtib29sZWFufVxuICAgICAgICAgKi9cbiAgICAgICAgZnVsbFVybDogdHJ1ZSxcbiAgICAgICAgLyoqXG4gICAgICAgICAqIFRoZSB0cmFuc3BvcnQgb2JqZWN0IGNvbnRhaW5zIHRoZSBvcHRpb25zIHBhc3NlZCB0byB0aGUgWEhSIHJlcXVlc3QuXG4gICAgICAgICAqIEB0eXBlIHtvYmplY3R9XG4gICAgICAgICAqL1xuICAgICAgICB0cmFuc3BvcnQ6IHtcbiAgICAgICAgICAgIHByb2Nlc3NEYXRhOiBmYWxzZVxuICAgICAgICB9XG4gICAgfTtcbiAgICB0aGlzLnNlc3Npb25NYW5hZ2VyID0gbmV3IFNlc3Npb25NYW5hZ2VyKCk7XG4gICAgdmFyIHNlcnZpY2VPcHRpb25zID0gdGhpcy5zZXNzaW9uTWFuYWdlci5nZXRNZXJnZWRPcHRpb25zKGRlZmF1bHRzLCBjb25maWcpO1xuICAgIHZhciB1cmxDb25maWcgPSBuZXcgQ29uZmlnU2VydmljZShzZXJ2aWNlT3B0aW9ucykuZ2V0KCdzZXJ2ZXInKTtcblxuICAgIGlmICghc2VydmljZU9wdGlvbnMuYWNjb3VudCkge1xuICAgICAgICBzZXJ2aWNlT3B0aW9ucy5hY2NvdW50ID0gdXJsQ29uZmlnLmFjY291bnRQYXRoO1xuICAgIH1cblxuICAgIGlmICghc2VydmljZU9wdGlvbnMucHJvamVjdCkge1xuICAgICAgICBzZXJ2aWNlT3B0aW9ucy5wcm9qZWN0ID0gdXJsQ29uZmlnLnByb2plY3RQYXRoO1xuICAgIH1cblxuICAgIHZhciB0cmFuc3BvcnRPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sIHNlcnZpY2VPcHRpb25zLnRyYW5zcG9ydCwge1xuICAgICAgICB1cmw6IHVybENvbmZpZy5nZXRBUElQYXRoKGFwaUVuZHBvaW50KVxuICAgIH0pO1xuXG4gICAgaWYgKHNlcnZpY2VPcHRpb25zLnRva2VuKSB7XG4gICAgICAgIHRyYW5zcG9ydE9wdGlvbnMuaGVhZGVycyA9IHtcbiAgICAgICAgICAgIEF1dGhvcml6YXRpb246ICdCZWFyZXIgJyArIHNlcnZpY2VPcHRpb25zLnRva2VuXG4gICAgICAgIH07XG4gICAgfVxuXG4gICAgdmFyIGh0dHAgPSBuZXcgVHJhbnNwb3J0RmFjdG9yeSh0cmFuc3BvcnRPcHRpb25zKTtcblxuICAgIHZhciBhc3NldEFwaVBhcmFtcyA9IFsnZW5jb2RpbmcnLCAnZGF0YScsICdjb250ZW50VHlwZSddO1xuICAgIHZhciBzY29wZUNvbmZpZyA9IHtcbiAgICAgICAgdXNlcjogWydzY29wZScsICdhY2NvdW50JywgJ3Byb2plY3QnLCAnZ3JvdXAnLCAndXNlcklkJ10sXG4gICAgICAgIGdyb3VwOiBbJ3Njb3BlJywgJ2FjY291bnQnLCAncHJvamVjdCcsICdncm91cCddLFxuICAgICAgICBwcm9qZWN0OiBbJ3Njb3BlJywgJ2FjY291bnQnLCAncHJvamVjdCddLFxuICAgIH07XG5cbiAgICB2YXIgdmFsaWRhdGVGaWxlbmFtZSA9IGZ1bmN0aW9uIChmaWxlbmFtZSkge1xuICAgICAgICBpZiAoIWZpbGVuYW1lKSB7XG4gICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ2ZpbGVuYW1lIGlzIG5lZWRlZC4nKTtcbiAgICAgICAgfVxuICAgIH07XG5cbiAgICB2YXIgdmFsaWRhdGVVcmxQYXJhbXMgPSBmdW5jdGlvbiAob3B0aW9ucykge1xuICAgICAgICB2YXIgcGFydEtleXMgPSBzY29wZUNvbmZpZ1tvcHRpb25zLnNjb3BlXTtcbiAgICAgICAgaWYgKCFwYXJ0S2V5cykge1xuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdzY29wZSBwYXJhbWV0ZXIgaXMgbmVlZGVkLicpO1xuICAgICAgICB9XG5cbiAgICAgICAgJC5lYWNoKHBhcnRLZXlzLCBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICBpZiAoIW9wdGlvbnNbdGhpc10pIHtcbiAgICAgICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IodGhpcyArICcgcGFyYW1ldGVyIGlzIG5lZWRlZC4nKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfSk7XG4gICAgfTtcblxuICAgIHZhciBidWlsZFVybCA9IGZ1bmN0aW9uIChmaWxlbmFtZSwgb3B0aW9ucykge1xuICAgICAgICB2YWxpZGF0ZVVybFBhcmFtcyhvcHRpb25zKTtcbiAgICAgICAgdmFyIHBhcnRLZXlzID0gc2NvcGVDb25maWdbb3B0aW9ucy5zY29wZV07XG4gICAgICAgIHZhciBwYXJ0cyA9ICQubWFwKHBhcnRLZXlzLCBmdW5jdGlvbiAoa2V5KSB7XG4gICAgICAgICAgICByZXR1cm4gb3B0aW9uc1trZXldO1xuICAgICAgICB9KTtcbiAgICAgICAgaWYgKGZpbGVuYW1lKSB7XG4gICAgICAgICAgICAvLyBUaGlzIHByZXZlbnRzIGFkZGluZyBhIHRyYWlsaW5nIC8gaW4gdGhlIFVSTCBhcyB0aGUgQXNzZXQgQVBJXG4gICAgICAgICAgICAvLyBkb2VzIG5vdCB3b3JrIGNvcnJlY3RseSB3aXRoIGl0XG4gICAgICAgICAgICBmaWxlbmFtZSA9ICcvJyArIGZpbGVuYW1lO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiB1cmxDb25maWcuZ2V0QVBJUGF0aChhcGlFbmRwb2ludCkgKyBwYXJ0cy5qb2luKCcvJykgKyBmaWxlbmFtZTtcbiAgICB9O1xuXG4gICAgLy8gUHJpdmF0ZSBmdW5jdGlvbiwgYWxsIHJlcXVlc3RzIGZvbGxvdyBhIG1vcmUgb3IgbGVzcyBzYW1lIGFwcHJvYWNoIHRvXG4gICAgLy8gdXNlIHRoZSBBc3NldCBBUEkgYW5kIHRoZSBkaWZmZXJlbmNlIGlzIHRoZSBIVFRQIHZlcmJcbiAgICAvL1xuICAgIC8vIEBwYXJhbSB7c3RyaW5nfSBtZXRob2RgIChSZXF1aXJlZCkgSFRUUCB2ZXJiXG4gICAgLy8gQHBhcmFtIHtzdHJpbmd9IGZpbGVuYW1lYCAoUmVxdWlyZWQpIE5hbWUgb2YgdGhlIGZpbGUgdG8gZGVsZXRlL3JlcGxhY2UvY3JlYXRlXG4gICAgLy8gQHBhcmFtIHtvYmplY3R9IHBhcmFtc2AgKE9wdGlvbmFsKSBCb2R5IHBhcmFtZXRlcnMgdG8gc2VuZCB0byB0aGUgQXNzZXQgQVBJXG4gICAgLy8gQHBhcmFtIHtvYmplY3R9IG9wdGlvbnNgIChPcHRpb25hbCkgT3B0aW9ucyBvYmplY3QgdG8gb3ZlcnJpZGUgZ2xvYmFsIG9wdGlvbnMuXG4gICAgdmFyIHVwbG9hZCA9IGZ1bmN0aW9uIChtZXRob2QsIGZpbGVuYW1lLCBwYXJhbXMsIG9wdGlvbnMpIHtcbiAgICAgICAgdmFsaWRhdGVGaWxlbmFtZShmaWxlbmFtZSk7XG4gICAgICAgIC8vIG1ha2Ugc3VyZSB0aGUgcGFyYW1ldGVyIGlzIGNsZWFuXG4gICAgICAgIG1ldGhvZCA9IG1ldGhvZC50b0xvd2VyQ2FzZSgpO1xuICAgICAgICB2YXIgY29udGVudFR5cGUgPSBwYXJhbXMgaW5zdGFuY2VvZiBGb3JtRGF0YSA9PT0gdHJ1ZSA/IGZhbHNlIDogJ2FwcGxpY2F0aW9uL2pzb24nO1xuICAgICAgICBpZiAoY29udGVudFR5cGUgPT09ICdhcHBsaWNhdGlvbi9qc29uJykge1xuICAgICAgICAgICAgLy8gd2hpdGVsaXN0IHRoZSBmaWVsZHMgdGhhdCB3ZSBhY3R1YWxseSBjYW4gc2VuZCB0byB0aGUgYXBpXG4gICAgICAgICAgICBwYXJhbXMgPSBfcGljayhwYXJhbXMsIGFzc2V0QXBpUGFyYW1zKTtcbiAgICAgICAgfSBlbHNlIHsgLy8gZWxzZSB3ZSdyZSBzZW5kaW5nIGZvcm0gZGF0YSB3aGljaCBnb2VzIGRpcmVjdGx5IGluIHJlcXVlc3QgYm9keVxuICAgICAgICAgICAgLy8gRm9yIG11bHRpcGFydC9mb3JtLWRhdGEgdXBsb2FkcyB0aGUgZmlsZW5hbWUgaXMgbm90IHNldCBpbiB0aGUgVVJMLFxuICAgICAgICAgICAgLy8gaXQncyBnZXR0aW5nIHBpY2tlZCBieSB0aGUgRm9ybURhdGEgZmllbGQgZmlsZW5hbWUuXG4gICAgICAgICAgICBmaWxlbmFtZSA9IG1ldGhvZCA9PT0gJ3Bvc3QnIHx8IG1ldGhvZCA9PT0gJ3B1dCcgPyAnJyA6IGZpbGVuYW1lO1xuICAgICAgICB9XG4gICAgICAgIHZhciB1cmxPcHRpb25zID0gJC5leHRlbmQoe30sIHNlcnZpY2VPcHRpb25zLCBvcHRpb25zKTtcbiAgICAgICAgdmFyIHVybCA9IGJ1aWxkVXJsKGZpbGVuYW1lLCB1cmxPcHRpb25zKTtcbiAgICAgICAgdmFyIGNyZWF0ZU9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSwgdXJsT3B0aW9ucywgeyB1cmw6IHVybCwgY29udGVudFR5cGU6IGNvbnRlbnRUeXBlIH0pO1xuXG4gICAgICAgIHJldHVybiBodHRwW21ldGhvZF0ocGFyYW1zLCBjcmVhdGVPcHRpb25zKTtcbiAgICB9O1xuXG4gICAgdmFyIHB1YmxpY0FQSSA9IHtcbiAgICAgICAgLyoqXG4gICAgICAgICogQ3JlYXRlcyBhIGZpbGUgaW4gdGhlIEFzc2V0IEFQSS4gVGhlIHNlcnZlciByZXR1cm5zIGFuIGVycm9yIChzdGF0dXMgY29kZSBgNDA5YCwgY29uZmxpY3QpIGlmIHRoZSBmaWxlIGFscmVhZHkgZXhpc3RzLCBzb1xuICAgICAgICAqIGNoZWNrIGZpcnN0IHdpdGggYSBgbGlzdCgpYCBvciBhIGBnZXQoKWAuXG4gICAgICAgICpcbiAgICAgICAgKiAgKipFeGFtcGxlKipcbiAgICAgICAgKlxuICAgICAgICAqICAgICAgIHZhciBhYSA9IG5ldyBGLnNlcnZpY2UuQXNzZXQoe1xuICAgICAgICAqICAgICAgICAgIGFjY291bnQ6ICdhY21lLXNpbXVsYXRpb25zJyxcbiAgICAgICAgKiAgICAgICAgICBwcm9qZWN0OiAnc3VwcGx5LWNoYWluLWdhbWUnLFxuICAgICAgICAqICAgICAgICAgIGdyb3VwOiAndGVhbTEnLFxuICAgICAgICAqICAgICAgICAgIHVzZXJJZDogJydcbiAgICAgICAgKiAgICAgICB9KTtcbiAgICAgICAgKlxuICAgICAgICAqICAgICAgIC8vIGNyZWF0ZSBhIG5ldyBhc3NldCB1c2luZyBlbmNvZGVkIHRleHRcbiAgICAgICAgKiAgICAgICBhYS5jcmVhdGUoJ3Rlc3QudHh0Jywge1xuICAgICAgICAqICAgICAgICAgICBlbmNvZGluZzogJ0JBU0VfNjQnLFxuICAgICAgICAqICAgICAgICAgICBkYXRhOiAnVkdocGN5QnBjeUJoSUhSbGMzUWdabWxzWlM0PScsXG4gICAgICAgICogICAgICAgICAgIGNvbnRlbnRUeXBlOiAndGV4dC9wbGFpbidcbiAgICAgICAgKiAgICAgICB9LCB7IHNjb3BlOiAndXNlcicgfSk7XG4gICAgICAgICpcbiAgICAgICAgKiAgICAgICAvLyBhbHRlcm5hdGl2ZWx5LCBjcmVhdGUgYSBuZXcgYXNzZXQgdXNpbmcgYSBmaWxlIHVwbG9hZGVkIHRocm91Z2ggYSBmb3JtXG4gICAgICAgICogICAgICAgLy8gdGhpcyBzYW1wbGUgY29kZSBnb2VzIHdpdGggYW4gaHRtbCBmb3JtIHRoYXQgbG9va3MgbGlrZSB0aGlzOlxuICAgICAgICAqICAgICAgIC8vXG4gICAgICAgICogICAgICAgLy8gPGZvcm0gaWQ9XCJ1cGxvYWQtZmlsZVwiPlxuICAgICAgICAqICAgICAgIC8vICAgPGlucHV0IGlkPVwiZmlsZVwiIHR5cGU9XCJmaWxlXCI+XG4gICAgICAgICogICAgICAgLy8gICA8aW5wdXQgaWQ9XCJmaWxlbmFtZVwiIHR5cGU9XCJ0ZXh0XCIgdmFsdWU9XCJteUZpbGUudHh0XCI+XG4gICAgICAgICogICAgICAgLy8gICA8YnV0dG9uIHR5cGU9XCJzdWJtaXRcIj5VcGxvYWQgbXlGaWxlPC9idXR0b24+XG4gICAgICAgICogICAgICAgLy8gPC9mb3JtPlxuICAgICAgICAqICAgICAgIC8vXG4gICAgICAgICogICAgICAgJCgnI3VwbG9hZC1maWxlJykub24oJ3N1Ym1pdCcsIGZ1bmN0aW9uIChlKSB7XG4gICAgICAgICogICAgICAgICAgZS5wcmV2ZW50RGVmYXVsdCgpO1xuICAgICAgICAqICAgICAgICAgIHZhciBmaWxlbmFtZSA9ICQoJyNmaWxlbmFtZScpLnZhbCgpO1xuICAgICAgICAqICAgICAgICAgIHZhciBkYXRhID0gbmV3IEZvcm1EYXRhKCk7XG4gICAgICAgICogICAgICAgICAgdmFyIGlucHV0Q29udHJvbCA9ICQoJyNmaWxlJylbMF07XG4gICAgICAgICogICAgICAgICAgZGF0YS5hcHBlbmQoJ2ZpbGUnLCBpbnB1dENvbnRyb2wuZmlsZXNbMF0sIGZpbGVuYW1lKTtcbiAgICAgICAgKlxuICAgICAgICAqICAgICAgICAgIGFhLmNyZWF0ZShmaWxlbmFtZSwgZGF0YSwgeyBzY29wZTogJ3VzZXInIH0pO1xuICAgICAgICAqICAgICAgIH0pO1xuICAgICAgICAqXG4gICAgICAgICpcbiAgICAgICAgKiAgKipQYXJhbWV0ZXJzKipcbiAgICAgICAgKiBAcGFyYW0ge3N0cmluZ30gZmlsZW5hbWUgKFJlcXVpcmVkKSBOYW1lIG9mIHRoZSBmaWxlIHRvIGNyZWF0ZS5cbiAgICAgICAgKiBAcGFyYW0ge29iamVjdH0gcGFyYW1zIChPcHRpb25hbCkgQm9keSBwYXJhbWV0ZXJzIHRvIHNlbmQgdG8gdGhlIEFzc2V0IEFQSS4gUmVxdWlyZWQgaWYgdGhlIGBvcHRpb25zLnRyYW5zcG9ydC5jb250ZW50VHlwZWAgaXMgYGFwcGxpY2F0aW9uL2pzb25gLCBvdGhlcndpc2UgaWdub3JlZC5cbiAgICAgICAgKiBAcGFyYW0ge3N0cmluZ30gcGFyYW1zLmVuY29kaW5nIEVpdGhlciBgSEVYYCBvciBgQkFTRV82NGAuIFJlcXVpcmVkIGlmIGBvcHRpb25zLnRyYW5zcG9ydC5jb250ZW50VHlwZWAgaXMgYGFwcGxpY2F0aW9uL2pzb25gLlxuICAgICAgICAqIEBwYXJhbSB7c3RyaW5nfSBwYXJhbXMuZGF0YSBUaGUgZW5jb2RlZCBkYXRhIGZvciB0aGUgZmlsZS4gUmVxdWlyZWQgaWYgYG9wdGlvbnMudHJhbnNwb3J0LmNvbnRlbnRUeXBlYCBpcyBgYXBwbGljYXRpb24vanNvbmAuXG4gICAgICAgICogQHBhcmFtIHtzdHJpbmd9IHBhcmFtcy5jb250ZW50VHlwZSBUaGUgbWltZSB0eXBlIG9mIHRoZSBmaWxlLiBPcHRpb25hbC5cbiAgICAgICAgKiBAcGFyYW0ge29iamVjdH0gb3B0aW9ucyAoT3B0aW9uYWwpIE9wdGlvbnMgb2JqZWN0IHRvIG92ZXJyaWRlIGdsb2JhbCBvcHRpb25zLlxuICAgICAgICAqIEByZXR1cm4ge1Byb21pc2V9XG4gICAgICAgICovXG4gICAgICAgIGNyZWF0ZTogZnVuY3Rpb24gKGZpbGVuYW1lLCBwYXJhbXMsIG9wdGlvbnMpIHtcbiAgICAgICAgICAgIHJldHVybiB1cGxvYWQoJ3Bvc3QnLCBmaWxlbmFtZSwgcGFyYW1zLCBvcHRpb25zKTtcbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgKiBHZXRzIGEgZmlsZSBmcm9tIHRoZSBBc3NldCBBUEksIGZldGNoaW5nIHRoZSBhc3NldCBjb250ZW50LiAoVG8gZ2V0IGEgbGlzdFxuICAgICAgICAqIG9mIHRoZSBhc3NldHMgaW4gYSBzY29wZSwgdXNlIGBsaXN0KClgLilcbiAgICAgICAgKlxuICAgICAgICAqICAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAqIEBwYXJhbSB7c3RyaW5nfSBmaWxlbmFtZSAoUmVxdWlyZWQpIE5hbWUgb2YgdGhlIGZpbGUgdG8gcmV0cmlldmUuXG4gICAgICAgICogQHBhcmFtIHtvYmplY3R9IG9wdGlvbnMgKE9wdGlvbmFsKSBPcHRpb25zIG9iamVjdCB0byBvdmVycmlkZSBnbG9iYWwgb3B0aW9ucy5cbiAgICAgICAgKiBAcmV0dXJuIHtQcm9taXNlfVxuICAgICAgICAqL1xuICAgICAgICBnZXQ6IGZ1bmN0aW9uIChmaWxlbmFtZSwgb3B0aW9ucykge1xuICAgICAgICAgICAgdmFyIGdldFNlcnZpY2VPcHRpb25zID0gX3BpY2soc2VydmljZU9wdGlvbnMsIFsnc2NvcGUnLCAnYWNjb3VudCcsICdwcm9qZWN0JywgJ2dyb3VwJywgJ3VzZXJJZCddKTtcbiAgICAgICAgICAgIHZhciB1cmxPcHRpb25zID0gJC5leHRlbmQoe30sIGdldFNlcnZpY2VPcHRpb25zLCBvcHRpb25zKTtcbiAgICAgICAgICAgIHZhciB1cmwgPSBidWlsZFVybChmaWxlbmFtZSwgdXJsT3B0aW9ucyk7XG4gICAgICAgICAgICB2YXIgZ2V0T3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LCB1cmxPcHRpb25zLCB7IHVybDogdXJsIH0pO1xuXG4gICAgICAgICAgICByZXR1cm4gaHR0cC5nZXQoe30sIGdldE9wdGlvbnMpO1xuICAgICAgICB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAqIEdldHMgdGhlIGxpc3Qgb2YgdGhlIGFzc2V0cyBpbiBhIHNjb3BlLlxuICAgICAgICAqXG4gICAgICAgICogKipFeGFtcGxlKipcbiAgICAgICAgKlxuICAgICAgICAqICAgICAgIGFhLmxpc3QoeyBmdWxsVXJsOiB0cnVlIH0pLnRoZW4oZnVuY3Rpb24oZmlsZUxpc3Qpe1xuICAgICAgICAqICAgICAgICAgICBjb25zb2xlLmxvZygnYXJyYXkgb2YgZmlsZXMgPSAnLCBmaWxlTGlzdCk7XG4gICAgICAgICogICAgICAgfSk7XG4gICAgICAgICpcbiAgICAgICAgKiAgKipQYXJhbWV0ZXJzKipcbiAgICAgICAgKiBAcGFyYW0ge29iamVjdH0gb3B0aW9ucyAoT3B0aW9uYWwpIE9wdGlvbnMgb2JqZWN0IHRvIG92ZXJyaWRlIGdsb2JhbCBvcHRpb25zLlxuICAgICAgICAqIEBwYXJhbSB7c3RyaW5nfSBvcHRpb25zLnNjb3BlIChPcHRpb25hbCkgVGhlIHNjb3BlIChgdXNlcmAsIGBncm91cGAsIGBwcm9qZWN0YCkuXG4gICAgICAgICogQHBhcmFtIHtib29sZWFufSBvcHRpb25zLmZ1bGxVcmwgKE9wdGlvbmFsKSBEZXRlcm1pbmVzIGlmIHRoZSBsaXN0IG9mIGFzc2V0cyBpbiBhIHNjb3BlIGluY2x1ZGVzIHRoZSBjb21wbGV0ZSBVUkwgZm9yIGVhY2ggYXNzZXQgKGB0cnVlYCksIG9yIG9ubHkgdGhlIGZpbGUgbmFtZXMgb2YgdGhlIGFzc2V0cyAoYGZhbHNlYCkuXG4gICAgICAgICogQHJldHVybiB7UHJvbWlzZX1cbiAgICAgICAgKi9cbiAgICAgICAgbGlzdDogZnVuY3Rpb24gKG9wdGlvbnMpIHtcbiAgICAgICAgICAgIHZhciBkdGQgPSAkLkRlZmVycmVkKCk7XG4gICAgICAgICAgICB2YXIgbWUgPSB0aGlzO1xuICAgICAgICAgICAgdmFyIHVybE9wdGlvbnMgPSAkLmV4dGVuZCh7fSwgc2VydmljZU9wdGlvbnMsIG9wdGlvbnMpO1xuICAgICAgICAgICAgdmFyIHVybCA9IGJ1aWxkVXJsKCcnLCB1cmxPcHRpb25zKTtcbiAgICAgICAgICAgIHZhciBnZXRPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sIHVybE9wdGlvbnMsIHsgdXJsOiB1cmwgfSk7XG4gICAgICAgICAgICB2YXIgZnVsbFVybCA9IGdldE9wdGlvbnMuZnVsbFVybDtcblxuICAgICAgICAgICAgaWYgKCFmdWxsVXJsKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIGh0dHAuZ2V0KHt9LCBnZXRPcHRpb25zKTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgaHR0cC5nZXQoe30sIGdldE9wdGlvbnMpXG4gICAgICAgICAgICAgICAgLnRoZW4oZnVuY3Rpb24gKGZpbGVzKSB7XG4gICAgICAgICAgICAgICAgICAgIHZhciBmdWxsUGF0aEZpbGVzID0gJC5tYXAoZmlsZXMsIGZ1bmN0aW9uIChmaWxlKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICByZXR1cm4gYnVpbGRVcmwoZmlsZSwgdXJsT3B0aW9ucyk7XG4gICAgICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICAgICAgICBkdGQucmVzb2x2ZVdpdGgobWUsIFtmdWxsUGF0aEZpbGVzXSk7XG4gICAgICAgICAgICAgICAgfSlcbiAgICAgICAgICAgICAgICAuZmFpbChkdGQucmVqZWN0KTtcblxuICAgICAgICAgICAgcmV0dXJuIGR0ZC5wcm9taXNlKCk7XG4gICAgICAgIH0sXG5cbiAgICAgICAgLyoqXG4gICAgICAgICogUmVwbGFjZXMgYW4gZXhpc3RpbmcgZmlsZSBpbiB0aGUgQXNzZXQgQVBJLlxuICAgICAgICAqXG4gICAgICAgICogKipFeGFtcGxlKipcbiAgICAgICAgKlxuICAgICAgICAqICAgICAgIC8vIHJlcGxhY2UgYW4gYXNzZXQgdXNpbmcgZW5jb2RlZCB0ZXh0XG4gICAgICAgICogICAgICAgYWEucmVwbGFjZSgndGVzdC50eHQnLCB7XG4gICAgICAgICogICAgICAgICAgIGVuY29kaW5nOiAnQkFTRV82NCcsXG4gICAgICAgICogICAgICAgICAgIGRhdGE6ICdWR2hwY3lCcGN5QmhJSE5sWTI5dVpDQjBaWE4wSUdacGJHVXUnLFxuICAgICAgICAqICAgICAgICAgICBjb250ZW50VHlwZTogJ3RleHQvcGxhaW4nXG4gICAgICAgICogICAgICAgfSwgeyBzY29wZTogJ3VzZXInIH0pO1xuICAgICAgICAqXG4gICAgICAgICogICAgICAgLy8gYWx0ZXJuYXRpdmVseSwgcmVwbGFjZSBhbiBhc3NldCB1c2luZyBhIGZpbGUgdXBsb2FkZWQgdGhyb3VnaCBhIGZvcm1cbiAgICAgICAgKiAgICAgICAvLyB0aGlzIHNhbXBsZSBjb2RlIGdvZXMgd2l0aCBhbiBodG1sIGZvcm0gdGhhdCBsb29rcyBsaWtlIHRoaXM6XG4gICAgICAgICogICAgICAgLy9cbiAgICAgICAgKiAgICAgICAvLyA8Zm9ybSBpZD1cInJlcGxhY2UtZmlsZVwiPlxuICAgICAgICAqICAgICAgIC8vICAgPGlucHV0IGlkPVwiZmlsZVwiIHR5cGU9XCJmaWxlXCI+XG4gICAgICAgICogICAgICAgLy8gICA8aW5wdXQgaWQ9XCJyZXBsYWNlLWZpbGVuYW1lXCIgdHlwZT1cInRleHRcIiB2YWx1ZT1cIm15RmlsZS50eHRcIj5cbiAgICAgICAgKiAgICAgICAvLyAgIDxidXR0b24gdHlwZT1cInN1Ym1pdFwiPlJlcGxhY2UgbXlGaWxlPC9idXR0b24+XG4gICAgICAgICogICAgICAgLy8gPC9mb3JtPlxuICAgICAgICAqICAgICAgIC8vXG4gICAgICAgICogICAgICAgJCgnI3JlcGxhY2UtZmlsZScpLm9uKCdzdWJtaXQnLCBmdW5jdGlvbiAoZSkge1xuICAgICAgICAqICAgICAgICAgIGUucHJldmVudERlZmF1bHQoKTtcbiAgICAgICAgKiAgICAgICAgICB2YXIgZmlsZW5hbWUgPSAkKCcjcmVwbGFjZS1maWxlbmFtZScpLnZhbCgpO1xuICAgICAgICAqICAgICAgICAgIHZhciBkYXRhID0gbmV3IEZvcm1EYXRhKCk7XG4gICAgICAgICogICAgICAgICAgdmFyIGlucHV0Q29udHJvbCA9ICQoJyNmaWxlJylbMF07XG4gICAgICAgICogICAgICAgICAgZGF0YS5hcHBlbmQoJ2ZpbGUnLCBpbnB1dENvbnRyb2wuZmlsZXNbMF0sIGZpbGVuYW1lKTtcbiAgICAgICAgKlxuICAgICAgICAqICAgICAgICAgIGFhLnJlcGxhY2UoZmlsZW5hbWUsIGRhdGEsIHsgc2NvcGU6ICd1c2VyJyB9KTtcbiAgICAgICAgKiAgICAgICB9KTtcbiAgICAgICAgKlxuICAgICAgICAqICAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAqIEBwYXJhbSB7c3RyaW5nfSBmaWxlbmFtZSAoUmVxdWlyZWQpIE5hbWUgb2YgdGhlIGZpbGUgYmVpbmcgcmVwbGFjZWQuXG4gICAgICAgICogQHBhcmFtIHtvYmplY3R9IHBhcmFtcyAoT3B0aW9uYWwpIEJvZHkgcGFyYW1ldGVycyB0byBzZW5kIHRvIHRoZSBBc3NldCBBUEkuIFJlcXVpcmVkIGlmIHRoZSBgb3B0aW9ucy50cmFuc3BvcnQuY29udGVudFR5cGVgIGlzIGBhcHBsaWNhdGlvbi9qc29uYCwgb3RoZXJ3aXNlIGlnbm9yZWQuXG4gICAgICAgICogQHBhcmFtIHtzdHJpbmd9IHBhcmFtcy5lbmNvZGluZyBFaXRoZXIgYEhFWGAgb3IgYEJBU0VfNjRgLiBSZXF1aXJlZCBpZiBgb3B0aW9ucy50cmFuc3BvcnQuY29udGVudFR5cGVgIGlzIGBhcHBsaWNhdGlvbi9qc29uYC5cbiAgICAgICAgKiBAcGFyYW0ge3N0cmluZ30gcGFyYW1zLmRhdGEgVGhlIGVuY29kZWQgZGF0YSBmb3IgdGhlIGZpbGUuIFJlcXVpcmVkIGlmIGBvcHRpb25zLnRyYW5zcG9ydC5jb250ZW50VHlwZWAgaXMgYGFwcGxpY2F0aW9uL2pzb25gLlxuICAgICAgICAqIEBwYXJhbSB7c3RyaW5nfSBwYXJhbXMuY29udGVudFR5cGUgVGhlIG1pbWUgdHlwZSBvZiB0aGUgZmlsZS4gT3B0aW9uYWwuXG4gICAgICAgICogQHBhcmFtIHtvYmplY3R9IG9wdGlvbnMgKE9wdGlvbmFsKSBPcHRpb25zIG9iamVjdCB0byBvdmVycmlkZSBnbG9iYWwgb3B0aW9ucy5cbiAgICAgICAgKiBAcmV0dXJuIHtQcm9taXNlfVxuICAgICAgICAqL1xuICAgICAgICByZXBsYWNlOiBmdW5jdGlvbiAoZmlsZW5hbWUsIHBhcmFtcywgb3B0aW9ucykge1xuICAgICAgICAgICAgcmV0dXJuIHVwbG9hZCgncHV0JywgZmlsZW5hbWUsIHBhcmFtcywgb3B0aW9ucyk7XG4gICAgICAgIH0sXG5cbiAgICAgICAgLyoqXG4gICAgICAgICogRGVsZXRlcyBhIGZpbGUgZnJvbSB0aGUgQXNzZXQgQVBJLlxuICAgICAgICAqXG4gICAgICAgICogKipFeGFtcGxlKipcbiAgICAgICAgKlxuICAgICAgICAqICAgICAgIGFhLmRlbGV0ZShzYW1wbGVGaWxlTmFtZSk7XG4gICAgICAgICpcbiAgICAgICAgKiAgKipQYXJhbWV0ZXJzKipcbiAgICAgICAgKiBAcGFyYW0ge3N0cmluZ30gZmlsZW5hbWUgKFJlcXVpcmVkKSBOYW1lIG9mIHRoZSBmaWxlIHRvIGRlbGV0ZS5cbiAgICAgICAgKiBAcGFyYW0ge29iamVjdH0gb3B0aW9ucyAoT3B0aW9uYWwpIE9wdGlvbnMgb2JqZWN0IHRvIG92ZXJyaWRlIGdsb2JhbCBvcHRpb25zLlxuICAgICAgICAqIEByZXR1cm4ge1Byb21pc2V9XG4gICAgICAgICovXG4gICAgICAgIGRlbGV0ZTogZnVuY3Rpb24gKGZpbGVuYW1lLCBvcHRpb25zKSB7XG4gICAgICAgICAgICByZXR1cm4gdXBsb2FkKCdkZWxldGUnLCBmaWxlbmFtZSwge30sIG9wdGlvbnMpO1xuICAgICAgICB9LFxuXG4gICAgICAgIGFzc2V0VXJsOiBmdW5jdGlvbiAoZmlsZW5hbWUsIG9wdGlvbnMpIHtcbiAgICAgICAgICAgIHZhciB1cmxPcHRpb25zID0gJC5leHRlbmQoe30sIHNlcnZpY2VPcHRpb25zLCBvcHRpb25zKTtcbiAgICAgICAgICAgIHJldHVybiBidWlsZFVybChmaWxlbmFtZSwgdXJsT3B0aW9ucyk7XG4gICAgICAgIH1cbiAgICB9O1xuICAgICQuZXh0ZW5kKHRoaXMsIHB1YmxpY0FQSSk7XG59O1xuIiwiLyoqXG4gKlxuICogIyMgQXV0aGVudGljYXRpb24gQVBJIFNlcnZpY2VcbiAqXG4gKiBUaGUgQXV0aGVudGljYXRpb24gQVBJIFNlcnZpY2UgcHJvdmlkZXMgYSBtZXRob2QgZm9yIGxvZ2dpbmcgaW4sIHdoaWNoIGNyZWF0ZXMgYW5kIHJldHVybnMgYSB1c2VyIGFjY2VzcyB0b2tlbi5cbiAqXG4gKiBVc2VyIGFjY2VzcyB0b2tlbnMgYXJlIHJlcXVpcmVkIGZvciBlYWNoIGNhbGwgdG8gRXBpY2VudGVyLiAoU2VlIFtQcm9qZWN0IEFjY2Vzc10oLi4vLi4vLi4vcHJvamVjdF9hY2Nlc3MvKSBmb3IgbW9yZSBpbmZvcm1hdGlvbi4pXG4gKlxuICogSWYgeW91IG5lZWQgYWRkaXRpb25hbCBmdW5jdGlvbmFsaXR5IC0tIHN1Y2ggYXMgdHJhY2tpbmcgc2Vzc2lvbiBpbmZvcm1hdGlvbiwgZWFzaWx5IHJldHJpZXZpbmcgdGhlIHVzZXIgdG9rZW4sIG9yIGdldHRpbmcgdGhlIGdyb3VwcyB0byB3aGljaCBhbiBlbmQgdXNlciBiZWxvbmdzIC0tIGNvbnNpZGVyIHVzaW5nIHRoZSBbQXV0aG9yaXphdGlvbiBNYW5hZ2VyXSguLi9hdXRoLW1hbmFnZXIvKSBpbnN0ZWFkLlxuICpcbiAqICAgICAgdmFyIGF1dGggPSBuZXcgRi5zZXJ2aWNlLkF1dGgoKTtcbiAqICAgICAgYXV0aC5sb2dpbih7IHVzZXJOYW1lOiAnanNtaXRoQGFjbWVzaW11bGF0aW9ucy5jb20nLFxuICogICAgICAgICAgICAgICAgICBwYXNzd29yZDogJ3Bhc3N3MHJkJyB9KTtcbiAqL1xuXG4ndXNlIHN0cmljdCc7XG5cbnZhciBDb25maWdTZXJ2aWNlID0gcmVxdWlyZSgnLi9jb25maWd1cmF0aW9uLXNlcnZpY2UnKTtcbnZhciBUcmFuc3BvcnRGYWN0b3J5ID0gcmVxdWlyZSgnLi4vdHJhbnNwb3J0L2h0dHAtdHJhbnNwb3J0LWZhY3RvcnknKTtcblxubW9kdWxlLmV4cG9ydHMgPSBmdW5jdGlvbiAoY29uZmlnKSB7XG4gICAgdmFyIGRlZmF1bHRzID0ge1xuICAgICAgICAvKipcbiAgICAgICAgICogRW1haWwgb3IgdXNlcm5hbWUgdG8gdXNlIGZvciBsb2dnaW5nIGluLiBEZWZhdWx0cyB0byBlbXB0eSBzdHJpbmcuXG4gICAgICAgICAqIEB0eXBlIHtTdHJpbmd9XG4gICAgICAgICAqL1xuICAgICAgICB1c2VyTmFtZTogJycsXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIFBhc3N3b3JkIGZvciBzcGVjaWZpZWQgYHVzZXJOYW1lYC4gRGVmYXVsdHMgdG8gZW1wdHkgc3RyaW5nLlxuICAgICAgICAgKiBAdHlwZSB7U3RyaW5nfVxuICAgICAgICAgKi9cbiAgICAgICAgcGFzc3dvcmQ6ICcnLFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBUaGUgYWNjb3VudCBpZCBmb3IgdGhpcyBgdXNlck5hbWVgLiBJbiB0aGUgRXBpY2VudGVyIFVJLCB0aGlzIGlzIHRoZSAqKlRlYW0gSUQqKiAoZm9yIHRlYW0gcHJvamVjdHMpIG9yIHRoZSAqKlVzZXIgSUQqKiAoZm9yIHBlcnNvbmFsIHByb2plY3RzKS4gUmVxdWlyZWQgaWYgdGhlIGB1c2VyTmFtZWAgaXMgZm9yIGFuIFtlbmQgdXNlcl0oLi4vLi4vLi4vZ2xvc3NhcnkvI3VzZXJzKS4gRGVmYXVsdHMgdG8gZW1wdHkgc3RyaW5nLlxuICAgICAgICAgKiBAdHlwZSB7U3RyaW5nfVxuICAgICAgICAgKi9cbiAgICAgICAgYWNjb3VudDogJycsXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIE9wdGlvbnMgdG8gcGFzcyBvbiB0byB0aGUgdW5kZXJseWluZyB0cmFuc3BvcnQgbGF5ZXIuIEFsbCBqcXVlcnkuYWpheCBvcHRpb25zIGF0IGh0dHA6Ly9hcGkuanF1ZXJ5LmNvbS9qUXVlcnkuYWpheC8gYXJlIGF2YWlsYWJsZS4gRGVmYXVsdHMgdG8gZW1wdHkgb2JqZWN0LlxuICAgICAgICAgKiBAdHlwZSB7T2JqZWN0fVxuICAgICAgICAgKi9cbiAgICAgICAgdHJhbnNwb3J0OiB7fVxuICAgIH07XG4gICAgdmFyIHNlcnZpY2VPcHRpb25zID0gJC5leHRlbmQoe30sIGRlZmF1bHRzLCBjb25maWcpO1xuICAgIHZhciB1cmxDb25maWcgPSBuZXcgQ29uZmlnU2VydmljZShzZXJ2aWNlT3B0aW9ucykuZ2V0KCdzZXJ2ZXInKTtcblxuICAgIHZhciB0cmFuc3BvcnRPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sIHNlcnZpY2VPcHRpb25zLnRyYW5zcG9ydCwge1xuICAgICAgICB1cmw6IHVybENvbmZpZy5nZXRBUElQYXRoKCdhdXRoZW50aWNhdGlvbicpXG4gICAgfSk7XG4gICAgdmFyIGh0dHAgPSBuZXcgVHJhbnNwb3J0RmFjdG9yeSh0cmFuc3BvcnRPcHRpb25zKTtcblxuICAgIHZhciBwdWJsaWNBUEkgPSB7XG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIExvZ3MgdXNlciBpbiwgcmV0dXJuaW5nIHRoZSB1c2VyIGFjY2VzcyB0b2tlbi5cbiAgICAgICAgICpcbiAgICAgICAgICogSWYgbm8gYHVzZXJOYW1lYCBvciBgcGFzc3dvcmRgIHdlcmUgcHJvdmlkZWQgaW4gdGhlIGluaXRpYWwgY29uZmlndXJhdGlvbiBvcHRpb25zLCB0aGV5IGFyZSByZXF1aXJlZCBpbiB0aGUgYG9wdGlvbnNgIGhlcmUuIElmIG5vIGBhY2NvdW50YCB3YXMgcHJvdmlkZWQgaW4gdGhlIGluaXRpYWwgY29uZmlndXJhdGlvbiBvcHRpb25zIGFuZCB0aGUgYHVzZXJOYW1lYCBpcyBmb3IgYW4gW2VuZCB1c2VyXSguLi8uLi8uLi9nbG9zc2FyeS8jdXNlcnMpLCB0aGUgYGFjY291bnRgIGlzIHJlcXVpcmVkIGFzIHdlbGwuXG4gICAgICAgICAqXG4gICAgICAgICAqICoqRXhhbXBsZSoqXG4gICAgICAgICAqXG4gICAgICAgICAqICAgICAgYXV0aC5sb2dpbih7XG4gICAgICAgICAqICAgICAgICAgIHVzZXJOYW1lOiAnanNtaXRoJyxcbiAgICAgICAgICogICAgICAgICAgcGFzc3dvcmQ6ICdwYXNzdzByZCcsXG4gICAgICAgICAqICAgICAgICAgIGFjY291bnQ6ICdhY21lLXNpbXVsYXRpb25zJyB9KVxuICAgICAgICAgKiAgICAgIC50aGVuKGZ1bmN0aW9uICh0b2tlbikge1xuICAgICAgICAgKiAgICAgICAgICBjb25zb2xlLmxvZyhcInVzZXIgYWNjZXNzIHRva2VuIGlzOiBcIiwgdG9rZW4uYWNjZXNzX3Rva2VuKTtcbiAgICAgICAgICogICAgICB9KTtcbiAgICAgICAgICpcbiAgICAgICAgICogKipQYXJhbWV0ZXJzKipcbiAgICAgICAgICogQHBhcmFtIHtPYmplY3R9IG9wdGlvbnMgKE9wdGlvbmFsKSBPdmVycmlkZXMgZm9yIGNvbmZpZ3VyYXRpb24gb3B0aW9ucy5cbiAgICAgICAgICogQHJldHVybiB7UHJvbWlzZX1cbiAgICAgICAgICovXG4gICAgICAgIGxvZ2luOiBmdW5jdGlvbiAob3B0aW9ucykge1xuICAgICAgICAgICAgdmFyIGh0dHBPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwgeyBzdWNjZXNzOiAkLm5vb3AgfSwgc2VydmljZU9wdGlvbnMsIG9wdGlvbnMpO1xuICAgICAgICAgICAgaWYgKCFodHRwT3B0aW9ucy51c2VyTmFtZSB8fCAhaHR0cE9wdGlvbnMucGFzc3dvcmQpIHtcbiAgICAgICAgICAgICAgICB2YXIgcmVzcCA9IHsgc3RhdHVzOiA0MDEsIHN0YXR1c01lc3NhZ2U6ICdObyB1c2VybmFtZSBvciBwYXNzd29yZCBzcGVjaWZpZWQuJyB9O1xuICAgICAgICAgICAgICAgIGlmIChvcHRpb25zLmVycm9yKSB7XG4gICAgICAgICAgICAgICAgICAgIG9wdGlvbnMuZXJyb3IuY2FsbCh0aGlzLCByZXNwKTtcbiAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICByZXR1cm4gJC5EZWZlcnJlZCgpLnJlamVjdChyZXNwKS5wcm9taXNlKCk7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIHZhciBwb3N0UGFyYW1zID0ge1xuICAgICAgICAgICAgICAgIHVzZXJOYW1lOiBodHRwT3B0aW9ucy51c2VyTmFtZSxcbiAgICAgICAgICAgICAgICBwYXNzd29yZDogaHR0cE9wdGlvbnMucGFzc3dvcmQsXG4gICAgICAgICAgICB9O1xuICAgICAgICAgICAgaWYgKGh0dHBPcHRpb25zLmFjY291bnQpIHtcbiAgICAgICAgICAgICAgICAvL3Bhc3MgaW4gbnVsbCBmb3IgYWNjb3VudCB1bmRlciBvcHRpb25zIGlmIHlvdSBkb24ndCB3YW50IGl0IHRvIGJlIHNlbnRcbiAgICAgICAgICAgICAgICBwb3N0UGFyYW1zLmFjY291bnQgPSBodHRwT3B0aW9ucy5hY2NvdW50O1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICByZXR1cm4gaHR0cC5wb3N0KHBvc3RQYXJhbXMsIGh0dHBPcHRpb25zKTtcbiAgICAgICAgfSxcblxuICAgICAgICAvLyAocmVwbGFjZSB3aXRoIC8qICovIGNvbW1lbnQgYmxvY2ssIHRvIG1ha2UgdmlzaWJsZSBpbiBkb2NzLCBvbmNlIHRoaXMgaXMgbW9yZSB0aGFuIGEgbm9vcClcbiAgICAgICAgLy9cbiAgICAgICAgLy8gTG9ncyB1c2VyIG91dCBmcm9tIHNwZWNpZmllZCBhY2NvdW50cy5cbiAgICAgICAgLy9cbiAgICAgICAgLy8gRXBpY2VudGVyIGxvZ291dCBpcyBub3QgaW1wbGVtZW50ZWQgeWV0LCBzbyBmb3Igbm93IHRoaXMgaXMgYSBkdW1teSBwcm9taXNlIHRoYXQgZ2V0cyBhdXRvbWF0aWNhbGx5IHJlc29sdmVkLlxuICAgICAgICAvL1xuICAgICAgICAvLyAqKkV4YW1wbGUqKlxuICAgICAgICAvL1xuICAgICAgICAvLyAgICAgIGF1dGgubG9nb3V0KCk7XG4gICAgICAgIC8vXG4gICAgICAgIC8vICoqUGFyYW1ldGVycyoqXG4gICAgICAgIC8vIEBwYXJhbSB7T2JqZWN0fSBgb3B0aW9uc2AgKE9wdGlvbmFsKSBPdmVycmlkZXMgZm9yIGNvbmZpZ3VyYXRpb24gb3B0aW9ucy5cbiAgICAgICAgLy9cbiAgICAgICAgbG9nb3V0OiBmdW5jdGlvbiAob3B0aW9ucykge1xuICAgICAgICAgICAgdmFyIGR0ZCA9ICQuRGVmZXJyZWQoKTtcbiAgICAgICAgICAgIGR0ZC5yZXNvbHZlKCk7XG4gICAgICAgICAgICByZXR1cm4gZHRkLnByb21pc2UoKTtcbiAgICAgICAgfVxuICAgIH07XG5cbiAgICAkLmV4dGVuZCh0aGlzLCBwdWJsaWNBUEkpO1xufTtcbiIsIi8qKlxuICogIyMgQ2hhbm5lbCBTZXJ2aWNlXG4gKlxuICogVGhlIEVwaWNlbnRlciBwbGF0Zm9ybSBwcm92aWRlcyBhIHB1c2ggY2hhbm5lbCwgd2hpY2ggYWxsb3dzIHlvdSB0byBwdWJsaXNoIGFuZCBzdWJzY3JpYmUgdG8gbWVzc2FnZXMgd2l0aGluIGEgW3Byb2plY3RdKC4uLy4uLy4uL2dsb3NzYXJ5LyNwcm9qZWN0cyksIFtncm91cF0oLi4vLi4vLi4vZ2xvc3NhcnkvI2dyb3VwcyksIG9yIFttdWx0aXBsYXllciB3b3JsZF0oLi4vLi4vLi4vZ2xvc3NhcnkvI3dvcmxkKS4gVGhlcmUgYXJlIHR3byBtYWluIHVzZSBjYXNlcyBmb3IgdGhlIGNoYW5uZWw6IGV2ZW50IG5vdGlmaWNhdGlvbnMgYW5kIGNoYXQgbWVzc2FnZXMuXG4gKlxuICogSWYgeW91IGFyZSBkZXZlbG9waW5nIHdpdGggRXBpY2VudGVyLmpzLCB5b3Ugc2hvdWxkIHVzZSB0aGUgW0VwaWNlbnRlciBDaGFubmVsIE1hbmFnZXJdKC4uL2VwaWNlbnRlci1jaGFubmVsLW1hbmFnZXIvKSBkaXJlY3RseS4gVGhlIEVwaWNlbnRlciBDaGFubmVsIE1hbmFnZXIgZG9jdW1lbnRhdGlvbiBhbHNvIGhhcyBtb3JlIFtiYWNrZ3JvdW5kXSguLi9lcGljZW50ZXItY2hhbm5lbC1tYW5hZ2VyLyNiYWNrZ3JvdW5kKSBpbmZvcm1hdGlvbiBvbiBjaGFubmVscyBhbmQgdGhlaXIgdXNlLlxuICpcbiAqIFRoZSBDaGFubmVsIFNlcnZpY2UgaXMgYSBidWlsZGluZyBibG9jayBmb3IgdGhpcyBmdW5jdGlvbmFsaXR5LiBJdCBjcmVhdGVzIGEgcHVibGlzaC1zdWJzY3JpYmUgb2JqZWN0LCBhbGxvd2luZyB5b3UgdG8gcHVibGlzaCBtZXNzYWdlcywgc3Vic2NyaWJlIHRvIG1lc3NhZ2VzLCBvciB1bnN1YnNjcmliZSBmcm9tIG1lc3NhZ2VzIGZvciBhIGdpdmVuICd0b3BpYycgb24gYSBgJC5jb21ldGRgIHRyYW5zcG9ydCBpbnN0YW5jZS5cbiAqXG4gKiBZb3UnbGwgbmVlZCB0byBpbmNsdWRlIHRoZSBgZXBpY2VudGVyLW11bHRpcGxheWVyLWRlcGVuZGVuY2llcy5qc2AgbGlicmFyeSBpbiBhZGRpdGlvbiB0byB0aGUgYGVwaWNlbnRlci5qc2AgbGlicmFyeSBpbiB5b3VyIHByb2plY3QgdG8gdXNlIHRoZSBDaGFubmVsIFNlcnZpY2UuIFNlZSBbSW5jbHVkaW5nIEVwaWNlbnRlci5qc10oLi4vLi4vI2luY2x1ZGUpLlxuICpcbiAqIFRvIHVzZSB0aGUgQ2hhbm5lbCBTZXJ2aWNlLCBpbnN0YW50aWF0ZSBpdCwgdGhlbiBtYWtlIGNhbGxzIHRvIGFueSBvZiB0aGUgbWV0aG9kcyB5b3UgbmVlZC5cbiAqXG4gKiAgICAgICAgdmFyIGNzID0gbmV3IEYuc2VydmljZS5DaGFubmVsKCk7XG4gKiAgICAgICAgY3MucHVibGlzaCgnL2FjbWUtc2ltdWxhdGlvbnMvc3VwcGx5LWNoYWluLWdhbWUvZmFsbC1zZW1pbmFyL3J1bi92YXJpYWJsZXMnLCB7IHByaWNlOiA1MCB9KTtcbiAqXG4gKiBJZiB5b3UgYXJlIHdvcmtpbmcgdGhyb3VnaCB0aGUgW0VwaWNlbnRlciBDaGFubmVsIE1hbmFnZXJdKC4uL2VwaWNlbnRlci1jaGFubmVsLW1hbmFnZXIvKSwgd2hlbiB5b3UgYXNrIHRvIFwiZ2V0XCIgYSBwYXJ0aWN1bGFyIGNoYW5uZWwsIHlvdSBhcmUgcmVhbGx5IGFza2luZyBmb3IgYW4gaW5zdGFuY2Ugb2YgdGhlIENoYW5uZWwgU2VydmljZSB3aXRoIGEgdG9waWMgYWxyZWFkeSBzZXQsIGZvciBleGFtcGxlIHRvIHRoZSBhcHByb3ByaWF0ZSBncm91cCBvciB3b3JsZDpcbiAqXG4gKiAgICAgIHZhciBjbSA9IG5ldyBGLm1hbmFnZXIuQ2hhbm5lbE1hbmFnZXIoKTtcbiAqICAgICAgdmFyIGdjID0gY20uZ2V0R3JvdXBDaGFubmVsKCk7XG4gKiAgICAgIC8vIGJlY2F1c2Ugd2UgdXNlZCBhbiBFcGljZW50ZXIgQ2hhbm5lbCBNYW5hZ2VyIHRvIGdldCB0aGUgZ3JvdXAgY2hhbm5lbCxcbiAqICAgICAgLy8gc3Vic2NyaWJlKCkgYW5kIHB1Ymxpc2goKSBoZXJlIGRlZmF1bHQgdG8gdGhlIGJhc2UgdG9waWMgZm9yIHRoZSBncm91cFxuICogICAgICBnYy5zdWJzY3JpYmUoJycsIGZ1bmN0aW9uKGRhdGEpIHsgY29uc29sZS5sb2coZGF0YSk7IH0pO1xuICogICAgICBnYy5wdWJsaXNoKCcnLCB7IG1lc3NhZ2U6ICdhIG5ldyBtZXNzYWdlIHRvIHRoZSBncm91cCcgfSk7XG4gKlxuICogVGhlIHBhcmFtZXRlcnMgZm9yIGluc3RhbnRpYXRpbmcgYSBDaGFubmVsIFNlcnZpY2UgaW5jbHVkZTpcbiAqXG4gKiAqIGBvcHRpb25zYCBUaGUgb3B0aW9ucyBvYmplY3QgdG8gY29uZmlndXJlIHRoZSBDaGFubmVsIFNlcnZpY2UuXG4gKiAqIGBvcHRpb25zLmJhc2VgIFRoZSBiYXNlIHRvcGljLiBUaGlzIGlzIGFkZGVkIGFzIGEgcHJlZml4IHRvIGFsbCBmdXJ0aGVyIHRvcGljcyB5b3UgcHVibGlzaCBvciBzdWJzY3JpYmUgdG8gd2hpbGUgd29ya2luZyB3aXRoIHRoaXMgQ2hhbm5lbCBTZXJ2aWNlLlxuICogKiBgb3B0aW9ucy50b3BpY1Jlc29sdmVyYCBBIGZ1bmN0aW9uIHRoYXQgcHJvY2Vzc2VzIGFsbCAndG9waWNzJyBwYXNzZWQgaW50byB0aGUgYHB1Ymxpc2hgIGFuZCBgc3Vic2NyaWJlYCBtZXRob2RzLiBUaGlzIGlzIHVzZWZ1bCBpZiB5b3Ugd2FudCB0byBpbXBsZW1lbnQgeW91ciBvd24gc2VyaWFsaXplIGZ1bmN0aW9ucyBmb3IgY29udmVydGluZyBjdXN0b20gb2JqZWN0cyB0byB0b3BpYyBuYW1lcy4gUmV0dXJucyBhIFN0cmluZy4gQnkgZGVmYXVsdCwgaXQganVzdCBlY2hvZXMgdGhlIHRvcGljLlxuICogKiBgb3B0aW9ucy50cmFuc3BvcnRgIFRoZSBpbnN0YW5jZSBvZiBgJC5jb21ldGRgIHRvIGhvb2sgb250by4gU2VlIGh0dHA6Ly9kb2NzLmNvbWV0ZC5vcmcvcmVmZXJlbmNlL2phdmFzY3JpcHQuaHRtbCBmb3IgYWRkaXRpb25hbCBiYWNrZ3JvdW5kIG9uIGNvbWV0ZC5cbiAqL1xuXG4ndXNlIHN0cmljdCc7XG52YXIgQ2hhbm5lbCA9IGZ1bmN0aW9uIChvcHRpb25zKSB7XG4gICAgdmFyIGRlZmF1bHRzID0ge1xuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBUaGUgYmFzZSB0b3BpYy4gVGhpcyBpcyBhZGRlZCBhcyBhIHByZWZpeCB0byBhbGwgZnVydGhlciB0b3BpY3MgeW91IHB1Ymxpc2ggb3Igc3Vic2NyaWJlIHRvIHdoaWxlIHdvcmtpbmcgd2l0aCB0aGlzIENoYW5uZWwgU2VydmljZS5cbiAgICAgICAgICogQHR5cGUge3N0cmluZ31cbiAgICAgICAgICovXG4gICAgICAgIGJhc2U6ICcnLFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBBIGZ1bmN0aW9uIHRoYXQgcHJvY2Vzc2VzIGFsbCAndG9waWNzJyBwYXNzZWQgaW50byB0aGUgYHB1Ymxpc2hgIGFuZCBgc3Vic2NyaWJlYCBtZXRob2RzLiBUaGlzIGlzIHVzZWZ1bCBpZiB5b3Ugd2FudCB0byBpbXBsZW1lbnQgeW91ciBvd24gc2VyaWFsaXplIGZ1bmN0aW9ucyBmb3IgY29udmVydGluZyBjdXN0b20gb2JqZWN0cyB0byB0b3BpYyBuYW1lcy4gQnkgZGVmYXVsdCwgaXQganVzdCBlY2hvZXMgdGhlIHRvcGljLlxuICAgICAgICAgKlxuICAgICAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAgKlxuICAgICAgICAgKiAqIGB0b3BpY2AgVG9waWMgdG8gcGFyc2UuXG4gICAgICAgICAqXG4gICAgICAgICAqICoqUmV0dXJuIFZhbHVlKipcbiAgICAgICAgICpcbiAgICAgICAgICogKiAqU3RyaW5nKjogVGhpcyBmdW5jdGlvbiBzaG91bGQgcmV0dXJuIGEgc3RyaW5nIHRvcGljLlxuICAgICAgICAgKlxuICAgICAgICAgKiBAdHlwZSB7ZnVuY3Rpb259XG4gICAgICAgICAqIEBwYXJhbSB7U3RyaW5nfSB0b3BpYyB0b3BpYyB0byByZXNvbHZlXG4gICAgICAgICAqIEByZXR1cm4ge1N0cmluZ31cbiAgICAgICAgICovXG4gICAgICAgIHRvcGljUmVzb2x2ZXI6IGZ1bmN0aW9uICh0b3BpYykge1xuICAgICAgICAgICAgcmV0dXJuIHRvcGljO1xuICAgICAgICB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBUaGUgaW5zdGFuY2Ugb2YgYCQuY29tZXRkYCB0byBob29rIG9udG8uXG4gICAgICAgICAqIEB0eXBlIHtvYmplY3R9XG4gICAgICAgICAqL1xuICAgICAgICB0cmFuc3BvcnQ6IG51bGxcbiAgICB9O1xuICAgIHRoaXMuY2hhbm5lbE9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSwgZGVmYXVsdHMsIG9wdGlvbnMpO1xufTtcblxudmFyIG1ha2VOYW1lID0gZnVuY3Rpb24gKGNoYW5uZWxOYW1lLCB0b3BpYykge1xuICAgIC8vUmVwbGFjZSB0cmFpbGluZy9kb3VibGUgc2xhc2hlc1xuICAgIHZhciBuZXdOYW1lID0gKGNoYW5uZWxOYW1lID8gKGNoYW5uZWxOYW1lICsgJy8nICsgdG9waWMpIDogdG9waWMpLnJlcGxhY2UoL1xcL1xcLy9nLCAnLycpLnJlcGxhY2UoL1xcLyQvLCAnJyk7XG4gICAgcmV0dXJuIG5ld05hbWU7XG59O1xuXG5cbkNoYW5uZWwucHJvdG90eXBlID0gJC5leHRlbmQoQ2hhbm5lbC5wcm90b3R5cGUsIHtcblxuICAgIC8vIGZ1dHVyZSBmdW5jdGlvbmFsaXR5OlxuICAgIC8vICAgICAgLy8gU2V0IHRoZSBjb250ZXh0IGZvciB0aGUgY2FsbGJhY2tcbiAgICAvLyAgICAgIGNzLnN1YnNjcmliZSgncnVuJywgZnVuY3Rpb24gKCkgeyB0aGlzLmlubmVySFRNTCA9ICdUcmlnZ2VyZWQnfSwgZG9jdW1lbnQuYm9keSk7XG4gICAgIC8vXG4gICAgIC8vICAgICAgLy8gQ29udHJvbCB0aGUgb3JkZXIgb2Ygb3BlcmF0aW9ucyBieSBzZXR0aW5nIHRoZSBgcHJpb3JpdHlgXG4gICAgIC8vICAgICAgY3Muc3Vic2NyaWJlKCdydW4nLCBjYiwgdGhpcywge3ByaW9yaXR5OiA5fSk7XG4gICAgIC8vXG4gICAgIC8vICAgICAgLy8gT25seSBleGVjdXRlIHRoZSBjYWxsYmFjaywgYGNiYCwgaWYgdGhlIHZhbHVlIG9mIHRoZSBgcHJpY2VgIHZhcmlhYmxlIGlzIDUwXG4gICAgIC8vICAgICAgY3Muc3Vic2NyaWJlKCdydW4vdmFyaWFibGVzL3ByaWNlJywgY2IsIHRoaXMsIHtwcmlvcml0eTogMzAsIHZhbHVlOiA1MH0pO1xuICAgICAvL1xuICAgICAvLyAgICAgIC8vIE9ubHkgZXhlY3V0ZSB0aGUgY2FsbGJhY2ssIGBjYmAsIGlmIHRoZSB2YWx1ZSBvZiB0aGUgYHByaWNlYCB2YXJpYWJsZSBpcyBncmVhdGVyIHRoYW4gNTBcbiAgICAgLy8gICAgICBzdWJzY3JpYmUoJ3J1bi92YXJpYWJsZXMvcHJpY2UnLCBjYiwgdGhpcywge3ByaW9yaXR5OiAzMCwgdmFsdWU6ICc+NTAnfSk7XG4gICAgIC8vXG4gICAgIC8vICAgICAgLy8gT25seSBleGVjdXRlIHRoZSBjYWxsYmFjaywgYGNiYCwgaWYgdGhlIHZhbHVlIG9mIHRoZSBgcHJpY2VgIHZhcmlhYmxlIGlzIGV2ZW5cbiAgICAgLy8gICAgICBzdWJzY3JpYmUoJ3J1bi92YXJpYWJsZXMvcHJpY2UnLCBjYiwgdGhpcywge3ByaW9yaXR5OiAzMCwgdmFsdWU6IGZ1bmN0aW9uICh2YWwpIHtyZXR1cm4gdmFsICUgMiA9PT0gMH19KTtcblxuXG4gICAgLyoqXG4gICAgICogU3Vic2NyaWJlIHRvIGNoYW5nZXMgb24gYSB0b3BpYy5cbiAgICAgKlxuICAgICAqIFRoZSB0b3BpYyBzaG91bGQgaW5jbHVkZSB0aGUgZnVsbCBwYXRoIG9mIHRoZSBhY2NvdW50IGlkICgqKlRlYW0gSUQqKiBmb3IgdGVhbSBwcm9qZWN0cyksIHByb2plY3QgaWQsIGFuZCBncm91cCBuYW1lLiAoSW4gbW9zdCBjYXNlcywgaXQgaXMgc2ltcGxlciB0byB1c2UgdGhlIFtFcGljZW50ZXIgQ2hhbm5lbCBNYW5hZ2VyXSguLi9lcGljZW50ZXItY2hhbm5lbC1tYW5hZ2VyLykgaW5zdGVhZCwgaW4gd2hpY2ggY2FzZSB0aGlzIGlzIGNvbmZpZ3VyZWQgZm9yIHlvdS4pXG4gICAgICpcbiAgICAgKiAgKipFeGFtcGxlcyoqXG4gICAgICpcbiAgICAgKiAgICAgIHZhciBjYiA9IGZ1bmN0aW9uKHZhbCkgeyBjb25zb2xlLmxvZyh2YWwuZGF0YSk7IH07XG4gICAgICpcbiAgICAgKiAgICAgIC8vIFN1YnNjcmliZSB0byBjaGFuZ2VzIG9uIGEgdG9wLWxldmVsICdydW4nIHRvcGljXG4gICAgICogICAgICBjcy5zdWJzY3JpYmUoJy9hY21lLXNpbXVsYXRpb25zL3N1cHBseS1jaGFpbi1nYW1lL2ZhbGwtc2VtaW5hci9ydW4nLCBjYik7XG4gICAgICpcbiAgICAgKiAgICAgIC8vIFN1YnNjcmliZSB0byBjaGFuZ2VzIG9uIGNoaWxkcmVuIG9mIHRoZSAncnVuJyB0b3BpYy4gTm90ZSB0aGlzIHdpbGwgYWxzbyBiZSB0cmlnZ2VyZWQgZm9yIGNoYW5nZXMgdG8gcnVuLngueS56LlxuICAgICAqICAgICAgY3Muc3Vic2NyaWJlKCcvYWNtZS1zaW11bGF0aW9ucy9zdXBwbHktY2hhaW4tZ2FtZS9mYWxsLXNlbWluYXIvcnVuLyonLCBjYik7XG4gICAgICpcbiAgICAgKiAgICAgIC8vIFN1YnNjcmliZSB0byBjaGFuZ2VzIG9uIGJvdGggdGhlIHRvcC1sZXZlbCAncnVuJyB0b3BpYyBhbmQgaXRzIGNoaWxkcmVuXG4gICAgICogICAgICBjcy5zdWJzY3JpYmUoWycvYWNtZS1zaW11bGF0aW9ucy9zdXBwbHktY2hhaW4tZ2FtZS9mYWxsLXNlbWluYXIvcnVuJyxcbiAgICAgKiAgICAgICAgICAnL2FjbWUtc2ltdWxhdGlvbnMvc3VwcGx5LWNoYWluLWdhbWUvZmFsbC1zZW1pbmFyL3J1bi8qJ10sIGNiKTtcbiAgICAgKlxuICAgICAqICAgICAgLy8gU3Vic2NyaWJlIHRvIGNoYW5nZXMgb24gYSBwYXJ0aWN1bGFyIHZhcmlhYmxlXG4gICAgICogICAgICBzdWJzY3JpYmUoJy9hY21lLXNpbXVsYXRpb25zL3N1cHBseS1jaGFpbi1nYW1lL2ZhbGwtc2VtaW5hci9ydW4vdmFyaWFibGVzL3ByaWNlJywgY2IpO1xuICAgICAqXG4gICAgICpcbiAgICAgKiAqKlJldHVybiBWYWx1ZSoqXG4gICAgICpcbiAgICAgKiAqICpTdHJpbmcqIFJldHVybnMgYSB0b2tlbiB5b3UgY2FuIGxhdGVyIHVzZSB0byB1bnN1YnNjcmliZS5cbiAgICAgKlxuICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICogQHBhcmFtICB7U3RyaW5nfEFycmF5fSAgIHRvcGljICAgIExpc3Qgb2YgdG9waWNzIHRvIGxpc3RlbiBmb3IgY2hhbmdlcyBvbi5cbiAgICAgKiBAcGFyYW0gIHtGdW5jdGlvbn0gY2FsbGJhY2sgQ2FsbGJhY2sgZnVuY3Rpb24gdG8gZXhlY3V0ZS4gQ2FsbGJhY2sgaXMgY2FsbGVkIHdpdGggc2lnbmF0dXJlIGAoZXZ0LCBwYXlsb2FkLCBtZXRhZGF0YSlgLlxuICAgICAqIEBwYXJhbSAge09iamVjdH0gICBjb250ZXh0ICBDb250ZXh0IGluIHdoaWNoIHRoZSBgY2FsbGJhY2tgIGlzIGV4ZWN1dGVkLlxuICAgICAqIEBwYXJhbSAge09iamVjdH0gICBvcHRpb25zICAoT3B0aW9uYWwpIE92ZXJyaWRlcyBmb3IgY29uZmlndXJhdGlvbiBvcHRpb25zLlxuICAgICAqIEBwYXJhbSAge051bWJlcn0gICBvcHRpb25zLnByaW9yaXR5ICBVc2VkIHRvIGNvbnRyb2wgb3JkZXIgb2Ygb3BlcmF0aW9ucy4gRGVmYXVsdHMgdG8gMC4gQ2FuIGJlIGFueSArdmUgb3IgLXZlIG51bWJlci5cbiAgICAgKiBAcGFyYW0gIHtTdHJpbmd8TnVtYmVyfEZ1bmN0aW9ufSAgIG9wdGlvbnMudmFsdWUgVGhlIGBjYWxsYmFja2AgaXMgb25seSB0cmlnZ2VyZWQgaWYgdGhpcyBjb25kaXRpb24gbWF0Y2hlcy4gU2VlIGV4YW1wbGVzIGZvciBkZXRhaWxzLlxuICAgICAqIEByZXR1cm4ge3N0cmluZ30gU3Vic2NyaXB0aW9uIElEXG4gICAgICovXG4gICAgc3Vic2NyaWJlOiBmdW5jdGlvbiAodG9waWMsIGNhbGxiYWNrLCBjb250ZXh0LCBvcHRpb25zKSB7XG5cbiAgICAgICAgdmFyIHRvcGljcyA9IFtdLmNvbmNhdCh0b3BpYyk7XG4gICAgICAgIHZhciBtZSA9IHRoaXM7XG4gICAgICAgIHZhciBzdWJzY3JpcHRpb25JZHMgPSBbXTtcbiAgICAgICAgdmFyIG9wdHMgPSBtZS5jaGFubmVsT3B0aW9ucztcblxuICAgICAgICBvcHRzLnRyYW5zcG9ydC5iYXRjaChmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICAkLmVhY2godG9waWNzLCBmdW5jdGlvbiAoaW5kZXgsIHRvcGljKSB7XG4gICAgICAgICAgICAgICAgdG9waWMgPSBtYWtlTmFtZShvcHRzLmJhc2UsIG9wdHMudG9waWNSZXNvbHZlcih0b3BpYykpO1xuICAgICAgICAgICAgICAgIHN1YnNjcmlwdGlvbklkcy5wdXNoKG9wdHMudHJhbnNwb3J0LnN1YnNjcmliZSh0b3BpYywgY2FsbGJhY2spKTtcbiAgICAgICAgICAgIH0pO1xuICAgICAgICB9KTtcbiAgICAgICAgcmV0dXJuIChzdWJzY3JpcHRpb25JZHNbMV0gPyBzdWJzY3JpcHRpb25JZHMgOiBzdWJzY3JpcHRpb25JZHNbMF0pO1xuICAgIH0sXG5cbiAgICAvKipcbiAgICAgKiBQdWJsaXNoIGRhdGEgdG8gYSB0b3BpYy5cbiAgICAgKlxuICAgICAqICoqRXhhbXBsZXMqKlxuICAgICAqXG4gICAgICogICAgICAvLyBTZW5kIGRhdGEgdG8gYWxsIHN1YnNjcmliZXJzIG9mIHRoZSAncnVuJyB0b3BpY1xuICAgICAqICAgICAgY3MucHVibGlzaCgnL2FjbWUtc2ltdWxhdGlvbnMvc3VwcGx5LWNoYWluLWdhbWUvZmFsbC1zZW1pbmFyL3J1bicsIHsgY29tcGxldGVkOiBmYWxzZSB9KTtcbiAgICAgKlxuICAgICAqICAgICAgLy8gU2VuZCBkYXRhIHRvIGFsbCBzdWJzY3JpYmVycyBvZiB0aGUgJ3J1bi92YXJpYWJsZXMnIHRvcGljXG4gICAgICogICAgICBjcy5wdWJsaXNoKCcvYWNtZS1zaW11bGF0aW9ucy9zdXBwbHktY2hhaW4tZ2FtZS9mYWxsLXNlbWluYXIvcnVuL3ZhcmlhYmxlcycsIHsgcHJpY2U6IDUwIH0pO1xuICAgICAqXG4gICAgICogKipQYXJhbWV0ZXJzKipcbiAgICAgKlxuICAgICAqIEBwYXJhbSAge1N0cmluZ30gdG9waWMgVG9waWMgdG8gcHVibGlzaCB0by5cbiAgICAgKiBAcGFyYW0gIHsqfSBkYXRhICBEYXRhIHRvIHB1Ymxpc2ggdG8gdG9waWMuXG4gICAgICogQHJldHVybiB7QXJyYXkgfCBPYmplY3R9IFJlc3BvbnNlcyB0byBwdWJsaXNoZWQgZGF0YVxuICAgICAqXG4gICAgICovXG4gICAgcHVibGlzaDogZnVuY3Rpb24gKHRvcGljLCBkYXRhKSB7XG4gICAgICAgIHZhciB0b3BpY3MgPSBbXS5jb25jYXQodG9waWMpO1xuICAgICAgICB2YXIgbWUgPSB0aGlzO1xuICAgICAgICB2YXIgcmV0dXJuT2JqcyA9IFtdO1xuICAgICAgICB2YXIgb3B0cyA9IG1lLmNoYW5uZWxPcHRpb25zO1xuXG5cbiAgICAgICAgb3B0cy50cmFuc3BvcnQuYmF0Y2goZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgJC5lYWNoKHRvcGljcywgZnVuY3Rpb24gKGluZGV4LCB0b3BpYykge1xuICAgICAgICAgICAgICAgIHRvcGljID0gbWFrZU5hbWUob3B0cy5iYXNlLCBvcHRzLnRvcGljUmVzb2x2ZXIodG9waWMpKTtcbiAgICAgICAgICAgICAgICBpZiAodG9waWMuY2hhckF0KHRvcGljLmxlbmd0aCAtIDEpID09PSAnKicpIHtcbiAgICAgICAgICAgICAgICAgICAgdG9waWMgPSB0b3BpYy5yZXBsYWNlKC9cXCorJC8sICcnKTtcbiAgICAgICAgICAgICAgICAgICAgY29uc29sZS53YXJuKCdZb3UgY2FuIGNhbm5vdCBwdWJsaXNoIHRvIGNoYW5uZWxzIHdpdGggd2lsZGNhcmRzLiBQdWJsaXNoaW5nIHRvICcsIHRvcGljLCAnaW5zdGVhZCcpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICByZXR1cm5PYmpzLnB1c2gob3B0cy50cmFuc3BvcnQucHVibGlzaCh0b3BpYywgZGF0YSkpO1xuICAgICAgICAgICAgfSk7XG4gICAgICAgIH0pO1xuICAgICAgICByZXR1cm4gKHJldHVybk9ianNbMV0gPyByZXR1cm5PYmpzIDogcmV0dXJuT2Jqc1swXSk7XG4gICAgfSxcblxuICAgIC8qKlxuICAgICAqIFVuc3Vic2NyaWJlIGZyb20gY2hhbmdlcyB0byBhIHRvcGljLlxuICAgICAqXG4gICAgICogKipFeGFtcGxlKipcbiAgICAgKlxuICAgICAqICAgICAgY3MudW5zdWJzY3JpYmUoJ3NhbXBsZVRva2VuJyk7XG4gICAgICpcbiAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAqIEBwYXJhbSAge1N0cmluZ30gdG9rZW4gVGhlIHRva2VuIGZvciB0b3BpYyBpcyByZXR1cm5lZCB3aGVuIHlvdSBpbml0aWFsbHkgc3Vic2NyaWJlLiBQYXNzIGl0IGhlcmUgdG8gdW5zdWJzY3JpYmUgZnJvbSB0aGF0IHRvcGljLlxuICAgICAqIEByZXR1cm4ge09iamVjdH0gcmVmZXJlbmNlIHRvIGN1cnJlbnQgaW5zdGFuY2VcbiAgICAgKi9cbiAgICB1bnN1YnNjcmliZTogZnVuY3Rpb24gKHRva2VuKSB7XG4gICAgICAgIHRoaXMuY2hhbm5lbE9wdGlvbnMudHJhbnNwb3J0LnVuc3Vic2NyaWJlKHRva2VuKTtcbiAgICAgICAgcmV0dXJuIHRoaXM7XG4gICAgfSxcblxuICAgIC8qKlxuICAgICAqIFN0YXJ0IGxpc3RlbmluZyBmb3IgZXZlbnRzIG9uIHRoaXMgaW5zdGFuY2UuIFNpZ25hdHVyZSBpcyBzYW1lIGFzIGZvciBqUXVlcnkgRXZlbnRzOiBodHRwOi8vYXBpLmpxdWVyeS5jb20vb24vLlxuICAgICAqXG4gICAgICogU3VwcG9ydGVkIGV2ZW50cyBhcmU6IGBjb25uZWN0YCwgYGRpc2Nvbm5lY3RgLCBgc3Vic2NyaWJlYCwgYHVuc3Vic2NyaWJlYCwgYHB1Ymxpc2hgLCBgZXJyb3JgLlxuICAgICAqXG4gICAgICogKipQYXJhbWV0ZXJzKipcbiAgICAgKlxuICAgICAqIEBwYXJhbSB7c3RyaW5nfSBldmVudCBUaGUgZXZlbnQgdHlwZS4gU2VlIG1vcmUgZGV0YWlsIGF0IGpRdWVyeSBFdmVudHM6IGh0dHA6Ly9hcGkuanF1ZXJ5LmNvbS9vbi8uXG4gICAgICovXG4gICAgb246IGZ1bmN0aW9uIChldmVudCkge1xuICAgICAgICAkKHRoaXMpLm9uLmFwcGx5KCQodGhpcyksIGFyZ3VtZW50cyk7XG4gICAgfSxcblxuICAgIC8qKlxuICAgICAqIFN0b3AgbGlzdGVuaW5nIGZvciBldmVudHMgb24gdGhpcyBpbnN0YW5jZS4gU2lnbmF0dXJlIGlzIHNhbWUgYXMgZm9yIGpRdWVyeSBFdmVudHM6IGh0dHA6Ly9hcGkuanF1ZXJ5LmNvbS9vZmYvLlxuICAgICAqXG4gICAgICogKipQYXJhbWV0ZXJzKipcbiAgICAgKlxuICAgICAqIEBwYXJhbSB7c3RyaW5nfSBldmVudCBUaGUgZXZlbnQgdHlwZS4gU2VlIG1vcmUgZGV0YWlsIGF0IGpRdWVyeSBFdmVudHM6IGh0dHA6Ly9hcGkuanF1ZXJ5LmNvbS9vZmYvLlxuICAgICAqL1xuICAgIG9mZjogZnVuY3Rpb24gKGV2ZW50KSB7XG4gICAgICAgICQodGhpcykub2ZmLmFwcGx5KCQodGhpcyksIGFyZ3VtZW50cyk7XG4gICAgfSxcblxuICAgIC8qKlxuICAgICAqIFRyaWdnZXIgZXZlbnRzIGFuZCBleGVjdXRlIGhhbmRsZXJzLiBTaWduYXR1cmUgaXMgc2FtZSBhcyBmb3IgalF1ZXJ5IEV2ZW50czogaHR0cDovL2FwaS5qcXVlcnkuY29tL3RyaWdnZXIvLlxuICAgICAqXG4gICAgICogKipQYXJhbWV0ZXJzKipcbiAgICAgKlxuICAgICAqIEBwYXJhbSB7c3RyaW5nfSBldmVudCBUaGUgZXZlbnQgdHlwZS4gU2VlIG1vcmUgZGV0YWlsIGF0IGpRdWVyeSBFdmVudHM6IGh0dHA6Ly9hcGkuanF1ZXJ5LmNvbS90cmlnZ2VyLy5cbiAgICAgKi9cbiAgICB0cmlnZ2VyOiBmdW5jdGlvbiAoZXZlbnQpIHtcbiAgICAgICAgJCh0aGlzKS50cmlnZ2VyLmFwcGx5KCQodGhpcyksIGFyZ3VtZW50cyk7XG4gICAgfVxuXG59KTtcblxubW9kdWxlLmV4cG9ydHMgPSBDaGFubmVsO1xuIiwiLyoqXG4gKiBAY2xhc3MgQ29uZmlndXJhdGlvblNlcnZpY2VcbiAqXG4gKiBBbGwgc2VydmljZXMgdGFrZSBpbiBhIGNvbmZpZ3VyYXRpb24gc2V0dGluZ3Mgb2JqZWN0IHRvIGNvbmZpZ3VyZSB0aGVtc2VsdmVzLiBBIEpTIGhhc2gge30gaXMgYSB2YWxpZCBjb25maWd1cmF0aW9uIG9iamVjdCwgYnV0IG9wdGlvbmFsbHkgeW91IGNhbiB1c2UgdGhlIGNvbmZpZ3VyYXRpb24gc2VydmljZSB0byB0b2dnbGUgY29uZmlncyBiYXNlZCBvbiB0aGUgZW52aXJvbm1lbnRcbiAqXG4gKiBAZXhhbXBsZVxuICogICAgIHZhciBjcyA9IHJlcXVpcmUoJ2NvbmZpZ3VyYXRpb24tc2VydmljZScpKHtcbiAqICAgICAgICAgIGRldjogeyAvL2Vudmlyb25tZW50XG4gICAgICAgICAgICAgICAgcG9ydDogMzAwMCxcbiAgICAgICAgICAgICAgICBob3N0OiAnbG9jYWxob3N0JyxcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICBwcm9kOiB7XG4gICAgICAgICAgICAgICAgcG9ydDogODA4MCxcbiAgICAgICAgICAgICAgICBob3N0OiAnYXBpLmZvcmlvLmNvbScsXG4gICAgICAgICAgICAgICAgbG9nTGV2ZWw6ICdub25lJ1xuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIGxvZ0xldmVsOiAnREVCVUcnIC8vZ2xvYmFsXG4gKiAgICAgfSk7XG4gKlxuICogICAgICBjcy5nZXQoJ2xvZ0xldmVsJyk7IC8vcmV0dXJucyAnREVCVUcnXG4gKlxuICogICAgICBjcy5zZXRFbnYoJ2RldicpO1xuICogICAgICBjcy5nZXQoJ2xvZ0xldmVsJyk7IC8vcmV0dXJucyAnREVCVUcnXG4gKlxuICogICAgICBjcy5zZXRFbnYoJ3Byb2QnKTtcbiAqICAgICAgY3MuZ2V0KCdsb2dMZXZlbCcpOyAvL3JldHVybnMgJ25vbmUnXG4gKlxuICovXG5cbid1c2Ugc3RyaWN0JztcbnZhciB1cmxTZXJ2aWNlID0gcmVxdWlyZSgnLi91cmwtY29uZmlnLXNlcnZpY2UnKTtcblxubW9kdWxlLmV4cG9ydHMgPSBmdW5jdGlvbiAoY29uZmlnKSB7XG4gICAgLy9UT0RPOiBFbnZpcm9ubWVudHNcbiAgICB2YXIgZGVmYXVsdHMgPSB7XG4gICAgICAgIGxvZ0xldmVsOiAnTk9ORSdcbiAgICB9O1xuICAgIHZhciBzZXJ2aWNlT3B0aW9ucyA9ICQuZXh0ZW5kKHt9LCBkZWZhdWx0cywgY29uZmlnKTtcbiAgICBzZXJ2aWNlT3B0aW9ucy5zZXJ2ZXIgPSB1cmxTZXJ2aWNlKHNlcnZpY2VPcHRpb25zLnNlcnZlcik7XG5cbiAgICByZXR1cm4ge1xuXG4gICAgICAgIGRhdGE6IHNlcnZpY2VPcHRpb25zLFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBTZXQgdGhlIGVudmlyb25tZW50IGtleSB0byBnZXQgY29uZmlndXJhdGlvbiBvcHRpb25zIGZyb21cbiAgICAgICAgICogQHBhcmFtIHsgc3RyaW5nfSBlbnZcbiAgICAgICAgICovXG4gICAgICAgIHNldEVudjogZnVuY3Rpb24gKGVudikge1xuXG4gICAgICAgIH0sXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIEdldCBjb25maWd1cmF0aW9uLlxuICAgICAgICAgKiBAcGFyYW0gIHsgc3RyaW5nfSBwcm9wZXJ0eSBvcHRpb25hbFxuICAgICAgICAgKiBAcmV0dXJuIHsqfSAgICAgICAgICBWYWx1ZSBvZiBwcm9wZXJ0eSBpZiBzcGVjaWZpZWQsIHRoZSBlbnRpcmUgY29uZmlnIG9iamVjdCBvdGhlcndpc2VcbiAgICAgICAgICovXG4gICAgICAgIGdldDogZnVuY3Rpb24gKHByb3BlcnR5KSB7XG4gICAgICAgICAgICByZXR1cm4gc2VydmljZU9wdGlvbnNbcHJvcGVydHldO1xuICAgICAgICB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBTZXQgY29uZmlndXJhdGlvbi5cbiAgICAgICAgICogQHBhcmFtICB7IHN0cmluZ3xPYmplY3R9IGtleSBpZiBhIGtleSBpcyBwcm92aWRlZCwgc2V0IGEga2V5IHRvIHRoYXQgdmFsdWUuIE90aGVyd2lzZSBtZXJnZSBvYmplY3Qgd2l0aCBjdXJyZW50IGNvbmZpZ1xuICAgICAgICAgKiBAcGFyYW0gIHsqfSB2YWx1ZSAgdmFsdWUgZm9yIHByb3ZpZGVkIGtleVxuICAgICAgICAgKi9cbiAgICAgICAgc2V0OiBmdW5jdGlvbiAoa2V5LCB2YWx1ZSkge1xuICAgICAgICAgICAgc2VydmljZU9wdGlvbnNba2V5XSA9IHZhbHVlO1xuICAgICAgICB9XG4gICAgfTtcbn07XG5cbiIsIi8qKlxuICogIyMgRGF0YSBBUEkgU2VydmljZVxuICpcbiAqIFRoZSBEYXRhIEFQSSBTZXJ2aWNlIGFsbG93cyB5b3UgdG8gY3JlYXRlLCBhY2Nlc3MsIGFuZCBtYW5pcHVsYXRlIGRhdGEgcmVsYXRlZCB0byBhbnkgb2YgeW91ciBwcm9qZWN0cy4gRGF0YSBhcmUgb3JnYW5pemVkIGluIGNvbGxlY3Rpb25zLiBFYWNoIGNvbGxlY3Rpb24gY29udGFpbnMgYSBkb2N1bWVudDsgZWFjaCBlbGVtZW50IG9mIHRoaXMgdG9wLWxldmVsIGRvY3VtZW50IGlzIGEgSlNPTiBvYmplY3QuIChTZWUgYWRkaXRpb25hbCBpbmZvcm1hdGlvbiBvbiB0aGUgdW5kZXJseWluZyBbRGF0YSBBUEldKC4uLy4uLy4uL3Jlc3RfYXBpcy9kYXRhX2FwaS8pLilcbiAqXG4gKiBBbGwgQVBJIGNhbGxzIHRha2UgaW4gYW4gXCJvcHRpb25zXCIgb2JqZWN0IGFzIHRoZSBsYXN0IHBhcmFtZXRlci4gVGhlIG9wdGlvbnMgY2FuIGJlIHVzZWQgdG8gZXh0ZW5kL292ZXJyaWRlIHRoZSBEYXRhIEFQSSBTZXJ2aWNlIGRlZmF1bHRzLiBJbiBwYXJ0aWN1bGFyLCB0aGVyZSBhcmUgdGhyZWUgcmVxdWlyZWQgcGFyYW1ldGVycyB3aGVuIHlvdSBpbnN0YW50aWF0ZSB0aGUgRGF0YSBTZXJ2aWNlOlxuICpcbiAqICogYGFjY291bnRgOiBFcGljZW50ZXIgYWNjb3VudCBpZCAoKipUZWFtIElEKiogZm9yIHRlYW0gcHJvamVjdHMsICoqVXNlciBJRCoqIGZvciBwZXJzb25hbCBwcm9qZWN0cykuXG4gKiAqIGBwcm9qZWN0YDogRXBpY2VudGVyIHByb2plY3QgaWQuXG4gKiAqIGByb290YDogVGhlIHRoZSBuYW1lIG9mIHRoZSBjb2xsZWN0aW9uLiBJZiB5b3UgaGF2ZSBtdWx0aXBsZSBjb2xsZWN0aW9ucyB3aXRoaW4gZWFjaCBvZiB5b3VyIHByb2plY3RzLCB5b3UgY2FuIGFsc28gcGFzcyB0aGUgY29sbGVjdGlvbiBuYW1lIGFzIGFuIG9wdGlvbiBmb3IgZWFjaCBjYWxsLlxuICpcbiAqICAgICAgIHZhciBkcyA9IG5ldyBGLnNlcnZpY2UuRGF0YSh7XG4gKiAgICAgICAgICBhY2NvdW50OiAnYWNtZS1zaW11bGF0aW9ucycsXG4gKiAgICAgICAgICBwcm9qZWN0OiAnc3VwcGx5LWNoYWluLWdhbWUnLFxuICogICAgICAgICAgcm9vdDogJ3N1cnZleS1yZXNwb25zZXMnLFxuICogICAgICAgICAgc2VydmVyOiB7IGhvc3Q6ICdhcGkuZm9yaW8uY29tJyB9XG4gKiAgICAgICB9KTtcbiAqICAgICAgIGRzLnNhdmVBcygndXNlcjEnLFxuICogICAgICAgICAgeyAncXVlc3Rpb24xJzogMiwgJ3F1ZXN0aW9uMic6IDEwLFxuICogICAgICAgICAgJ3F1ZXN0aW9uMyc6IGZhbHNlLCAncXVlc3Rpb240JzogJ3NvbWV0aW1lcycgfSApO1xuICogICAgICAgZHMuc2F2ZUFzKCd1c2VyMicsXG4gKiAgICAgICAgICB7ICdxdWVzdGlvbjEnOiAzLCAncXVlc3Rpb24yJzogOCxcbiAqICAgICAgICAgICdxdWVzdGlvbjMnOiB0cnVlLCAncXVlc3Rpb240JzogJ2Fsd2F5cycgfSApO1xuICogICAgICAgZHMucXVlcnkoJycseyAncXVlc3Rpb24yJzogeyAnJGd0JzogOX0gfSk7XG4gKlxuICogTm90ZSB0aGF0IGluIGFkZGl0aW9uIHRvIHRoZSBgYWNjb3VudGAsIGBwcm9qZWN0YCwgYW5kIGByb290YCwgdGhlIERhdGEgU2VydmljZSBwYXJhbWV0ZXJzIG9wdGlvbmFsbHkgaW5jbHVkZSBhIGBzZXJ2ZXJgIG9iamVjdCwgd2hvc2UgYGhvc3RgIGZpZWxkIGNvbnRhaW5zIHRoZSBVUkkgb2YgdGhlIEZvcmlvIHNlcnZlci4gVGhpcyBpcyBhdXRvbWF0aWNhbGx5IHNldCwgYnV0IHlvdSBjYW4gcGFzcyBpdCBleHBsaWNpdGx5IGlmIGRlc2lyZWQuIEl0IGlzIG1vc3QgY29tbW9ubHkgdXNlZCBmb3IgY2xhcml0eSB3aGVuIHlvdSBhcmUgW2hvc3RpbmcgYW4gRXBpY2VudGVyIHByb2plY3Qgb24geW91ciBvd24gc2VydmVyXSguLi8uLi8uLi9ob3dfdG8vc2VsZl9ob3N0aW5nLykuXG4gKi9cblxuJ3VzZSBzdHJpY3QnO1xuXG52YXIgQ29uZmlnU2VydmljZSA9IHJlcXVpcmUoJy4vY29uZmlndXJhdGlvbi1zZXJ2aWNlJyk7XG52YXIgcXV0aWwgPSByZXF1aXJlKCcuLi91dGlsL3F1ZXJ5LXV0aWwnKTtcbnZhciBUcmFuc3BvcnRGYWN0b3J5ID0gcmVxdWlyZSgnLi4vdHJhbnNwb3J0L2h0dHAtdHJhbnNwb3J0LWZhY3RvcnknKTtcbnZhciBTZXNzaW9uTWFuYWdlciA9IHJlcXVpcmUoJy4uL3N0b3JlL3Nlc3Npb24tbWFuYWdlcicpO1xuXG5tb2R1bGUuZXhwb3J0cyA9IGZ1bmN0aW9uIChjb25maWcpIHtcbiAgICB2YXIgZGVmYXVsdHMgPSB7XG4gICAgICAgIC8qKlxuICAgICAgICAgKiBOYW1lIG9mIGNvbGxlY3Rpb24uIFJlcXVpcmVkLiBEZWZhdWx0cyB0byBgL2AsIHRoYXQgaXMsIHRoZSByb290IGxldmVsIG9mIHlvdXIgcHJvamVjdCBhdCBgZm9yaW8uY29tL2FwcC95b3VyLWFjY291bnQtaWQveW91ci1wcm9qZWN0LWlkL2AsIGJ1dCBtdXN0IGJlIHNldCB0byBhIGNvbGxlY3Rpb24gbmFtZS5cbiAgICAgICAgICogQHR5cGUge1N0cmluZ31cbiAgICAgICAgICovXG4gICAgICAgIHJvb3Q6ICcvJyxcblxuICAgICAgICAvKipcbiAgICAgICAgICogVGhlIGFjY291bnQgaWQuIEluIHRoZSBFcGljZW50ZXIgVUksIHRoaXMgaXMgdGhlICoqVGVhbSBJRCoqIChmb3IgdGVhbSBwcm9qZWN0cykgb3IgKipVc2VyIElEKiogKGZvciBwZXJzb25hbCBwcm9qZWN0cykuIERlZmF1bHRzIHRvIGVtcHR5IHN0cmluZy4gSWYgbGVmdCB1bmRlZmluZWQsIHRha2VuIGZyb20gdGhlIFVSTC5cbiAgICAgICAgICogQHR5cGUge1N0cmluZ31cbiAgICAgICAgICovXG4gICAgICAgIGFjY291bnQ6IHVuZGVmaW5lZCxcblxuICAgICAgICAvKipcbiAgICAgICAgICogVGhlIHByb2plY3QgaWQuIERlZmF1bHRzIHRvIGVtcHR5IHN0cmluZy4gSWYgbGVmdCB1bmRlZmluZWQsIHRha2VuIGZyb20gdGhlIFVSTC5cbiAgICAgICAgICogQHR5cGUge1N0cmluZ31cbiAgICAgICAgICovXG4gICAgICAgIHByb2plY3Q6IHVuZGVmaW5lZCxcblxuICAgICAgICAvKipcbiAgICAgICAgICogRm9yIG9wZXJhdGlvbnMgdGhhdCByZXF1aXJlIGF1dGhlbnRpY2F0aW9uLCBwYXNzIGluIHRoZSB1c2VyIGFjY2VzcyB0b2tlbiAoZGVmYXVsdHMgdG8gZW1wdHkgc3RyaW5nKS4gSWYgdGhlIHVzZXIgaXMgYWxyZWFkeSBsb2dnZWQgaW4gdG8gRXBpY2VudGVyLCB0aGUgdXNlciBhY2Nlc3MgdG9rZW4gaXMgYWxyZWFkeSBzZXQgaW4gYSBjb29raWUgYW5kIGF1dG9tYXRpY2FsbHkgbG9hZGVkIGZyb20gdGhlcmUuIChTZWUgW21vcmUgYmFja2dyb3VuZCBvbiBhY2Nlc3MgdG9rZW5zXSguLi8uLi8uLi9wcm9qZWN0X2FjY2Vzcy8pKS5cbiAgICAgICAgICogQHNlZSBbQXV0aGVudGljYXRpb24gQVBJIFNlcnZpY2VdKC4uL2F1dGgtYXBpLXNlcnZpY2UvKSBmb3IgZ2V0dGluZyB0b2tlbnMuXG4gICAgICAgICAqIEB0eXBlIHtTdHJpbmd9XG4gICAgICAgICAqL1xuICAgICAgICB0b2tlbjogdW5kZWZpbmVkLFxuXG4gICAgICAgIC8vT3B0aW9ucyB0byBwYXNzIG9uIHRvIHRoZSB1bmRlcmx5aW5nIHRyYW5zcG9ydCBsYXllclxuICAgICAgICB0cmFuc3BvcnQ6IHt9XG4gICAgfTtcbiAgICB0aGlzLnNlc3Npb25NYW5hZ2VyID0gbmV3IFNlc3Npb25NYW5hZ2VyKCk7XG4gICAgdmFyIHNlcnZpY2VPcHRpb25zID0gdGhpcy5zZXNzaW9uTWFuYWdlci5nZXRNZXJnZWRPcHRpb25zKGRlZmF1bHRzLCBjb25maWcpO1xuXG4gICAgdmFyIHVybENvbmZpZyA9IG5ldyBDb25maWdTZXJ2aWNlKHNlcnZpY2VPcHRpb25zKS5nZXQoJ3NlcnZlcicpO1xuICAgIGlmIChzZXJ2aWNlT3B0aW9ucy5hY2NvdW50KSB7XG4gICAgICAgIHVybENvbmZpZy5hY2NvdW50UGF0aCA9IHNlcnZpY2VPcHRpb25zLmFjY291bnQ7XG4gICAgfVxuICAgIGlmIChzZXJ2aWNlT3B0aW9ucy5wcm9qZWN0KSB7XG4gICAgICAgIHVybENvbmZpZy5wcm9qZWN0UGF0aCA9IHNlcnZpY2VPcHRpb25zLnByb2plY3Q7XG4gICAgfVxuXG4gICAgdmFyIGdldFVSTCA9IGZ1bmN0aW9uIChrZXksIHJvb3QpIHtcbiAgICAgICAgaWYgKCFyb290KSB7XG4gICAgICAgICAgICByb290ID0gc2VydmljZU9wdGlvbnMucm9vdDtcbiAgICAgICAgfVxuICAgICAgICB2YXIgdXJsID0gdXJsQ29uZmlnLmdldEFQSVBhdGgoJ2RhdGEnKSArIHF1dGlsLmFkZFRyYWlsaW5nU2xhc2gocm9vdCk7XG4gICAgICAgIGlmIChrZXkpIHtcbiAgICAgICAgICAgIHVybCArPSBxdXRpbC5hZGRUcmFpbGluZ1NsYXNoKGtleSk7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIHVybDtcbiAgICB9O1xuXG4gICAgdmFyIGh0dHBPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sIHNlcnZpY2VPcHRpb25zLnRyYW5zcG9ydCwge1xuICAgICAgICB1cmw6IGdldFVSTFxuICAgIH0pO1xuICAgIGlmIChzZXJ2aWNlT3B0aW9ucy50b2tlbikge1xuICAgICAgICBodHRwT3B0aW9ucy5oZWFkZXJzID0ge1xuICAgICAgICAgICAgQXV0aG9yaXphdGlvbjogJ0JlYXJlciAnICsgc2VydmljZU9wdGlvbnMudG9rZW5cbiAgICAgICAgfTtcbiAgICB9XG4gICAgdmFyIGh0dHAgPSBuZXcgVHJhbnNwb3J0RmFjdG9yeShodHRwT3B0aW9ucyk7XG5cbiAgICB2YXIgcHVibGljQVBJID0ge1xuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBTZWFyY2ggZm9yIGRhdGEgd2l0aGluIGEgY29sbGVjdGlvbi5cbiAgICAgICAgICpcbiAgICAgICAgICogU2VhcmNoaW5nIHVzaW5nIGNvbXBhcmlzb24gb3IgbG9naWNhbCBvcGVyYXRvcnMgKGFzIG9wcG9zZWQgdG8gZXhhY3QgbWF0Y2hlcykgcmVxdWlyZXMgTW9uZ29EQiBzeW50YXguIFNlZSB0aGUgdW5kZXJseWluZyBbRGF0YSBBUEldKC4uLy4uLy4uL3Jlc3RfYXBpcy9kYXRhX2FwaS8jc2VhcmNoaW5nKSBmb3IgYWRkaXRpb25hbCBkZXRhaWxzLlxuICAgICAgICAgKlxuICAgICAgICAgKiAqKkV4YW1wbGVzKipcbiAgICAgICAgICpcbiAgICAgICAgICogICAgICAvLyByZXF1ZXN0IGFsbCBkYXRhIGFzc29jaWF0ZWQgd2l0aCBkb2N1bWVudCAndXNlcjEnXG4gICAgICAgICAqICAgICAgZHMucXVlcnkoJ3VzZXIxJyk7XG4gICAgICAgICAqXG4gICAgICAgICAqICAgICAgLy8gZXhhY3QgbWF0Y2hpbmc6XG4gICAgICAgICAqICAgICAgLy8gcmVxdWVzdCBhbGwgZG9jdW1lbnRzIGluIGNvbGxlY3Rpb24gd2hlcmUgJ3F1ZXN0aW9uMicgaXMgOVxuICAgICAgICAgKiAgICAgIGRzLnF1ZXJ5KCcnLCB7ICdxdWVzdGlvbjInOiA5fSk7XG4gICAgICAgICAqXG4gICAgICAgICAqICAgICAgLy8gY29tcGFyaXNvbiBvcGVyYXRvcnM6XG4gICAgICAgICAqICAgICAgLy8gcmVxdWVzdCBhbGwgZG9jdW1lbnRzIGluIGNvbGxlY3Rpb25cbiAgICAgICAgICogICAgICAvLyB3aGVyZSAncXVlc3Rpb24yJyBpcyBncmVhdGVyIHRoYW4gOVxuICAgICAgICAgKiAgICAgIGRzLnF1ZXJ5KCcnLCB7ICdxdWVzdGlvbjInOiB7ICckZ3QnOiA5fSB9KTtcbiAgICAgICAgICpcbiAgICAgICAgICogICAgICAvLyBsb2dpY2FsIG9wZXJhdG9yczpcbiAgICAgICAgICogICAgICAvLyByZXF1ZXN0IGFsbCBkb2N1bWVudHMgaW4gY29sbGVjdGlvblxuICAgICAgICAgKiAgICAgIC8vIHdoZXJlICdxdWVzdGlvbjInIGlzIGxlc3MgdGhhbiAxMCwgYW5kICdxdWVzdGlvbjMnIGlzIGZhbHNlXG4gICAgICAgICAqICAgICAgZHMucXVlcnkoJycsIHsgJyRhbmQnOiBbIHsgJ3F1ZXN0aW9uMic6IHsgJyRsdCc6MTB9IH0sIHsgJ3F1ZXN0aW9uMyc6IGZhbHNlIH1dIH0pO1xuICAgICAgICAgKlxuICAgICAgICAgKiAgICAgIC8vIHJlZ3VsYXIgZXhwcmVzc3Npb25zOiB1c2UgYW55IFBlcmwtY29tcGF0aWJsZSByZWd1bGFyIGV4cHJlc3Npb25zXG4gICAgICAgICAqICAgICAgLy8gcmVxdWVzdCBhbGwgZG9jdW1lbnRzIGluIGNvbGxlY3Rpb25cbiAgICAgICAgICogICAgICAvLyB3aGVyZSAncXVlc3Rpb241JyBjb250YWlucyB0aGUgc3RyaW5nICcuKmRheSdcbiAgICAgICAgICogICAgICBkcy5xdWVyeSgnJywgeyAncXVlc3Rpb241JzogeyAnJHJlZ2V4JzogJy4qZGF5JyB9IH0pO1xuICAgICAgICAgKlxuICAgICAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAgKiBAcGFyYW0ge1N0cmluZ30ga2V5IFRoZSBuYW1lIG9mIHRoZSBkb2N1bWVudCB0byBzZWFyY2guIFBhc3MgdGhlIGVtcHR5IHN0cmluZyAoJycpIHRvIHNlYXJjaCB0aGUgZW50aXJlIGNvbGxlY3Rpb24uXG4gICAgICAgICAqIEBwYXJhbSB7T2JqZWN0fSBxdWVyeSBUaGUgcXVlcnkgb2JqZWN0LiBGb3IgZXhhY3QgbWF0Y2hpbmcsIHRoaXMgb2JqZWN0IGNvbnRhaW5zIHRoZSBmaWVsZCBuYW1lIGFuZCBmaWVsZCB2YWx1ZSB0byBtYXRjaC4gRm9yIG1hdGNoaW5nIGJhc2VkIG9uIGNvbXBhcmlzb24sIHRoaXMgb2JqZWN0IGNvbnRhaW5zIHRoZSBmaWVsZCBuYW1lIGFuZCB0aGUgY29tcGFyaXNvbiBleHByZXNzaW9uLiBGb3IgbWF0Y2hpbmcgYmFzZWQgb24gbG9naWNhbCBvcGVyYXRvcnMsIHRoaXMgb2JqZWN0IGNvbnRhaW5zIGFuIGV4cHJlc3Npb24gdXNpbmcgTW9uZ29EQiBzeW50YXguIFNlZSB0aGUgdW5kZXJseWluZyBbRGF0YSBBUEldKC4uLy4uLy4uL3Jlc3RfYXBpcy9kYXRhX2FwaS8jc2VhcmNoaW5nKSBmb3IgYWRkaXRpb25hbCBleGFtcGxlcy5cbiAgICAgICAgICogQHBhcmFtIHtPYmplY3R9IG91dHB1dE1vZGlmaWVyIChPcHRpb25hbCkgQXZhaWxhYmxlIGZpZWxkcyBpbmNsdWRlOiBgc3RhcnRyZWNvcmRgLCBgZW5kcmVjb3JkYCwgYHNvcnRgLCBhbmQgYGRpcmVjdGlvbmAgKGBhc2NgIG9yIGBkZXNjYCkuXG4gICAgICAgICAqIEBwYXJhbSB7T2JqZWN0fSBvcHRpb25zIChPcHRpb25hbCkgT3ZlcnJpZGVzIGZvciBjb25maWd1cmF0aW9uIG9wdGlvbnMuXG4gICAgICAgICAqIEByZXR1cm4ge1Byb21pc2V9IFxuICAgICAgICAgKi9cbiAgICAgICAgcXVlcnk6IGZ1bmN0aW9uIChrZXksIHF1ZXJ5LCBvdXRwdXRNb2RpZmllciwgb3B0aW9ucykge1xuICAgICAgICAgICAgdmFyIHBhcmFtcyA9ICQuZXh0ZW5kKHRydWUsIHsgcTogcXVlcnkgfSwgb3V0cHV0TW9kaWZpZXIpO1xuICAgICAgICAgICAgdmFyIGh0dHBPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sIHNlcnZpY2VPcHRpb25zLCBvcHRpb25zKTtcbiAgICAgICAgICAgIGh0dHBPcHRpb25zLnVybCA9IGdldFVSTChrZXksIGh0dHBPcHRpb25zLnJvb3QpO1xuICAgICAgICAgICAgcmV0dXJuIGh0dHAuZ2V0KHBhcmFtcywgaHR0cE9wdGlvbnMpO1xuICAgICAgICB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBTYXZlIGRhdGEgaW4gYW4gYW5vbnltb3VzIGRvY3VtZW50IHdpdGhpbiB0aGUgY29sbGVjdGlvbi5cbiAgICAgICAgICpcbiAgICAgICAgICogVGhlIGByb290YCBvZiB0aGUgY29sbGVjdGlvbiBtdXN0IGJlIHNwZWNpZmllZC4gQnkgZGVmYXVsdCB0aGUgYHJvb3RgIGlzIHRha2VuIGZyb20gdGhlIERhdGEgU2VydmljZSBjb25maWd1cmF0aW9uIG9wdGlvbnM7IHlvdSBjYW4gYWxzbyBwYXNzIHRoZSBgcm9vdGAgdG8gdGhlIGBzYXZlYCBjYWxsIGV4cGxpY2l0bHkgYnkgb3ZlcnJpZGluZyB0aGUgb3B0aW9ucyAodGhpcmQgcGFyYW1ldGVyKS5cbiAgICAgICAgICpcbiAgICAgICAgICogKEFkZGl0aW9uYWwgYmFja2dyb3VuZDogRG9jdW1lbnRzIGFyZSB0b3AtbGV2ZWwgZWxlbWVudHMgd2l0aGluIGEgY29sbGVjdGlvbi4gQ29sbGVjdGlvbnMgbXVzdCBiZSB1bmlxdWUgd2l0aGluIHRoaXMgYWNjb3VudCAodGVhbSBvciBwZXJzb25hbCBhY2NvdW50KSBhbmQgcHJvamVjdCBhbmQgYXJlIHNldCB3aXRoIHRoZSBgcm9vdGAgZmllbGQgaW4gdGhlIGBvcHRpb25gIHBhcmFtZXRlci4gU2VlIHRoZSB1bmRlcmx5aW5nIFtEYXRhIEFQSV0oLi4vLi4vLi4vcmVzdF9hcGlzL2RhdGFfYXBpLykgZm9yIG1vcmUgaW5mb3JtYXRpb24uIFRoZSBgc2F2ZWAgbWV0aG9kIGlzIG1ha2luZyBhIGBQT1NUYCByZXF1ZXN0LilcbiAgICAgICAgICpcbiAgICAgICAgICogKipFeGFtcGxlKipcbiAgICAgICAgICpcbiAgICAgICAgICogICAgICAvLyBDcmVhdGUgYSBuZXcgZG9jdW1lbnQsIHdpdGggb25lIGVsZW1lbnQsIGF0IHRoZSBkZWZhdWx0IHJvb3QgbGV2ZWxcbiAgICAgICAgICogICAgICBkcy5zYXZlKCdxdWVzdGlvbjEnLCAneWVzJyk7XG4gICAgICAgICAqXG4gICAgICAgICAqICAgICAgLy8gQ3JlYXRlIGEgbmV3IGRvY3VtZW50LCB3aXRoIHR3byBlbGVtZW50cywgYXQgdGhlIGRlZmF1bHQgcm9vdCBsZXZlbFxuICAgICAgICAgKiAgICAgIGRzLnNhdmUoeyBxdWVzdGlvbjE6J3llcycsIHF1ZXN0aW9uMjogMzIgfSk7XG4gICAgICAgICAqXG4gICAgICAgICAqICAgICAgLy8gQ3JlYXRlIGEgbmV3IGRvY3VtZW50LCB3aXRoIHR3byBlbGVtZW50cywgYXQgYC9zdHVkZW50cy9gXG4gICAgICAgICAqICAgICAgZHMuc2F2ZSh7IG5hbWU6J0pvaG4nLCBjbGFzc05hbWU6ICdDUzEwMScgfSwgeyByb290OiAnc3R1ZGVudHMnIH0pO1xuICAgICAgICAgKlxuICAgICAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAgKlxuICAgICAgICAgKiBAcGFyYW0ge1N0cmluZ3xPYmplY3R9IGtleSBJZiBga2V5YCBpcyBhIHN0cmluZywgaXQgaXMgdGhlIGlkIG9mIHRoZSBlbGVtZW50IHRvIHNhdmUgKGNyZWF0ZSkgaW4gdGhpcyBkb2N1bWVudC4gSWYgYGtleWAgaXMgYW4gb2JqZWN0LCB0aGUgb2JqZWN0IGlzIHRoZSBkYXRhIHRvIHNhdmUgKGNyZWF0ZSkgaW4gdGhpcyBkb2N1bWVudC4gSW4gYm90aCBjYXNlcywgdGhlIGlkIGZvciB0aGUgZG9jdW1lbnQgaXMgZ2VuZXJhdGVkIGF1dG9tYXRpY2FsbHkuXG4gICAgICAgICAqIEBwYXJhbSB7T2JqZWN0fSB2YWx1ZSAoT3B0aW9uYWwpIFRoZSBkYXRhIHRvIHNhdmUuIElmIGBrZXlgIGlzIGEgc3RyaW5nLCB0aGlzIGlzIHRoZSB2YWx1ZSB0byBzYXZlLiBJZiBga2V5YCBpcyBhbiBvYmplY3QsIHRoZSB2YWx1ZShzKSB0byBzYXZlIGFyZSBhbHJlYWR5IHBhcnQgb2YgYGtleWAgYW5kIHRoaXMgYXJndW1lbnQgaXMgbm90IHJlcXVpcmVkLlxuICAgICAgICAgKiBAcGFyYW0ge09iamVjdH0gb3B0aW9ucyAoT3B0aW9uYWwpIE92ZXJyaWRlcyBmb3IgY29uZmlndXJhdGlvbiBvcHRpb25zLiBJZiB5b3Ugd2FudCB0byBvdmVycmlkZSB0aGUgZGVmYXVsdCBgcm9vdGAgb2YgdGhlIGNvbGxlY3Rpb24sIGRvIHNvIGhlcmUuXG4gICAgICAgICAqIEByZXR1cm4ge1Byb21pc2V9IFxuICAgICAgICAgKi9cbiAgICAgICAgc2F2ZTogZnVuY3Rpb24gKGtleSwgdmFsdWUsIG9wdGlvbnMpIHtcbiAgICAgICAgICAgIHZhciBhdHRycztcbiAgICAgICAgICAgIGlmICh0eXBlb2Yga2V5ID09PSAnb2JqZWN0Jykge1xuICAgICAgICAgICAgICAgIGF0dHJzID0ga2V5O1xuICAgICAgICAgICAgICAgIG9wdGlvbnMgPSB2YWx1ZTtcbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgKGF0dHJzID0ge30pW2tleV0gPSB2YWx1ZTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHZhciBodHRwT3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LCBzZXJ2aWNlT3B0aW9ucywgb3B0aW9ucyk7XG4gICAgICAgICAgICBodHRwT3B0aW9ucy51cmwgPSBnZXRVUkwoJycsIGh0dHBPcHRpb25zLnJvb3QpO1xuXG4gICAgICAgICAgICByZXR1cm4gaHR0cC5wb3N0KGF0dHJzLCBodHRwT3B0aW9ucyk7XG4gICAgICAgIH0sXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIFNhdmUgKGNyZWF0ZSBvciByZXBsYWNlKSBkYXRhIGluIGEgbmFtZWQgZG9jdW1lbnQgb3IgZWxlbWVudCB3aXRoaW4gdGhlIGNvbGxlY3Rpb24uIFxuICAgICAgICAgKiBcbiAgICAgICAgICogVGhlIGByb290YCBvZiB0aGUgY29sbGVjdGlvbiBtdXN0IGJlIHNwZWNpZmllZC4gQnkgZGVmYXVsdCB0aGUgYHJvb3RgIGlzIHRha2VuIGZyb20gdGhlIERhdGEgU2VydmljZSBjb25maWd1cmF0aW9uIG9wdGlvbnM7IHlvdSBjYW4gYWxzbyBwYXNzIHRoZSBgcm9vdGAgdG8gdGhlIGBzYXZlQXNgIGNhbGwgZXhwbGljaXRseSBieSBvdmVycmlkaW5nIHRoZSBvcHRpb25zICh0aGlyZCBwYXJhbWV0ZXIpLlxuICAgICAgICAgKlxuICAgICAgICAgKiBPcHRpb25hbGx5LCB0aGUgbmFtZWQgZG9jdW1lbnQgb3IgZWxlbWVudCBjYW4gaW5jbHVkZSBwYXRoIGluZm9ybWF0aW9uLCBzbyB0aGF0IHlvdSBhcmUgc2F2aW5nIGp1c3QgcGFydCBvZiB0aGUgZG9jdW1lbnQuXG4gICAgICAgICAqXG4gICAgICAgICAqIChBZGRpdGlvbmFsIGJhY2tncm91bmQ6IERvY3VtZW50cyBhcmUgdG9wLWxldmVsIGVsZW1lbnRzIHdpdGhpbiBhIGNvbGxlY3Rpb24uIENvbGxlY3Rpb25zIG11c3QgYmUgdW5pcXVlIHdpdGhpbiB0aGlzIGFjY291bnQgKHRlYW0gb3IgcGVyc29uYWwgYWNjb3VudCkgYW5kIHByb2plY3QgYW5kIGFyZSBzZXQgd2l0aCB0aGUgYHJvb3RgIGZpZWxkIGluIHRoZSBgb3B0aW9uYCBwYXJhbWV0ZXIuIFNlZSB0aGUgdW5kZXJseWluZyBbRGF0YSBBUEldKC4uLy4uLy4uL3Jlc3RfYXBpcy9kYXRhX2FwaS8pIGZvciBtb3JlIGluZm9ybWF0aW9uLiBUaGUgYHNhdmVBc2AgbWV0aG9kIGlzIG1ha2luZyBhIGBQVVRgIHJlcXVlc3QuKVxuICAgICAgICAgKlxuICAgICAgICAgKiAqKkV4YW1wbGUqKlxuICAgICAgICAgKlxuICAgICAgICAgKiAgICAgIC8vIENyZWF0ZSAob3IgcmVwbGFjZSkgdGhlIGB1c2VyMWAgZG9jdW1lbnQgYXQgdGhlIGRlZmF1bHQgcm9vdCBsZXZlbC5cbiAgICAgICAgICogICAgICAvLyBOb3RlIHRoYXQgdGhpcyByZXBsYWNlcyBhbnkgZXhpc3RpbmcgY29udGVudCBpbiB0aGUgYHVzZXIxYCBkb2N1bWVudC5cbiAgICAgICAgICogICAgICBkcy5zYXZlQXMoJ3VzZXIxJyxcbiAgICAgICAgICogICAgICAgICAgeyAncXVlc3Rpb24xJzogMiwgJ3F1ZXN0aW9uMic6IDEwLFxuICAgICAgICAgKiAgICAgICAgICAgJ3F1ZXN0aW9uMyc6IGZhbHNlLCAncXVlc3Rpb240JzogJ3NvbWV0aW1lcycgfSApO1xuICAgICAgICAgKlxuICAgICAgICAgKiAgICAgIC8vIENyZWF0ZSAob3IgcmVwbGFjZSkgdGhlIGBzdHVkZW50MWAgZG9jdW1lbnQgYXQgdGhlIGBzdHVkZW50c2Agcm9vdCwgXG4gICAgICAgICAqICAgICAgLy8gdGhhdCBpcywgdGhlIGRhdGEgYXQgYC9zdHVkZW50cy9zdHVkZW50MS9gLlxuICAgICAgICAgKiAgICAgIC8vIE5vdGUgdGhhdCB0aGlzIHJlcGxhY2VzIGFueSBleGlzdGluZyBjb250ZW50IGluIHRoZSBgL3N0dWRlbnRzL3N0dWRlbnQxL2AgZG9jdW1lbnQuXG4gICAgICAgICAqICAgICAgLy8gSG93ZXZlciwgdGhpcyB3aWxsIGtlZXAgZXhpc3RpbmcgY29udGVudCBpbiBvdGhlciBwYXRocyBvZiB0aGlzIGNvbGxlY3Rpb24uXG4gICAgICAgICAqICAgICAgLy8gRm9yIGV4YW1wbGUsIHRoZSBkYXRhIGF0IGAvc3R1ZGVudHMvc3R1ZGVudDIvYCBpcyB1bmNoYW5nZWQgYnkgdGhpcyBjYWxsLlxuICAgICAgICAgKiAgICAgIGRzLnNhdmVBcygnc3R1ZGVudDEnLFxuICAgICAgICAgKiAgICAgICAgICB7IGZpcnN0TmFtZTogJ2pvaG4nLCBsYXN0TmFtZTogJ3NtaXRoJyB9LFxuICAgICAgICAgKiAgICAgICAgICB7IHJvb3Q6ICdzdHVkZW50cycgfSk7XG4gICAgICAgICAqXG4gICAgICAgICAqICAgICAgLy8gQ3JlYXRlIChvciByZXBsYWNlKSB0aGUgYG1nbXQxMDAvZ3JvdXBCYCBkb2N1bWVudCBhdCB0aGUgYG15Y2xhc3Nlc2Agcm9vdCxcbiAgICAgICAgICogICAgICAvLyB0aGF0IGlzLCB0aGUgZGF0YSBhdCBgL215Y2xhc3Nlcy9tZ210MTAwL2dyb3VwQi9gLlxuICAgICAgICAgKiAgICAgIC8vIE5vdGUgdGhhdCB0aGlzIHJlcGxhY2VzIGFueSBleGlzdGluZyBjb250ZW50IGluIHRoZSBgL215Y2xhc3Nlcy9tZ210MTAwL2dyb3VwQi9gIGRvY3VtZW50LlxuICAgICAgICAgKiAgICAgIC8vIEhvd2V2ZXIsIHRoaXMgd2lsbCBrZWVwIGV4aXN0aW5nIGNvbnRlbnQgaW4gb3RoZXIgcGF0aHMgb2YgdGhpcyBjb2xsZWN0aW9uLlxuICAgICAgICAgKiAgICAgIC8vIEZvciBleGFtcGxlLCB0aGUgZGF0YSBhdCBgL215Y2xhc3Nlcy9tZ210MTAwL2dyb3VwQS9gIGlzIHVuY2hhbmdlZCBieSB0aGlzIGNhbGwuXG4gICAgICAgICAqICAgICAgZHMuc2F2ZUFzKCdtZ210MTAwL2dyb3VwQicsXG4gICAgICAgICAqICAgICAgICAgIHsgc2NlbmFyaW9ZZWFyOiAnMjAxNScgfSxcbiAgICAgICAgICogICAgICAgICAgeyByb290OiAnbXljbGFzc2VzJyB9KTtcbiAgICAgICAgICpcbiAgICAgICAgICogKipQYXJhbWV0ZXJzKipcbiAgICAgICAgICpcbiAgICAgICAgICogQHBhcmFtIHtTdHJpbmd9IGtleSBJZCBvZiB0aGUgZG9jdW1lbnQuXG4gICAgICAgICAqIEBwYXJhbSB7T2JqZWN0fSB2YWx1ZSAoT3B0aW9uYWwpIFRoZSBkYXRhIHRvIHNhdmUsIGluIGtleTp2YWx1ZSBwYWlycy5cbiAgICAgICAgICogQHBhcmFtIHtPYmplY3R9IG9wdGlvbnMgKE9wdGlvbmFsKSBPdmVycmlkZXMgZm9yIGNvbmZpZ3VyYXRpb24gb3B0aW9ucy4gSWYgeW91IHdhbnQgdG8gb3ZlcnJpZGUgdGhlIGRlZmF1bHQgYHJvb3RgIG9mIHRoZSBjb2xsZWN0aW9uLCBkbyBzbyBoZXJlLlxuICAgICAgICAgKiBAcmV0dXJuIHtQcm9taXNlfSBcbiAgICAgICAgICovXG4gICAgICAgIHNhdmVBczogZnVuY3Rpb24gKGtleSwgdmFsdWUsIG9wdGlvbnMpIHtcbiAgICAgICAgICAgIHZhciBodHRwT3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LCBzZXJ2aWNlT3B0aW9ucywgb3B0aW9ucyk7XG4gICAgICAgICAgICBodHRwT3B0aW9ucy51cmwgPSBnZXRVUkwoa2V5LCBodHRwT3B0aW9ucy5yb290KTtcblxuICAgICAgICAgICAgcmV0dXJuIGh0dHAucHV0KHZhbHVlLCBodHRwT3B0aW9ucyk7XG4gICAgICAgIH0sXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIEdldCBkYXRhIGZvciBhIHNwZWNpZmljIGRvY3VtZW50IG9yIGZpZWxkLlxuICAgICAgICAgKlxuICAgICAgICAgKiAqKkV4YW1wbGUqKlxuICAgICAgICAgKlxuICAgICAgICAgKiAgICAgIGRzLmxvYWQoJ3VzZXIxJyk7XG4gICAgICAgICAqICAgICAgZHMubG9hZCgndXNlcjEvcXVlc3Rpb24zJyk7XG4gICAgICAgICAqXG4gICAgICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICAgICAqIEBwYXJhbSAge1N0cmluZ3xPYmplY3R9IGtleSBUaGUgaWQgb2YgdGhlIGRhdGEgdG8gcmV0dXJuLiBDYW4gYmUgdGhlIGlkIG9mIGEgZG9jdW1lbnQsIG9yIGEgcGF0aCB0byBkYXRhIHdpdGhpbiB0aGF0IGRvY3VtZW50LlxuICAgICAgICAgKiBAcGFyYW0ge09iamVjdH0gb3V0cHV0TW9kaWZpZXIgKE9wdGlvbmFsKSBBdmFpbGFibGUgZmllbGRzIGluY2x1ZGU6IGBzdGFydHJlY29yZGAsIGBlbmRyZWNvcmRgLCBgc29ydGAsIGFuZCBgZGlyZWN0aW9uYCAoYGFzY2Agb3IgYGRlc2NgKS5cbiAgICAgICAgICogQHBhcmFtIHtPYmplY3R9IG9wdGlvbnMgT3ZlcnJpZGVzIGZvciBjb25maWd1cmF0aW9uIG9wdGlvbnMuXG4gICAgICAgICAqIEByZXR1cm4ge1Byb21pc2V9IFxuICAgICAgICAgKi9cbiAgICAgICAgbG9hZDogZnVuY3Rpb24gKGtleSwgb3V0cHV0TW9kaWZpZXIsIG9wdGlvbnMpIHtcbiAgICAgICAgICAgIHZhciBodHRwT3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LCBzZXJ2aWNlT3B0aW9ucywgb3B0aW9ucyk7XG4gICAgICAgICAgICBodHRwT3B0aW9ucy51cmwgPSBnZXRVUkwoa2V5LCBodHRwT3B0aW9ucy5yb290KTtcbiAgICAgICAgICAgIHJldHVybiBodHRwLmdldChvdXRwdXRNb2RpZmllciwgaHR0cE9wdGlvbnMpO1xuICAgICAgICB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBSZW1vdmVzIGRhdGEgZnJvbSBjb2xsZWN0aW9uLiBPbmx5IGRvY3VtZW50cyAodG9wLWxldmVsIGVsZW1lbnRzIGluIGVhY2ggY29sbGVjdGlvbikgY2FuIGJlIGRlbGV0ZWQuXG4gICAgICAgICAqXG4gICAgICAgICAqICoqRXhhbXBsZSoqXG4gICAgICAgICAqXG4gICAgICAgICAqICAgICBkcy5yZW1vdmUoJ3VzZXIxJyk7XG4gICAgICAgICAqXG4gICAgICAgICAqXG4gICAgICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICAgICAqXG4gICAgICAgICAqIEBwYXJhbSB7U3RyaW5nfEFycmF5fSBrZXlzIFRoZSBpZCBvZiB0aGUgZG9jdW1lbnQgdG8gcmVtb3ZlIGZyb20gdGhpcyBjb2xsZWN0aW9uLCBvciBhbiBhcnJheSBvZiBzdWNoIGlkcy5cbiAgICAgICAgICogQHBhcmFtIHtPYmplY3R9IG9wdGlvbnMgKE9wdGlvbmFsKSBPdmVycmlkZXMgZm9yIGNvbmZpZ3VyYXRpb24gb3B0aW9ucy5cbiAgICAgICAgICogQHJldHVybiB7UHJvbWlzZX0gXG4gICAgICAgICAqL1xuICAgICAgICByZW1vdmU6IGZ1bmN0aW9uIChrZXlzLCBvcHRpb25zKSB7XG4gICAgICAgICAgICB2YXIgaHR0cE9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSwgc2VydmljZU9wdGlvbnMsIG9wdGlvbnMpO1xuICAgICAgICAgICAgdmFyIHBhcmFtcztcbiAgICAgICAgICAgIGlmICgkLmlzQXJyYXkoa2V5cykpIHtcbiAgICAgICAgICAgICAgICBwYXJhbXMgPSB7IGlkOiBrZXlzIH07XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgIHBhcmFtcyA9ICcnO1xuICAgICAgICAgICAgICAgIGh0dHBPcHRpb25zLnVybCA9IGdldFVSTChrZXlzLCBodHRwT3B0aW9ucy5yb290KTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHJldHVybiBodHRwLmRlbGV0ZShwYXJhbXMsIGh0dHBPcHRpb25zKTtcbiAgICAgICAgfVxuXG4gICAgICAgIC8vIEVwaWNlbnRlciBkb2Vzbid0IGFsbG93IG51a2luZyBjb2xsZWN0aW9uc1xuICAgICAgICAvLyAgICAgLyoqXG4gICAgICAgIC8vICAgICAgKiBSZW1vdmVzIGNvbGxlY3Rpb24gYmVpbmcgcmVmZXJlbmNlZFxuICAgICAgICAvLyAgICAgICogQHJldHVybiBudWxsXG4gICAgICAgIC8vICAgICAgKi9cbiAgICAgICAgLy8gICAgIGRlc3Ryb3k6IGZ1bmN0aW9uIChvcHRpb25zKSB7XG4gICAgICAgIC8vICAgICAgICAgcmV0dXJuIHRoaXMucmVtb3ZlKCcnLCBvcHRpb25zKTtcbiAgICAgICAgLy8gICAgIH1cbiAgICB9O1xuXG4gICAgJC5leHRlbmQodGhpcywgcHVibGljQVBJKTtcbn07XG4iLCIvKipcbiAqXG4gKiAjIyBHcm91cCBBUEkgQWRhcHRlclxuICpcbiAqIFRoZSBHcm91cCBBUEkgQWRhcHRlciBwcm92aWRlcyBtZXRob2RzIHRvIGxvb2sgdXAsIGNyZWF0ZSwgY2hhbmdlIG9yIHJlbW92ZSBpbmZvcm1hdGlvbiBhYm91dCBncm91cHMgaW4gYSBwcm9qZWN0LiBJdCBpcyBiYXNlZCBvbiBxdWVyeSBjYXBhYmlsaXRpZXMgb2YgdGhlIHVuZGVybHlpbmcgUkVTVGZ1bCBbR3JvdXAgQVBJXSguLi8uLi8uLi9yZXN0X2FwaXMvdXNlcl9tYW5hZ2VtZW50L2dyb3VwLykuXG4gKlxuICogVGhpcyBpcyBvbmx5IG5lZWRlZCBmb3IgQXV0aGVudGljYXRlZCBwcm9qZWN0cywgdGhhdCBpcywgdGVhbSBwcm9qZWN0cyB3aXRoIFtlbmQgdXNlcnMgYW5kIGdyb3Vwc10oLi4vLi4vLi4vZ3JvdXBzX2FuZF9lbmRfdXNlcnMvKS5cbiAqXG4gKiAgICAgIHZhciBtYSA9IG5ldyBGLnNlcnZpY2UuR3JvdXAoeyB0b2tlbjogJ3VzZXItb3ItcHJvamVjdC1hY2Nlc3MtdG9rZW4nIH0pO1xuICogICAgICBtYS5nZXRHcm91cHNGb3JQcm9qZWN0KHsgYWNjb3VudDogJ2FjbWUnLCBwcm9qZWN0OiAnc2FtcGxlJyB9KTtcbiAqL1xuXG4ndXNlIHN0cmljdCc7XG5cbnZhciBzZXJ2aWNlVXRpbHMgPSByZXF1aXJlKCcuL3NlcnZpY2UtdXRpbHMnKTtcbnZhciBUcmFuc3BvcnRGYWN0b3J5ID0gcmVxdWlyZSgnLi4vdHJhbnNwb3J0L2h0dHAtdHJhbnNwb3J0LWZhY3RvcnknKTtcbnZhciBvYmplY3RBc3NpZ24gPSByZXF1aXJlKCdvYmplY3QtYXNzaWduJyk7XG5cbnZhciBhcGlFbmRwb2ludCA9ICdncm91cC9sb2NhbCc7XG5cbnZhciBHcm91cFNlcnZpY2UgPSBmdW5jdGlvbiAoY29uZmlnKSB7XG4gICAgdmFyIGRlZmF1bHRzID0ge1xuICAgICAgICAvKipcbiAgICAgICAgICogRXBpY2VudGVyIGFjY291bnQgbmFtZS4gRGVmYXVsdHMgdG8gdW5kZWZpbmVkLlxuICAgICAgICAgKiBAdHlwZSB7c3RyaW5nfVxuICAgICAgICAgKi9cbiAgICAgICAgYWNjb3VudDogdW5kZWZpbmVkLFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBFcGljZW50ZXIgcHJvamVjdCBuYW1lLiBEZWZhdWx0cyB0byB1bmRlZmluZWQuXG4gICAgICAgICAqIEB0eXBlIHtzdHJpbmd9XG4gICAgICAgICAqL1xuICAgICAgICBwcm9qZWN0OiB1bmRlZmluZWQsXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIE9wdGlvbnMgdG8gcGFzcyBvbiB0byB0aGUgdW5kZXJseWluZyB0cmFuc3BvcnQgbGF5ZXIuIEFsbCBqcXVlcnkuYWpheCBvcHRpb25zIGF0IGh0dHA6Ly9hcGkuanF1ZXJ5LmNvbS9qUXVlcnkuYWpheC8gYXJlIGF2YWlsYWJsZS4gRGVmYXVsdHMgdG8gZW1wdHkgb2JqZWN0LlxuICAgICAgICAgKiBAdHlwZSB7b2JqZWN0fVxuICAgICAgICAgKi9cbiAgICAgICAgdHJhbnNwb3J0OiB7fVxuICAgIH07XG4gICAgdmFyIHNlcnZpY2VPcHRpb25zID0gc2VydmljZVV0aWxzLmdldERlZmF1bHRPcHRpb25zKGRlZmF1bHRzLCBjb25maWcsIHsgYXBpRW5kcG9pbnQ6IGFwaUVuZHBvaW50IH0pO1xuICAgIHZhciB0cmFuc3BvcnRPcHRpb25zID0gc2VydmljZU9wdGlvbnMudHJhbnNwb3J0O1xuICAgIGRlbGV0ZSBzZXJ2aWNlT3B0aW9ucy50cmFuc3BvcnQ7XG4gICAgdmFyIGh0dHAgPSBuZXcgVHJhbnNwb3J0RmFjdG9yeSh0cmFuc3BvcnRPcHRpb25zLCBzZXJ2aWNlT3B0aW9ucyk7XG4gICAgdmFyIHB1YmxpY0FQSSA9IHtcbiAgICAgICAgLyoqXG4gICAgICAgICogR2V0cyBpbmZvcm1hdGlvbiBmb3IgYSBncm91cCBvciBtdWx0aXBsZSBncm91cHMuXG4gICAgICAgICogQHBhcmFtIHtPYmplY3R9IHBhcmFtcyBvYmplY3Qgd2l0aCBxdWVyeSBwYXJhbWV0ZXJzXG4gICAgICAgICogQHBhdGFtIHtzdHJpbmd9IHBhcmFtcy5xIHBhcnRpYWwgbWF0Y2ggZm9yIG5hbWUsIG9yZ2FuaXphdGlvbiBvciBldmVudC5cbiAgICAgICAgKiBAcGF0YW0ge3N0cmluZ30gcGFyYW1zLmFjY291bnQgRXBpY2VudGVyJ3MgVGVhbSBJRFxuICAgICAgICAqIEBwYXRhbSB7c3RyaW5nfSBwYXJhbXMucHJvamVjdCBFcGljZW50ZXIncyBQcm9qZWN0IElEXG4gICAgICAgICogQHBhdGFtIHtzdHJpbmd9IHBhcmFtcy5uYW1lIEVwaWNlbnRlcidzIEdyb3VwIE5hbWVcbiAgICAgICAgKiBAcGFyYW0ge09iamVjdH0gb3B0aW9ucyAoT3B0aW9uYWwpIE92ZXJyaWRlcyBmb3IgY29uZmlndXJhdGlvbiBvcHRpb25zLlxuICAgICAgICAqIEByZXR1cm4ge1Byb21pc2V9XG4gICAgICAgICovXG4gICAgICAgIGdldEdyb3VwczogZnVuY3Rpb24gKHBhcmFtcywgb3B0aW9ucykge1xuICAgICAgICAgICAgLy9ncm91cElEIGlzIHBhcnQgb2YgdGhlIFVSTFxuICAgICAgICAgICAgLy9xLCBhY2NvdW50IGFuZCBwcm9qZWN0IGFyZSBwYXJ0IG9mIHRoZSBxdWVyeSBzdHJpbmdcbiAgICAgICAgICAgIHZhciBmaW5hbE9wdHMgPSBvYmplY3RBc3NpZ24oe30sIHNlcnZpY2VPcHRpb25zLCBvcHRpb25zKTtcbiAgICAgICAgICAgIHZhciBmaW5hbFBhcmFtcztcbiAgICAgICAgICAgIGlmICh0eXBlb2YgcGFyYW1zID09PSAnc3RyaW5nJykge1xuICAgICAgICAgICAgICAgIGZpbmFsT3B0cy51cmwgPSBzZXJ2aWNlVXRpbHMuZ2V0QXBpVXJsKGFwaUVuZHBvaW50ICsgJy8nICsgcGFyYW1zLCBmaW5hbE9wdHMpO1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICBmaW5hbFBhcmFtcyA9IHBhcmFtcztcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHJldHVybiBodHRwLmdldChmaW5hbFBhcmFtcywgZmluYWxPcHRzKTtcbiAgICAgICAgfVxuICAgIH07XG4gICAgb2JqZWN0QXNzaWduKHRoaXMsIHB1YmxpY0FQSSk7XG59O1xuXG5tb2R1bGUuZXhwb3J0cyA9IEdyb3VwU2VydmljZTtcbiIsIi8qKlxuICpcbiAqICMjIEludHJvc3BlY3Rpb24gQVBJIFNlcnZpY2VcbiAqXG4gKiBUaGUgSW50cm9zcGVjdGlvbiBBUEkgU2VydmljZSBhbGxvd3MgeW91IHRvIHZpZXcgYSBsaXN0IG9mIHRoZSB2YXJpYWJsZXMgYW5kIG9wZXJhdGlvbnMgaW4gYSBtb2RlbC4gVHlwaWNhbGx5IHVzZWQgaW4gY29uanVuY3Rpb24gd2l0aCB0aGUgW1J1biBBUEkgU2VydmljZV0oLi4vcnVuLWFwaS1zZXJ2aWNlLykuXG4gKlxuICogVGhlIEludHJvc3BlY3Rpb24gQVBJIFNlcnZpY2UgaXMgbm90IGF2YWlsYWJsZSBmb3IgRm9yaW8gU2ltTGFuZy5cbiAqXG4gKiAgICAgICB2YXIgaW50cm8gPSBuZXcgRi5zZXJ2aWNlLkludHJvc3BlY3Qoe1xuICogICAgICAgICAgICAgICBhY2NvdW50OiAnYWNtZS1zaW11bGF0aW9ucycsXG4gKiAgICAgICAgICAgICAgIHByb2plY3Q6ICdzdXBwbHktY2hhaW4tZ2FtZSdcbiAqICAgICAgIH0pO1xuICogICAgICAgaW50cm8uYnlNb2RlbCgnc3VwcGx5LWNoYWluLnB5JykudGhlbihmdW5jdGlvbihkYXRhKXsgLi4uIH0pO1xuICogICAgICAgaW50cm8uYnlSdW5JRCgnMmI0ZDhmNzEtNWMzNC00MzVhLThjMTYtOWRlNjc0YWI3MmU2JykudGhlbihmdW5jdGlvbihkYXRhKXsgLi4uIH0pO1xuICpcbiAqL1xuXG4ndXNlIHN0cmljdCc7XG5cbnZhciBDb25maWdTZXJ2aWNlID0gcmVxdWlyZSgnLi9jb25maWd1cmF0aW9uLXNlcnZpY2UnKTtcbnZhciBUcmFuc3BvcnRGYWN0b3J5ID0gcmVxdWlyZSgnLi4vdHJhbnNwb3J0L2h0dHAtdHJhbnNwb3J0LWZhY3RvcnknKTtcbnZhciBTZXNzaW9uTWFuYWdlciA9IHJlcXVpcmUoJy4uL3N0b3JlL3Nlc3Npb24tbWFuYWdlcicpO1xuXG52YXIgYXBpRW5kcG9pbnQgPSAnbW9kZWwvaW50cm9zcGVjdCc7XG5cbm1vZHVsZS5leHBvcnRzID0gZnVuY3Rpb24gKGNvbmZpZykge1xuICAgIHZhciBkZWZhdWx0cyA9IHtcbiAgICAgICAgLyoqXG4gICAgICAgICAqIEZvciBwcm9qZWN0cyB0aGF0IHJlcXVpcmUgYXV0aGVudGljYXRpb24sIHBhc3MgaW4gdGhlIHVzZXIgYWNjZXNzIHRva2VuIChkZWZhdWx0cyB0byBlbXB0eSBzdHJpbmcpLiBJZiB0aGUgdXNlciBpcyBhbHJlYWR5IGxvZ2dlZCBpbiB0byBFcGljZW50ZXIsIHRoZSB1c2VyIGFjY2VzcyB0b2tlbiBpcyBhbHJlYWR5IHNldCBpbiBhIGNvb2tpZSBhbmQgYXV0b21hdGljYWxseSBsb2FkZWQgZnJvbSB0aGVyZS4gKFNlZSBbbW9yZSBiYWNrZ3JvdW5kIG9uIGFjY2VzcyB0b2tlbnNdKC4uLy4uLy4uL3Byb2plY3RfYWNjZXNzLykpLlxuICAgICAgICAgKiBAc2VlIFtBdXRoZW50aWNhdGlvbiBBUEkgU2VydmljZV0oLi4vYXV0aC1hcGktc2VydmljZS8pIGZvciBnZXR0aW5nIHRva2Vucy5cbiAgICAgICAgICogQHR5cGUge1N0cmluZ31cbiAgICAgICAgICovXG4gICAgICAgIHRva2VuOiB1bmRlZmluZWQsXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIFRoZSBhY2NvdW50IGlkLiBJbiB0aGUgRXBpY2VudGVyIFVJLCB0aGlzIGlzIHRoZSAqKlRlYW0gSUQqKiAoZm9yIHRlYW0gcHJvamVjdHMpIG9yICoqVXNlciBJRCoqIChmb3IgcGVyc29uYWwgcHJvamVjdHMpLiBEZWZhdWx0cyB0byBlbXB0eSBzdHJpbmcuIElmIGxlZnQgdW5kZWZpbmVkLCB0YWtlbiBmcm9tIHRoZSBVUkwuXG4gICAgICAgICAqIEB0eXBlIHtTdHJpbmd9XG4gICAgICAgICAqL1xuICAgICAgICBhY2NvdW50OiB1bmRlZmluZWQsXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIFRoZSBwcm9qZWN0IGlkLiBEZWZhdWx0cyB0byBlbXB0eSBzdHJpbmcuIElmIGxlZnQgdW5kZWZpbmVkLCB0YWtlbiBmcm9tIHRoZSBVUkwuXG4gICAgICAgICAqIEB0eXBlIHtTdHJpbmd9XG4gICAgICAgICAqL1xuICAgICAgICBwcm9qZWN0OiB1bmRlZmluZWQsXG5cbiAgICB9O1xuXG4gICAgdmFyIHNlc3Npb25NYW5hZ2VyID0gbmV3IFNlc3Npb25NYW5hZ2VyKCk7XG4gICAgdmFyIHNlcnZpY2VPcHRpb25zID0gc2Vzc2lvbk1hbmFnZXIuZ2V0TWVyZ2VkT3B0aW9ucyhkZWZhdWx0cywgY29uZmlnKTtcblxuICAgIHZhciB1cmxDb25maWcgPSBuZXcgQ29uZmlnU2VydmljZShzZXJ2aWNlT3B0aW9ucykuZ2V0KCdzZXJ2ZXInKTtcbiAgICBpZiAoc2VydmljZU9wdGlvbnMuYWNjb3VudCkge1xuICAgICAgICB1cmxDb25maWcuYWNjb3VudFBhdGggPSBzZXJ2aWNlT3B0aW9ucy5hY2NvdW50O1xuICAgIH1cbiAgICBpZiAoc2VydmljZU9wdGlvbnMucHJvamVjdCkge1xuICAgICAgICB1cmxDb25maWcucHJvamVjdFBhdGggPSBzZXJ2aWNlT3B0aW9ucy5wcm9qZWN0O1xuICAgIH1cblxuICAgIHZhciB0cmFuc3BvcnRPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sIHNlcnZpY2VPcHRpb25zLnRyYW5zcG9ydCwge1xuICAgICAgICB1cmw6IHVybENvbmZpZy5nZXRBUElQYXRoKGFwaUVuZHBvaW50KVxuICAgIH0pO1xuICAgIGlmIChzZXJ2aWNlT3B0aW9ucy50b2tlbikge1xuICAgICAgICB0cmFuc3BvcnRPcHRpb25zLmhlYWRlcnMgPSB7XG4gICAgICAgICAgICBBdXRob3JpemF0aW9uOiAnQmVhcmVyICcgKyBzZXJ2aWNlT3B0aW9ucy50b2tlblxuICAgICAgICB9O1xuICAgIH1cbiAgICB2YXIgaHR0cCA9IG5ldyBUcmFuc3BvcnRGYWN0b3J5KHRyYW5zcG9ydE9wdGlvbnMpO1xuXG4gICAgdmFyIHB1YmxpY0FQSSA9IHtcbiAgICAgICAgLyoqXG4gICAgICAgICAqIEdldCB0aGUgYXZhaWxhYmxlIHZhcmlhYmxlcyBhbmQgb3BlcmF0aW9ucyBmb3IgYSBnaXZlbiBtb2RlbCBmaWxlLlxuICAgICAgICAgKlxuICAgICAgICAgKiBOb3RlOiBUaGlzIGRvZXMgbm90IHdvcmsgZm9yIGFueSBtb2RlbCB3aGljaCByZXF1aXJlcyBhZGRpdGlvbmFsIHBhcmFtZXRlcnMsIHN1Y2ggYXMgYGZpbGVzYC5cbiAgICAgICAgICpcbiAgICAgICAgICogKipFeGFtcGxlKipcbiAgICAgICAgICpcbiAgICAgICAgICogICAgICBpbnRyby5ieU1vZGVsKCdhYmMudm1mJylcbiAgICAgICAgICogICAgICAgICAgLnRoZW4oZnVuY3Rpb24oZGF0YSkge1xuICAgICAgICAgKiAgICAgICAgICAgICAgLy8gZGF0YSBjb250YWlucyBhbiBvYmplY3Qgd2l0aCBhdmFpbGFibGUgZnVuY3Rpb25zICh1c2VkIHdpdGggb3BlcmF0aW9ucyBBUEkpIGFuZCBhdmFpbGFibGUgdmFyaWFibGVzICh1c2VkIHdpdGggdmFyaWFibGVzIEFQSSlcbiAgICAgICAgICogICAgICAgICAgICAgIGNvbnNvbGUubG9nKGRhdGEuZnVuY3Rpb25zKTtcbiAgICAgICAgICogICAgICAgICAgICAgIGNvbnNvbGUubG9nKGRhdGEudmFyaWFibGVzKTtcbiAgICAgICAgICogICAgICAgICAgfSk7XG4gICAgICAgICAqXG4gICAgICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICAgICAqIEBwYXJhbSAge1N0cmluZ30gbW9kZWxGaWxlIE5hbWUgb2YgdGhlIG1vZGVsIGZpbGUgdG8gaW50cm9zcGVjdC5cbiAgICAgICAgICogQHBhcmFtICB7T2JqZWN0fSBvcHRpb25zIChPcHRpb25hbCkgT3ZlcnJpZGVzIGZvciBjb25maWd1cmF0aW9uIG9wdGlvbnMuXG4gICAgICAgICAqIEByZXR1cm4ge1Byb21pc2V9IFxuICAgICAgICAgKi9cbiAgICAgICAgYnlNb2RlbDogZnVuY3Rpb24gKG1vZGVsRmlsZSwgb3B0aW9ucykge1xuICAgICAgICAgICAgdmFyIG9wdHMgPSAkLmV4dGVuZCh0cnVlLCB7fSwgc2VydmljZU9wdGlvbnMsIG9wdGlvbnMpO1xuICAgICAgICAgICAgaWYgKCFvcHRzLmFjY291bnQgfHwgIW9wdHMucHJvamVjdCkge1xuICAgICAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcignQWNjb3VudCBhbmQgcHJvamVjdCBhcmUgcmVxdWlyZWQgd2hlbiB1c2luZyBpbnRyb3NwZWN0I2J5TW9kZWwnKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGlmICghbW9kZWxGaWxlKSB7XG4gICAgICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdtb2RlbEZpbGUgaXMgcmVxdWlyZWQgd2hlbiB1c2luZyBpbnRyb3NwZWN0I2J5TW9kZWwnKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHZhciB1cmwgPSB7IHVybDogdXJsQ29uZmlnLmdldEFQSVBhdGgoYXBpRW5kcG9pbnQpICsgW29wdHMuYWNjb3VudCwgb3B0cy5wcm9qZWN0LCBtb2RlbEZpbGVdLmpvaW4oJy8nKSB9O1xuICAgICAgICAgICAgdmFyIGh0dHBPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sIHNlcnZpY2VPcHRpb25zLCBvcHRpb25zLCB1cmwpO1xuICAgICAgICAgICAgcmV0dXJuIGh0dHAuZ2V0KCcnLCBodHRwT3B0aW9ucyk7XG4gICAgICAgIH0sXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIEdldCB0aGUgYXZhaWxhYmxlIHZhcmlhYmxlcyBhbmQgb3BlcmF0aW9ucyBmb3IgYSBnaXZlbiBtb2RlbCBmaWxlLlxuICAgICAgICAgKlxuICAgICAgICAgKiBOb3RlOiBUaGlzIGRvZXMgbm90IHdvcmsgZm9yIGFueSBtb2RlbCB3aGljaCByZXF1aXJlcyBhZGRpdGlvbmFsIHBhcmFtZXRlcnMgc3VjaCBhcyBgZmlsZXNgLlxuICAgICAgICAgKlxuICAgICAgICAgKiAqKkV4YW1wbGUqKlxuICAgICAgICAgKlxuICAgICAgICAgKiAgICAgIGludHJvLmJ5UnVuSUQoJzJiNGQ4ZjcxLTVjMzQtNDM1YS04YzE2LTlkZTY3NGFiNzJlNicpXG4gICAgICAgICAqICAgICAgICAgIC50aGVuKGZ1bmN0aW9uKGRhdGEpIHtcbiAgICAgICAgICogICAgICAgICAgICAgIC8vIGRhdGEgY29udGFpbnMgYW4gb2JqZWN0IHdpdGggYXZhaWxhYmxlIGZ1bmN0aW9ucyAodXNlZCB3aXRoIG9wZXJhdGlvbnMgQVBJKSBhbmQgYXZhaWxhYmxlIHZhcmlhYmxlcyAodXNlZCB3aXRoIHZhcmlhYmxlcyBBUEkpXG4gICAgICAgICAqICAgICAgICAgICAgICBjb25zb2xlLmxvZyhkYXRhLmZ1bmN0aW9ucyk7XG4gICAgICAgICAqICAgICAgICAgICAgICBjb25zb2xlLmxvZyhkYXRhLnZhcmlhYmxlcyk7XG4gICAgICAgICAqICAgICAgICAgIH0pO1xuICAgICAgICAgKlxuICAgICAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAgKiBAcGFyYW0gIHtTdHJpbmd9IHJ1bklEIElkIG9mIHRoZSBydW4gdG8gaW50cm9zcGVjdC5cbiAgICAgICAgICogQHBhcmFtICB7T2JqZWN0fSBvcHRpb25zIChPcHRpb25hbCkgT3ZlcnJpZGVzIGZvciBjb25maWd1cmF0aW9uIG9wdGlvbnMuXG4gICAgICAgICAqIEByZXR1cm4ge1Byb21pc2V9IFxuICAgICAgICAgKi9cbiAgICAgICAgYnlSdW5JRDogZnVuY3Rpb24gKHJ1bklELCBvcHRpb25zKSB7XG4gICAgICAgICAgICBpZiAoIXJ1bklEKSB7XG4gICAgICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdydW5JRCBpcyByZXF1aXJlZCB3aGVuIHVzaW5nIGludHJvc3BlY3QjYnlNb2RlbCcpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgdmFyIHVybCA9IHsgdXJsOiB1cmxDb25maWcuZ2V0QVBJUGF0aChhcGlFbmRwb2ludCkgKyBydW5JRCB9O1xuICAgICAgICAgICAgdmFyIGh0dHBPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sIHNlcnZpY2VPcHRpb25zLCBvcHRpb25zLCB1cmwpO1xuICAgICAgICAgICAgcmV0dXJuIGh0dHAuZ2V0KCcnLCBodHRwT3B0aW9ucyk7XG4gICAgICAgIH1cbiAgICB9O1xuICAgICQuZXh0ZW5kKHRoaXMsIHB1YmxpY0FQSSk7XG59O1xuIiwiLyoqXG4gKlxuICogIyMgTWVtYmVyIEFQSSBBZGFwdGVyXG4gKlxuICogVGhlIE1lbWJlciBBUEkgQWRhcHRlciBwcm92aWRlcyBtZXRob2RzIHRvIGxvb2sgdXAgaW5mb3JtYXRpb24gYWJvdXQgZW5kIHVzZXJzIGZvciB5b3VyIHByb2plY3QgYW5kIGhvdyB0aGV5IGFyZSBkaXZpZGVkIGFjcm9zcyBncm91cHMuIEl0IGlzIGJhc2VkIG9uIHF1ZXJ5IGNhcGFiaWxpdGllcyBvZiB0aGUgdW5kZXJseWluZyBSRVNUZnVsIFtNZW1iZXIgQVBJXSguLi8uLi8uLi9yZXN0X2FwaXMvdXNlcl9tYW5hZ2VtZW50L21lbWJlci8pLlxuICpcbiAqIFRoaXMgaXMgb25seSBuZWVkZWQgZm9yIEF1dGhlbnRpY2F0ZWQgcHJvamVjdHMsIHRoYXQgaXMsIHRlYW0gcHJvamVjdHMgd2l0aCBbZW5kIHVzZXJzIGFuZCBncm91cHNdKC4uLy4uLy4uL2dyb3Vwc19hbmRfZW5kX3VzZXJzLykuIEZvciBleGFtcGxlLCBpZiBzb21lIG9mIHlvdXIgZW5kIHVzZXJzIGFyZSBmYWNpbGl0YXRvcnMsIG9yIGlmIHlvdXIgZW5kIHVzZXJzIHNob3VsZCBiZSB0cmVhdGVkIGRpZmZlcmVudGx5IGJhc2VkIG9uIHdoaWNoIGdyb3VwIHRoZXkgYXJlIGluLCB1c2UgdGhlIE1lbWJlciBBUEkgdG8gZmluZCB0aGF0IGluZm9ybWF0aW9uLlxuICpcbiAqICAgICAgdmFyIG1hID0gbmV3IEYuc2VydmljZS5NZW1iZXIoeyB0b2tlbjogJ3VzZXItb3ItcHJvamVjdC1hY2Nlc3MtdG9rZW4nIH0pO1xuICogICAgICBtYS5nZXRHcm91cHNGb3JVc2VyKHsgdXNlcklkOiAnYjZiMzEzYTMtYWI4NC00NzljLWJhZWEtMjA2ZjZiZmYzMzcnIH0pO1xuICogICAgICBtYS5nZXRHcm91cERldGFpbHMoeyBncm91cElkOiAnMDBiNTMzMDgtOTgzMy00N2YyLWIyMWUtMTI3OGMwN2Q1M2I4JyB9KTtcbiAqL1xuXG4ndXNlIHN0cmljdCc7XG5cbnZhciBDb25maWdTZXJ2aWNlID0gcmVxdWlyZSgnLi9jb25maWd1cmF0aW9uLXNlcnZpY2UnKTtcbnZhciBUcmFuc3BvcnRGYWN0b3J5ID0gcmVxdWlyZSgnLi4vdHJhbnNwb3J0L2h0dHAtdHJhbnNwb3J0LWZhY3RvcnknKTtcbnZhciBTZXNzaW9uTWFuYWdlciA9IHJlcXVpcmUoJy4uL3N0b3JlL3Nlc3Npb24tbWFuYWdlcicpO1xudmFyIF9waWNrID0gcmVxdWlyZSgnLi4vdXRpbC9vYmplY3QtdXRpbCcpLl9waWNrO1xudmFyIGFwaUVuZHBvaW50ID0gJ21lbWJlci9sb2NhbCc7XG5cbm1vZHVsZS5leHBvcnRzID0gZnVuY3Rpb24gKGNvbmZpZykge1xuICAgIHZhciBkZWZhdWx0cyA9IHtcbiAgICAgICAgLyoqXG4gICAgICAgICAqIEVwaWNlbnRlciB1c2VyIGlkLiBEZWZhdWx0cyB0byBhIGJsYW5rIHN0cmluZy5cbiAgICAgICAgICogQHR5cGUge3N0cmluZ31cbiAgICAgICAgICovXG4gICAgICAgIHVzZXJJZDogdW5kZWZpbmVkLFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBFcGljZW50ZXIgZ3JvdXAgaWQuIERlZmF1bHRzIHRvIGEgYmxhbmsgc3RyaW5nLiBOb3RlIHRoYXQgdGhpcyBpcyB0aGUgZ3JvdXAgKmlkKiwgbm90IHRoZSBncm91cCAqbmFtZSouXG4gICAgICAgICAqIEB0eXBlIHtzdHJpbmd9XG4gICAgICAgICAqL1xuICAgICAgICBncm91cElkOiB1bmRlZmluZWQsXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIE9wdGlvbnMgdG8gcGFzcyBvbiB0byB0aGUgdW5kZXJseWluZyB0cmFuc3BvcnQgbGF5ZXIuIEFsbCBqcXVlcnkuYWpheCBvcHRpb25zIGF0IGh0dHA6Ly9hcGkuanF1ZXJ5LmNvbS9qUXVlcnkuYWpheC8gYXJlIGF2YWlsYWJsZS4gRGVmYXVsdHMgdG8gZW1wdHkgb2JqZWN0LlxuICAgICAgICAgKiBAdHlwZSB7b2JqZWN0fVxuICAgICAgICAgKi9cbiAgICAgICAgdHJhbnNwb3J0OiB7fVxuICAgIH07XG4gICAgdGhpcy5zZXNzaW9uTWFuYWdlciA9IG5ldyBTZXNzaW9uTWFuYWdlcigpO1xuICAgIHZhciBzZXJ2aWNlT3B0aW9ucyA9IHRoaXMuc2Vzc2lvbk1hbmFnZXIuZ2V0TWVyZ2VkT3B0aW9ucyhkZWZhdWx0cywgY29uZmlnKTtcbiAgICB2YXIgdXJsQ29uZmlnID0gbmV3IENvbmZpZ1NlcnZpY2Uoc2VydmljZU9wdGlvbnMpLmdldCgnc2VydmVyJyk7XG5cbiAgICB2YXIgdHJhbnNwb3J0T3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LCBzZXJ2aWNlT3B0aW9ucy50cmFuc3BvcnQsIHtcbiAgICAgICAgdXJsOiB1cmxDb25maWcuZ2V0QVBJUGF0aChhcGlFbmRwb2ludClcbiAgICB9KTtcblxuICAgIGlmIChzZXJ2aWNlT3B0aW9ucy50b2tlbikge1xuICAgICAgICB0cmFuc3BvcnRPcHRpb25zLmhlYWRlcnMgPSB7XG4gICAgICAgICAgICBBdXRob3JpemF0aW9uOiAnQmVhcmVyICcgKyBzZXJ2aWNlT3B0aW9ucy50b2tlblxuICAgICAgICB9O1xuICAgIH1cbiAgICB2YXIgaHR0cCA9IG5ldyBUcmFuc3BvcnRGYWN0b3J5KHRyYW5zcG9ydE9wdGlvbnMsIHNlcnZpY2VPcHRpb25zKTtcblxuICAgIHZhciBnZXRGaW5hbFBhcmFtcyA9IGZ1bmN0aW9uIChwYXJhbXMpIHtcbiAgICAgICAgaWYgKHR5cGVvZiBwYXJhbXMgPT09ICdvYmplY3QnKSB7XG4gICAgICAgICAgICByZXR1cm4gJC5leHRlbmQodHJ1ZSwgc2VydmljZU9wdGlvbnMsIHBhcmFtcyk7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIHNlcnZpY2VPcHRpb25zO1xuICAgIH07XG5cbiAgICB2YXIgcGF0Y2hVc2VyQWN0aXZlRmllbGQgPSBmdW5jdGlvbiAocGFyYW1zLCBhY3RpdmUsIG9wdGlvbnMpIHtcbiAgICAgICAgdmFyIGh0dHBPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwgc2VydmljZU9wdGlvbnMsIG9wdGlvbnMsIHtcbiAgICAgICAgICAgIHVybDogdXJsQ29uZmlnLmdldEFQSVBhdGgoYXBpRW5kcG9pbnQpICsgcGFyYW1zLmdyb3VwSWQgKyAnLycgKyBwYXJhbXMudXNlcklkXG4gICAgICAgIH0pO1xuXG4gICAgICAgIHJldHVybiBodHRwLnBhdGNoKHsgYWN0aXZlOiBhY3RpdmUgfSwgaHR0cE9wdGlvbnMpO1xuICAgIH07XG5cbiAgICB2YXIgcHVibGljQVBJID0ge1xuXG4gICAgICAgIC8qKlxuICAgICAgICAqIFJldHJpZXZlIGRldGFpbHMgYWJvdXQgYWxsIG9mIHRoZSBncm91cCBtZW1iZXJzaGlwcyBmb3Igb25lIGVuZCB1c2VyLiBUaGUgbWVtYmVyc2hpcCBkZXRhaWxzIGFyZSByZXR1cm5lZCBpbiBhbiBhcnJheSwgd2l0aCBvbmUgZWxlbWVudCAoZ3JvdXAgcmVjb3JkKSBmb3IgZWFjaCBncm91cCB0byB3aGljaCB0aGUgZW5kIHVzZXIgYmVsb25ncy5cbiAgICAgICAgKlxuICAgICAgICAqIEluIHRoZSBtZW1iZXJzaGlwIGFycmF5LCBlYWNoIGdyb3VwIHJlY29yZCBpbmNsdWRlcyB0aGUgZ3JvdXAgaWQsIHByb2plY3QgaWQsIGFjY291bnQgKHRlYW0pIGlkLCBhbmQgYW4gYXJyYXkgb2YgbWVtYmVycy4gSG93ZXZlciwgb25seSB0aGUgdXNlciB3aG9zZSB1c2VySWQgaXMgaW5jbHVkZWQgaW4gdGhlIGNhbGwgaXMgbGlzdGVkIGluIHRoZSBtZW1iZXJzIGFycmF5IChyZWdhcmRsZXNzIG9mIHdoZXRoZXIgdGhlcmUgYXJlIG90aGVyIG1lbWJlcnMgaW4gdGhpcyBncm91cCkuXG4gICAgICAgICpcbiAgICAgICAgKiAqKkV4YW1wbGUqKlxuICAgICAgICAqXG4gICAgICAgICogICAgICAgdmFyIG1hID0gbmV3IEYuc2VydmljZS5NZW1iZXIoeyB0b2tlbjogJ3VzZXItb3ItcHJvamVjdC1hY2Nlc3MtdG9rZW4nIH0pO1xuICAgICAgICAqICAgICAgIG1hLmdldEdyb3Vwc0ZvclVzZXIoJzQyODM2ZDRiLTViNjEtNGZlNC04MGViLTMxMzZlOTU2ZWU1YycpXG4gICAgICAgICogICAgICAgICAgIC50aGVuKGZ1bmN0aW9uKG1lbWJlcnNoaXBzKXtcbiAgICAgICAgKiAgICAgICAgICAgICAgIGZvciAodmFyIGk9MDsgaTxtZW1iZXJzaGlwcy5sZW5ndGg7IGkrKykge1xuICAgICAgICAqICAgICAgICAgICAgICAgICAgIGNvbnNvbGUubG9nKG1lbWJlcnNoaXBzW2ldLmdyb3VwSWQpO1xuICAgICAgICAqICAgICAgICAgICAgICAgfVxuICAgICAgICAqICAgICAgICAgICB9KTtcbiAgICAgICAgKlxuICAgICAgICAqICAgICAgIG1hLmdldEdyb3Vwc0ZvclVzZXIoeyB1c2VySWQ6ICc0MjgzNmQ0Yi01YjYxLTRmZTQtODBlYi0zMTM2ZTk1NmVlNWMnIH0pO1xuICAgICAgICAqXG4gICAgICAgICogKipQYXJhbWV0ZXJzKipcbiAgICAgICAgKiBAcGFyYW0ge3N0cmluZ3xvYmplY3R9IHBhcmFtcyBUaGUgdXNlciBpZCBmb3IgdGhlIGVuZCB1c2VyLiBBbHRlcm5hdGl2ZWx5LCBhbiBvYmplY3Qgd2l0aCBmaWVsZCBgdXNlcklkYCBhbmQgdmFsdWUgdGhlIHVzZXIgaWQuXG4gICAgICAgICogQHBhcmFtIHtvYmplY3R9IG9wdGlvbnMgKE9wdGlvbmFsKSBPdmVycmlkZXMgZm9yIGNvbmZpZ3VyYXRpb24gb3B0aW9ucy5cbiAgICAgICAgKi9cblxuICAgICAgICBnZXRHcm91cHNGb3JVc2VyOiBmdW5jdGlvbiAocGFyYW1zLCBvcHRpb25zKSB7XG4gICAgICAgICAgICBvcHRpb25zID0gb3B0aW9ucyB8fCB7fTtcbiAgICAgICAgICAgIHZhciBodHRwT3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHNlcnZpY2VPcHRpb25zLCBvcHRpb25zKTtcbiAgICAgICAgICAgIHZhciBpc1N0cmluZyA9IHR5cGVvZiBwYXJhbXMgPT09ICdzdHJpbmcnO1xuICAgICAgICAgICAgdmFyIG9ialBhcmFtcyA9IGdldEZpbmFsUGFyYW1zKHBhcmFtcyk7XG4gICAgICAgICAgICBpZiAoIWlzU3RyaW5nICYmICFvYmpQYXJhbXMudXNlcklkKSB7XG4gICAgICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdObyB1c2VySWQgc3BlY2lmaWVkLicpO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICB2YXIgZ2V0UGFybXMgPSBpc1N0cmluZyA/IHsgdXNlcklkOiBwYXJhbXMgfSA6IF9waWNrKG9ialBhcmFtcywgJ3VzZXJJZCcpO1xuICAgICAgICAgICAgcmV0dXJuIGh0dHAuZ2V0KGdldFBhcm1zLCBodHRwT3B0aW9ucyk7XG4gICAgICAgIH0sXG5cbiAgICAgICAgLyoqXG4gICAgICAgICogUmV0cmlldmUgZGV0YWlscyBhYm91dCBvbmUgZ3JvdXAsIGluY2x1ZGluZyBhbiBhcnJheSBvZiBhbGwgaXRzIG1lbWJlcnMuXG4gICAgICAgICpcbiAgICAgICAgKiAqKkV4YW1wbGUqKlxuICAgICAgICAqXG4gICAgICAgICogICAgICAgdmFyIG1hID0gbmV3IEYuc2VydmljZS5NZW1iZXIoeyB0b2tlbjogJ3VzZXItb3ItcHJvamVjdC1hY2Nlc3MtdG9rZW4nIH0pO1xuICAgICAgICAqICAgICAgIG1hLmdldEdyb3VwRGV0YWlscygnODAyNTdhMjUtYWExMC00OTU5LTk2OGItZmQwNTM5MDFmNzJmJylcbiAgICAgICAgKiAgICAgICAgICAgLnRoZW4oZnVuY3Rpb24oZ3JvdXApe1xuICAgICAgICAqICAgICAgICAgICAgICAgZm9yICh2YXIgaT0wOyBpPGdyb3VwLm1lbWJlcnMubGVuZ3RoOyBpKyspIHtcbiAgICAgICAgKiAgICAgICAgICAgICAgICAgICBjb25zb2xlLmxvZyhncm91cC5tZW1iZXJzW2ldLnVzZXJOYW1lKTtcbiAgICAgICAgKiAgICAgICAgICAgICAgIH1cbiAgICAgICAgKiAgICAgICAgICAgfSk7XG4gICAgICAgICpcbiAgICAgICAgKiAgICAgICBtYS5nZXRHcm91cERldGFpbHMoeyBncm91cElkOiAnODAyNTdhMjUtYWExMC00OTU5LTk2OGItZmQwNTM5MDFmNzJmJyB9KTtcbiAgICAgICAgKlxuICAgICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICAgICogQHBhcmFtIHtzdHJpbmd8b2JqZWN0fSBwYXJhbXMgVGhlIGdyb3VwIGlkLiBBbHRlcm5hdGl2ZWx5LCBhbiBvYmplY3Qgd2l0aCBmaWVsZCBgZ3JvdXBJZGAgYW5kIHZhbHVlIHRoZSBncm91cCBpZC5cbiAgICAgICAgKiBAcGFyYW0ge29iamVjdH0gb3B0aW9ucyAoT3B0aW9uYWwpIE92ZXJyaWRlcyBmb3IgY29uZmlndXJhdGlvbiBvcHRpb25zLlxuICAgICAgICAqIEByZXR1cm4ge1Byb21pc2V9XG4gICAgICAgICovXG4gICAgICAgIGdldEdyb3VwRGV0YWlsczogZnVuY3Rpb24gKHBhcmFtcywgb3B0aW9ucykge1xuICAgICAgICAgICAgb3B0aW9ucyA9IG9wdGlvbnMgfHwge307XG4gICAgICAgICAgICB2YXIgaXNTdHJpbmcgPSB0eXBlb2YgcGFyYW1zID09PSAnc3RyaW5nJztcbiAgICAgICAgICAgIHZhciBvYmpQYXJhbXMgPSBnZXRGaW5hbFBhcmFtcyhwYXJhbXMpO1xuICAgICAgICAgICAgaWYgKCFpc1N0cmluZyAmJiAhb2JqUGFyYW1zLmdyb3VwSWQpIHtcbiAgICAgICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ05vIGdyb3VwSWQgc3BlY2lmaWVkLicpO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICB2YXIgZ3JvdXBJZCA9IGlzU3RyaW5nID8gcGFyYW1zIDogb2JqUGFyYW1zLmdyb3VwSWQ7XG4gICAgICAgICAgICB2YXIgaHR0cE9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCBzZXJ2aWNlT3B0aW9ucyxcbiAgICAgICAgICAgICAgICBvcHRpb25zLFxuICAgICAgICAgICAgICAgIHsgdXJsOiB1cmxDb25maWcuZ2V0QVBJUGF0aChhcGlFbmRwb2ludCkgKyBncm91cElkIH1cbiAgICAgICAgICAgICk7XG5cbiAgICAgICAgICAgIHJldHVybiBodHRwLmdldCh7fSwgaHR0cE9wdGlvbnMpO1xuICAgICAgICB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAqIFNldCBhIHBhcnRpY3VsYXIgZW5kIHVzZXIgYXMgYGFjdGl2ZWAuIEFjdGl2ZSBlbmQgdXNlcnMgY2FuIGJlIGFzc2lnbmVkIHRvIFt3b3JsZHNdKC4uL3dvcmxkLW1hbmFnZXIvKSBpbiBtdWx0aXBsYXllciBnYW1lcyBkdXJpbmcgYXV0b21hdGljIGFzc2lnbm1lbnQuXG4gICAgICAgICpcbiAgICAgICAgKiAqKkV4YW1wbGUqKlxuICAgICAgICAqXG4gICAgICAgICogICAgICAgdmFyIG1hID0gbmV3IEYuc2VydmljZS5NZW1iZXIoeyB0b2tlbjogJ3VzZXItb3ItcHJvamVjdC1hY2Nlc3MtdG9rZW4nIH0pO1xuICAgICAgICAqICAgICAgIG1hLm1ha2VVc2VyQWN0aXZlKHsgdXNlcklkOiAnNDI4MzZkNGItNWI2MS00ZmU0LTgwZWItMzEzNmU5NTZlZTVjJyxcbiAgICAgICAgKiAgICAgICAgICAgICAgICAgICAgICAgICAgIGdyb3VwSWQ6ICc4MDI1N2EyNS1hYTEwLTQ5NTktOTY4Yi1mZDA1MzkwMWY3MmYnIH0pO1xuICAgICAgICAqXG4gICAgICAgICogKipQYXJhbWV0ZXJzKipcbiAgICAgICAgKiBAcGFyYW0ge29iamVjdH0gcGFyYW1zIFRoZSBlbmQgdXNlciBhbmQgZ3JvdXAgaW5mb3JtYXRpb24uXG4gICAgICAgICogQHBhcmFtIHtzdHJpbmd9IHBhcmFtcy51c2VySWQgVGhlIGlkIG9mIHRoZSBlbmQgdXNlciB0byBtYWtlIGFjdGl2ZS5cbiAgICAgICAgKiBAcGFyYW0ge3N0cmluZ30gcGFyYW1zLmdyb3VwSWQgVGhlIGlkIG9mIHRoZSBncm91cCB0byB3aGljaCB0aGlzIGVuZCB1c2VyIGJlbG9uZ3MsIGFuZCBpbiB3aGljaCB0aGUgZW5kIHVzZXIgc2hvdWxkIGJlY29tZSBhY3RpdmUuXG4gICAgICAgICogQHBhcmFtIHtvYmplY3R9IG9wdGlvbnMgKE9wdGlvbmFsKSBPdmVycmlkZXMgZm9yIGNvbmZpZ3VyYXRpb24gb3B0aW9ucy5cbiAgICAgICAgKiBAcmV0dXJuIHtQcm9taXNlfVxuICAgICAgICAqL1xuICAgICAgICBtYWtlVXNlckFjdGl2ZTogZnVuY3Rpb24gKHBhcmFtcywgb3B0aW9ucykge1xuICAgICAgICAgICAgcmV0dXJuIHBhdGNoVXNlckFjdGl2ZUZpZWxkKHBhcmFtcywgdHJ1ZSwgb3B0aW9ucyk7XG4gICAgICAgIH0sXG5cbiAgICAgICAgLyoqXG4gICAgICAgICogU2V0IGEgcGFydGljdWxhciBlbmQgdXNlciBhcyBgaW5hY3RpdmVgLiBJbmFjdGl2ZSBlbmQgdXNlcnMgYXJlIG5vdCBhc3NpZ25lZCB0byBbd29ybGRzXSguLi93b3JsZC1tYW5hZ2VyLykgaW4gbXVsdGlwbGF5ZXIgZ2FtZXMgZHVyaW5nIGF1dG9tYXRpYyBhc3NpZ25tZW50LlxuICAgICAgICAqXG4gICAgICAgICogKipFeGFtcGxlKipcbiAgICAgICAgKlxuICAgICAgICAqICAgICAgIHZhciBtYSA9IG5ldyBGLnNlcnZpY2UuTWVtYmVyKHsgdG9rZW46ICd1c2VyLW9yLXByb2plY3QtYWNjZXNzLXRva2VuJyB9KTtcbiAgICAgICAgKiAgICAgICBtYS5tYWtlVXNlckluYWN0aXZlKHsgdXNlcklkOiAnNDI4MzZkNGItNWI2MS00ZmU0LTgwZWItMzEzNmU5NTZlZTVjJyxcbiAgICAgICAgKiAgICAgICAgICAgICAgICAgICAgICAgICAgIGdyb3VwSWQ6ICc4MDI1N2EyNS1hYTEwLTQ5NTktOTY4Yi1mZDA1MzkwMWY3MmYnIH0pO1xuICAgICAgICAqXG4gICAgICAgICogKipQYXJhbWV0ZXJzKipcbiAgICAgICAgKiBAcGFyYW0ge29iamVjdH0gcGFyYW1zIFRoZSBlbmQgdXNlciBhbmQgZ3JvdXAgaW5mb3JtYXRpb24uXG4gICAgICAgICogQHBhcmFtIHtzdHJpbmd9IHBhcmFtcy51c2VySWQgVGhlIGlkIG9mIHRoZSBlbmQgdXNlciB0byBtYWtlIGluYWN0aXZlLlxuICAgICAgICAqIEBwYXJhbSB7c3RyaW5nfSBwYXJhbXMuZ3JvdXBJZCBUaGUgaWQgb2YgdGhlIGdyb3VwIHRvIHdoaWNoIHRoaXMgZW5kIHVzZXIgYmVsb25ncywgYW5kIGluIHdoaWNoIHRoZSBlbmQgdXNlciBzaG91bGQgYmVjb21lIGluYWN0aXZlLlxuICAgICAgICAqIEBwYXJhbSB7b2JqZWN0fSBvcHRpb25zIChPcHRpb25hbCkgT3ZlcnJpZGVzIGZvciBjb25maWd1cmF0aW9uIG9wdGlvbnMuXG4gICAgICAgICogQHJldHVybiB7UHJvbWlzZX1cbiAgICAgICAgKi9cbiAgICAgICAgbWFrZVVzZXJJbmFjdGl2ZTogZnVuY3Rpb24gKHBhcmFtcywgb3B0aW9ucykge1xuICAgICAgICAgICAgcmV0dXJuIHBhdGNoVXNlckFjdGl2ZUZpZWxkKHBhcmFtcywgZmFsc2UsIG9wdGlvbnMpO1xuICAgICAgICB9XG4gICAgfTtcblxuICAgICQuZXh0ZW5kKHRoaXMsIHB1YmxpY0FQSSk7XG59O1xuIiwiLyoqXG4gKlxuICogIyMgUHJlc2VuY2UgQVBJIFNlcnZpY2VcbiAqXG4gKiBUaGUgUHJlc2VuY2UgQVBJIFNlcnZpY2UgcHJvdmlkZXMgbWV0aG9kcyB0byBnZXQgYW5kIHNldCB0aGUgcHJlc2VuY2Ugb2YgYW4gZW5kIHVzZXIgaW4gYSBwcm9qZWN0LCB0aGF0IGlzLCB0byBpbmRpY2F0ZSB3aGV0aGVyIHRoZSBlbmQgdXNlciBpcyBvbmxpbmUuIFRoaXMgaGFwcGVucyBhdXRvbWF0aWNhbGx5OiBpbiBwcm9qZWN0cyB0aGF0IHVzZSBbY2hhbm5lbHNdKC4uL2VwaWNlbnRlci1jaGFubmVsLW1hbmFnZXIvKSwgdGhlIGVuZCB1c2VyJ3MgcHJlc2VuY2UgaXMgcHVibGlzaGVkIGF1dG9tYXRpY2FsbHkgb24gYSBcInByZXNlbmNlXCIgY2hhbm5lbCB0aGF0IGlzIHNwZWNpZmljIHRvIGVhY2ggZ3JvdXAuIFlvdSBjYW4gYWxzbyB1c2UgdGhlIFByZXNlbmNlIEFQSSBTZXJ2aWNlIHRvIGRvIHRoaXMgZXhwbGljaXRseTogeW91IGNhbiBtYWtlIGEgY2FsbCB0byBpbmRpY2F0ZSB0aGF0IGEgcGFydGljdWxhciBlbmQgdXNlciBpcyBvbmxpbmUgb3Igb2ZmbGluZS4gXG4gKlxuICogVGhlIFByZXNlbmNlIEFQSSBTZXJ2aWNlIGlzIG9ubHkgbmVlZGVkIGZvciBBdXRoZW50aWNhdGVkIHByb2plY3RzLCB0aGF0IGlzLCB0ZWFtIHByb2plY3RzIHdpdGggW2VuZCB1c2VycyBhbmQgZ3JvdXBzXSguLi8uLi8uLi9ncm91cHNfYW5kX2VuZF91c2Vycy8pLiBJdCBpcyB0eXBpY2FsbHkgdXNlZCBvbmx5IGluIG11bHRpcGxheWVyIHByb2plY3RzLCB0byBmYWNpbGl0YXRlIGVuZCB1c2VycyBjb21tdW5pY2F0aW5nIHdpdGggZWFjaCBvdGhlci4gSXQgaXMgYmFzZWQgb24gdGhlIHF1ZXJ5IGNhcGFiaWxpdGllcyBvZiB0aGUgdW5kZXJseWluZyBSRVNUZnVsIFtQcmVzZW5jZSBBUEldKC4uLy4uLy4uL3Jlc3RfYXBpcy9tdWx0aXBsYXllci9wcmVzZW5jZS8pLlxuICpcbiAqICAgICAgdmFyIHByID0gbmV3IEYuc2VydmljZS5QcmVzZW5jZSgpO1xuICogICAgICBwci5tYXJrT25saW5lKCdleGFtcGxlLXVzZXJJZCcpO1xuICogICAgICBwci5tYXJrT2ZmbGluZSgnZXhhbXBsZS11c2VySWQnKTtcbiAqICAgICAgcHIuZ2V0U3RhdHVzKCk7XG4gKi9cblxudmFyIENvbmZpZ1NlcnZpY2UgPSByZXF1aXJlKCcuL2NvbmZpZ3VyYXRpb24tc2VydmljZScpO1xudmFyIFRyYW5zcG9ydEZhY3RvcnkgPSByZXF1aXJlKCcuLi90cmFuc3BvcnQvaHR0cC10cmFuc3BvcnQtZmFjdG9yeScpO1xudmFyIFNlc3Npb25NYW5hZ2VyID0gcmVxdWlyZSgnLi4vc3RvcmUvc2Vzc2lvbi1tYW5hZ2VyJyk7XG52YXIgYXBpRW5kcG9pbnQgPSAncHJlc2VuY2UnO1xudmFyIENoYW5uZWxNYW5hZ2VyID0gcmVxdWlyZSgnLi4vbWFuYWdlcnMvZXBpY2VudGVyLWNoYW5uZWwtbWFuYWdlcicpO1xuXG5tb2R1bGUuZXhwb3J0cyA9IGZ1bmN0aW9uIChjb25maWcpIHtcbiAgICB2YXIgZGVmYXVsdHMgPSB7XG4gICAgICAgIC8qKlxuICAgICAgICAgKiBUaGUgYWNjb3VudCBpZC4gSW4gdGhlIEVwaWNlbnRlciBVSSwgdGhpcyBpcyB0aGUgKipUZWFtIElEKiogKGZvciB0ZWFtIHByb2plY3RzKSBvciAqKlVzZXIgSUQqKiAoZm9yIHBlcnNvbmFsIHByb2plY3RzKS4gRGVmYXVsdHMgdG8gdW5kZWZpbmVkLiBJZiBsZWZ0IHVuZGVmaW5lZCwgdGFrZW4gZnJvbSB0aGUgVVJMIG9yIHNlc3Npb24gbWFuYWdlci5cbiAgICAgICAgICogQHR5cGUge1N0cmluZ31cbiAgICAgICAgICovXG4gICAgICAgIGFjY291bnQ6IHVuZGVmaW5lZCxcblxuICAgICAgICAvKipcbiAgICAgICAgICogVGhlIHByb2plY3QgaWQuIERlZmF1bHRzIHRvIHVuZGVmaW5lZC4gSWYgbGVmdCB1bmRlZmluZWQsIHRha2VuIGZyb20gdGhlIFVSTCBvciBzZXNzaW9uIG1hbmFnZXIuXG4gICAgICAgICAqIEB0eXBlIHtTdHJpbmd9XG4gICAgICAgICAqL1xuICAgICAgICBwcm9qZWN0OiB1bmRlZmluZWQsXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIEVwaWNlbnRlciBncm91cCBuYW1lLiBEZWZhdWx0cyB0byB1bmRlZmluZWQuIE5vdGUgdGhhdCB0aGlzIGlzIHRoZSBncm91cCAqbmFtZSosIG5vdCB0aGUgZ3JvdXAgKmlkKi4gSWYgbGVmdCBibGFuaywgdGFrZW4gZnJvbSB0aGUgc2Vzc2lvbiBtYW5hZ2VyLlxuICAgICAgICAgKiBAdHlwZSB7c3RyaW5nfVxuICAgICAgICAgKi9cbiAgICAgICAgZ3JvdXBOYW1lOiB1bmRlZmluZWQsXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIE9wdGlvbnMgdG8gcGFzcyBvbiB0byB0aGUgdW5kZXJseWluZyB0cmFuc3BvcnQgbGF5ZXIuIEFsbCBqcXVlcnkuYWpheCBvcHRpb25zIGF0IGh0dHA6Ly9hcGkuanF1ZXJ5LmNvbS9qUXVlcnkuYWpheC8gYXJlIGF2YWlsYWJsZS4gRGVmYXVsdHMgdG8gZW1wdHkgb2JqZWN0LlxuICAgICAgICAgKiBAdHlwZSB7b2JqZWN0fVxuICAgICAgICAgKi9cbiAgICAgICAgdHJhbnNwb3J0OiB7fSxcbiAgICB9O1xuICAgIHRoaXMuc2Vzc2lvbk1hbmFnZXIgPSBuZXcgU2Vzc2lvbk1hbmFnZXIoKTtcbiAgICB2YXIgc2VydmljZU9wdGlvbnMgPSB0aGlzLnNlc3Npb25NYW5hZ2VyLmdldE1lcmdlZE9wdGlvbnMoZGVmYXVsdHMsIGNvbmZpZyk7XG4gICAgdmFyIHVybENvbmZpZyA9IG5ldyBDb25maWdTZXJ2aWNlKHNlcnZpY2VPcHRpb25zKS5nZXQoJ3NlcnZlcicpO1xuICAgIGlmIChzZXJ2aWNlT3B0aW9ucy5hY2NvdW50KSB7XG4gICAgICAgIHVybENvbmZpZy5hY2NvdW50UGF0aCA9IHNlcnZpY2VPcHRpb25zLmFjY291bnQ7XG4gICAgfVxuICAgIGlmIChzZXJ2aWNlT3B0aW9ucy5wcm9qZWN0KSB7XG4gICAgICAgIHVybENvbmZpZy5wcm9qZWN0UGF0aCA9IHNlcnZpY2VPcHRpb25zLnByb2plY3Q7XG4gICAgfVxuXG4gICAgdmFyIHRyYW5zcG9ydE9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSwgc2VydmljZU9wdGlvbnMudHJhbnNwb3J0LCB7XG4gICAgICAgIHVybDogdXJsQ29uZmlnLmdldEFQSVBhdGgoYXBpRW5kcG9pbnQpXG4gICAgfSk7XG5cbiAgICBpZiAoc2VydmljZU9wdGlvbnMudG9rZW4pIHtcbiAgICAgICAgdHJhbnNwb3J0T3B0aW9ucy5oZWFkZXJzID0ge1xuICAgICAgICAgICAgQXV0aG9yaXphdGlvbjogJ0JlYXJlciAnICsgc2VydmljZU9wdGlvbnMudG9rZW5cbiAgICAgICAgfTtcbiAgICB9XG4gICAgdmFyIGh0dHAgPSBuZXcgVHJhbnNwb3J0RmFjdG9yeSh0cmFuc3BvcnRPcHRpb25zLCBzZXJ2aWNlT3B0aW9ucyk7XG5cblxuICAgIHZhciBnZXRGaW5hbFBhcmFtcyA9IGZ1bmN0aW9uIChwYXJhbXMpIHtcbiAgICAgICAgaWYgKHR5cGVvZiBwYXJhbXMgPT09ICdvYmplY3QnKSB7XG4gICAgICAgICAgICByZXR1cm4gJC5leHRlbmQodHJ1ZSwge30sIHNlcnZpY2VPcHRpb25zLCBwYXJhbXMpO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiBzZXJ2aWNlT3B0aW9ucztcbiAgICB9O1xuXG4gICAgdmFyIHB1YmxpY0FQSSA9IHtcbiAgICAgICAgLyoqXG4gICAgICAgICAqIE1hcmtzIGFuIGVuZCB1c2VyIGFzIG9ubGluZS5cbiAgICAgICAgICpcbiAgICAgICAgICpcbiAgICAgICAgICogKipFeGFtcGxlKipcbiAgICAgICAgICpcbiAgICAgICAgICogICAgIHZhciBwciA9IG5ldyBGLnNlcnZpY2UuUHJlc2VuY2UoKTtcbiAgICAgICAgICogICAgIHByLm1hcmtPbmxpbmUoJzAwMDAwMTVhNjhkODA2YmMwOWNkMGE3ZDIwN2Y0NGJhNWY3NCcpXG4gICAgICAgICAqICAgICAgICAgIC50aGVuKGZ1bmN0aW9uKHByZXNlbmNlT2JqKSB7XG4gICAgICAgICAqICAgICAgICAgICAgICAgY29uc29sZS5sb2coJ3VzZXIgJywgcHJlc2VuY2VPYmoudXNlcklkLCBcbiAgICAgICAgICogICAgICAgICAgICAgICAgICAgICcgbm93IG9ubGluZSwgYXMgb2YgJywgcHJlc2VuY2VPYmoubGFzdE1vZGlmaWVkKTtcbiAgICAgICAgICogICAgICAgICAgfSk7XG4gICAgICAgICAqXG4gICAgICAgICAqICoqUmV0dXJuIFZhbHVlKipcbiAgICAgICAgICpcbiAgICAgICAgICogUHJvbWlzZSB3aXRoIHByZXNlbmNlIGluZm9ybWF0aW9uIGZvciB1c2VyIG1hcmtlZCBvbmxpbmUuXG4gICAgICAgICAqXG4gICAgICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICAgICAqXG4gICAgICAgICAqIEBwYXJhbSAge1N0cmluZ30gdXNlcklkIChvcHRpb25hbCkgSWYgbm90IHByb3ZpZGVkLCB0YWtlbiBmcm9tIHNlc3Npb24gY29va2llLlxuICAgICAgICAgKiBAcGFyYW0gIHtPYmplY3R9IG9wdGlvbnMgQWRkaXRpb25hbCBvcHRpb25zIHRvIGNoYW5nZSB0aGUgcHJlc2VuY2Ugc2VydmljZSBkZWZhdWx0cy5cbiAgICAgICAgICogQHJldHVybiB7UHJvbWlzZX0gcHJvbWlzZVxuICAgICAgICAgKi9cbiAgICAgICAgbWFya09ubGluZTogZnVuY3Rpb24gKHVzZXJJZCwgb3B0aW9ucykge1xuICAgICAgICAgICAgb3B0aW9ucyA9IG9wdGlvbnMgfHwge307XG4gICAgICAgICAgICB2YXIgaXNTdHJpbmcgPSB0eXBlb2YgdXNlcklkID09PSAnc3RyaW5nJztcbiAgICAgICAgICAgIHZhciBvYmpQYXJhbXMgPSBnZXRGaW5hbFBhcmFtcyh1c2VySWQpO1xuICAgICAgICAgICAgaWYgKCFvYmpQYXJhbXMuZ3JvdXBOYW1lICYmICFvcHRpb25zLmdyb3VwTmFtZSkge1xuICAgICAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcignTm8gZ3JvdXBOYW1lIHNwZWNpZmllZC4nKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHVzZXJJZCA9IGlzU3RyaW5nID8gdXNlcklkIDogb2JqUGFyYW1zLnVzZXJJZDtcbiAgICAgICAgICAgIHZhciBncm91cE5hbWUgPSBvcHRpb25zLmdyb3VwTmFtZSB8fCBvYmpQYXJhbXMuZ3JvdXBOYW1lO1xuICAgICAgICAgICAgdmFyIGh0dHBPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sIHNlcnZpY2VPcHRpb25zLCBvcHRpb25zLFxuICAgICAgICAgICAgICAgIHsgdXJsOiB1cmxDb25maWcuZ2V0QVBJUGF0aChhcGlFbmRwb2ludCkgKyBncm91cE5hbWUgKyAnLycgKyB1c2VySWQgfVxuICAgICAgICAgICAgKTtcbiAgICAgICAgICAgIHJldHVybiBodHRwLnBvc3QoeyBtZXNzYWdlOiAnb25saW5lJyB9LCBodHRwT3B0aW9ucyk7XG4gICAgICAgIH0sXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIE1hcmtzIGFuIGVuZCB1c2VyIGFzIG9mZmxpbmUuXG4gICAgICAgICAqXG4gICAgICAgICAqXG4gICAgICAgICAqICoqRXhhbXBsZSoqXG4gICAgICAgICAqXG4gICAgICAgICAqICAgICB2YXIgcHIgPSBuZXcgRi5zZXJ2aWNlLlByZXNlbmNlKCk7XG4gICAgICAgICAqICAgICBwci5tYXJrT2ZmbGluZSgnMDAwMDAxNWE2OGQ4MDZiYzA5Y2QwYTdkMjA3ZjQ0YmE1Zjc0Jyk7XG4gICAgICAgICAqXG4gICAgICAgICAqICoqUmV0dXJuIFZhbHVlKipcbiAgICAgICAgICpcbiAgICAgICAgICogUHJvbWlzZSB0byByZW1vdmUgcHJlc2VuY2UgcmVjb3JkIGZvciBlbmQgdXNlci5cbiAgICAgICAgICpcbiAgICAgICAgICogKipQYXJhbWV0ZXJzKipcbiAgICAgICAgICpcbiAgICAgICAgICogQHBhcmFtICB7U3RyaW5nfSB1c2VySWQgKG9wdGlvbmFsKSBJZiBub3QgcHJvdmlkZWQsIHRha2VuIGZyb20gc2Vzc2lvbiBjb29raWUuXG4gICAgICAgICAqIEBwYXJhbSAge09iamVjdH0gb3B0aW9ucyBBZGRpdGlvbmFsIG9wdGlvbnMgdG8gY2hhbmdlIHRoZSBwcmVzZW5jZSBzZXJ2aWNlIGRlZmF1bHRzLlxuICAgICAgICAgKiBAcmV0dXJuIHtQcm9taXNlfSBwcm9taXNlXG4gICAgICAgICAqL1xuICAgICAgICBtYXJrT2ZmbGluZTogZnVuY3Rpb24gKHVzZXJJZCwgb3B0aW9ucykge1xuICAgICAgICAgICAgb3B0aW9ucyA9IG9wdGlvbnMgfHwge307XG4gICAgICAgICAgICB2YXIgaXNTdHJpbmcgPSB0eXBlb2YgdXNlcklkID09PSAnc3RyaW5nJztcbiAgICAgICAgICAgIHZhciBvYmpQYXJhbXMgPSBnZXRGaW5hbFBhcmFtcyh1c2VySWQpO1xuICAgICAgICAgICAgaWYgKCFvYmpQYXJhbXMuZ3JvdXBOYW1lICYmICFvcHRpb25zLmdyb3VwTmFtZSkge1xuICAgICAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcignTm8gZ3JvdXBOYW1lIHNwZWNpZmllZC4nKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHVzZXJJZCA9IGlzU3RyaW5nID8gdXNlcklkIDogb2JqUGFyYW1zLnVzZXJJZDtcbiAgICAgICAgICAgIHZhciBncm91cE5hbWUgPSBvcHRpb25zLmdyb3VwTmFtZSB8fCBvYmpQYXJhbXMuZ3JvdXBOYW1lO1xuICAgICAgICAgICAgdmFyIGh0dHBPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sIHNlcnZpY2VPcHRpb25zLCBvcHRpb25zLFxuICAgICAgICAgICAgICAgIHsgdXJsOiB1cmxDb25maWcuZ2V0QVBJUGF0aChhcGlFbmRwb2ludCkgKyBncm91cE5hbWUgKyAnLycgKyB1c2VySWQgfVxuICAgICAgICAgICAgKTtcbiAgICAgICAgICAgIHJldHVybiBodHRwLmRlbGV0ZSh7fSwgaHR0cE9wdGlvbnMpO1xuICAgICAgICB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBSZXR1cm5zIGEgbGlzdCBvZiBhbGwgZW5kIHVzZXJzIGluIHRoaXMgZ3JvdXAgdGhhdCBhcmUgY3VycmVudGx5IG9ubGluZS5cbiAgICAgICAgICpcbiAgICAgICAgICpcbiAgICAgICAgICogKipFeGFtcGxlKipcbiAgICAgICAgICpcbiAgICAgICAgICogICAgIHZhciBwciA9IG5ldyBGLnNlcnZpY2UuUHJlc2VuY2UoKTtcbiAgICAgICAgICogICAgIHByLmdldFN0YXR1cygnZ3JvdXBOYW1lJykudGhlbihmdW5jdGlvbihvbmxpbmVVc2Vycykge1xuICAgICAgICAgKiAgICAgICAgICBmb3IgKHZhciBpPTA7IGkgPCBvbmxpbmVVc2Vycy5sZW5ndGg7IGkrKykge1xuICAgICAgICAgKiAgICAgICAgICAgICAgIGNvbnNvbGUubG9nKCd1c2VyICcsIG9ubGluZVVzZXJzW2ldLnVzZXJJZCwgXG4gICAgICAgICAqICAgICAgICAgICAgICAgICAgICAnIGlzIG9ubGluZSBhcyBvZiAnLCBvbmxpbmVVc2Vyc1tpXS5sYXN0TW9kaWZpZWQpO1xuICAgICAgICAgKiAgICAgICAgICB9XG4gICAgICAgICAqICAgICB9KTtcbiAgICAgICAgICpcbiAgICAgICAgICogKipSZXR1cm4gVmFsdWUqKlxuICAgICAgICAgKlxuICAgICAgICAgKiBQcm9taXNlIHdpdGggcmVzcG9uc2Ugb2Ygb25saW5lIHVzZXJzXG4gICAgICAgICAqXG4gICAgICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICAgICAqXG4gICAgICAgICAqIEBwYXJhbSAge1N0cmluZ30gZ3JvdXBOYW1lIChvcHRpb25hbCkgSWYgbm90IHByb3ZpZGVkLCB0YWtlbiBmcm9tIHNlc3Npb24gY29va2llLlxuICAgICAgICAgKiBAcGFyYW0gIHtPYmplY3R9IG9wdGlvbnMgQWRkaXRpb25hbCBvcHRpb25zIHRvIGNoYW5nZSB0aGUgcHJlc2VuY2Ugc2VydmljZSBkZWZhdWx0cy5cbiAgICAgICAgICogQHJldHVybiB7UHJvbWlzZX0gcHJvbWlzZVxuICAgICAgICAgKi9cbiAgICAgICAgZ2V0U3RhdHVzOiBmdW5jdGlvbiAoZ3JvdXBOYW1lLCBvcHRpb25zKSB7XG4gICAgICAgICAgICBvcHRpb25zID0gb3B0aW9ucyB8fCB7fTtcbiAgICAgICAgICAgIHZhciBvYmpQYXJhbXMgPSBnZXRGaW5hbFBhcmFtcyhncm91cE5hbWUpO1xuICAgICAgICAgICAgaWYgKCFncm91cE5hbWUgJiYgIW9ialBhcmFtcy5ncm91cE5hbWUpIHtcbiAgICAgICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ05vIGdyb3VwTmFtZSBzcGVjaWZpZWQuJyk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBncm91cE5hbWUgPSBncm91cE5hbWUgfHwgb2JqUGFyYW1zLmdyb3VwTmFtZTtcbiAgICAgICAgICAgIHZhciBodHRwT3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LCBzZXJ2aWNlT3B0aW9ucywgb3B0aW9ucyxcbiAgICAgICAgICAgICAgICB7IHVybDogdXJsQ29uZmlnLmdldEFQSVBhdGgoYXBpRW5kcG9pbnQpICsgZ3JvdXBOYW1lIH1cbiAgICAgICAgICAgICk7XG4gICAgICAgICAgICByZXR1cm4gaHR0cC5nZXQoe30sIGh0dHBPcHRpb25zKTtcbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgICogRW5kIHVzZXJzIGFyZSBhdXRvbWF0aWNhbGx5IG1hcmtlZCBvbmxpbmUgYW5kIG9mZmxpbmUgaW4gYSBcInByZXNlbmNlXCIgY2hhbm5lbCB0aGF0IGlzIHNwZWNpZmljIHRvIGVhY2ggZ3JvdXAuIEdldHMgdGhpcyBjaGFubmVsIChhbiBpbnN0YW5jZSBvZiB0aGUgW0NoYW5uZWwgU2VydmljZV0oLi4vY2hhbm5lbC1zZXJ2aWNlLykpIGZvciB0aGUgZ2l2ZW4gZ3JvdXAuIChOb3RlIHRoYXQgdGhpcyBDaGFubmVsIFNlcnZpY2UgaW5zdGFuY2UgaXMgYWxzbyBhdmFpbGFibGUgZnJvbSB0aGUgW0VwaWNlbnRlciBDaGFubmVsIE1hbmFnZXIgZ2V0UHJlc2VuY2VDaGFubmVsKCldKC4uL2VwaWNlbnRlci1jaGFubmVsLW1hbmFnZXIvI2dldFByZXNlbmNlQ2hhbm5lbCkuKVxuICAgICAgICAgKlxuICAgICAgICAgKlxuICAgICAgICAgKiAqKkV4YW1wbGUqKlxuICAgICAgICAgKlxuICAgICAgICAgKiAgICAgdmFyIHByID0gbmV3IEYuc2VydmljZS5QcmVzZW5jZSgpO1xuICAgICAgICAgKiAgICAgdmFyIGNtID0gcHIuZ2V0Q2hhbm5lbCgnZ3JvdXAxJyk7XG4gICAgICAgICAqICAgICBjbS5wdWJsaXNoKCcnLCAnYSBtZXNzYWdlIHRvIHByZXNlbmNlIGNoYW5uZWwnKTtcbiAgICAgICAgICpcbiAgICAgICAgICogKipSZXR1cm4gVmFsdWUqKlxuICAgICAgICAgKlxuICAgICAgICAgKiBDaGFubmVsIGluc3RhbmNlIGZvciBQcmVzZW5jZSBjaGFubmVsXG4gICAgICAgICAqXG4gICAgICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICAgICAqXG4gICAgICAgICAqIEBwYXJhbSAge1N0cmluZ30gZ3JvdXBOYW1lIChvcHRpb25hbCkgSWYgbm90IHByb3ZpZGVkLCB0YWtlbiBmcm9tIHNlc3Npb24gY29va2llLlxuICAgICAgICAgKiBAcGFyYW0gIHtPYmplY3R9IG9wdGlvbnMgQWRkaXRpb25hbCBvcHRpb25zIHRvIGNoYW5nZSB0aGUgcHJlc2VuY2Ugc2VydmljZSBkZWZhdWx0c1xuICAgICAgICAgKiBAcmV0dXJuIHtDaGFubmVsfSBDaGFubmVsIGluc3RhbmNlXG4gICAgICAgICAqL1xuICAgICAgICBnZXRDaGFubmVsOiBmdW5jdGlvbiAoZ3JvdXBOYW1lLCBvcHRpb25zKSB7XG4gICAgICAgICAgICBvcHRpb25zID0gb3B0aW9ucyB8fCB7fTtcbiAgICAgICAgICAgIHZhciBpc1N0cmluZyA9IHR5cGVvZiBncm91cE5hbWUgPT09ICdzdHJpbmcnO1xuICAgICAgICAgICAgdmFyIG9ialBhcmFtcyA9IGdldEZpbmFsUGFyYW1zKGdyb3VwTmFtZSk7XG4gICAgICAgICAgICBpZiAoIWlzU3RyaW5nICYmICFvYmpQYXJhbXMuZ3JvdXBOYW1lKSB7XG4gICAgICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdObyBncm91cE5hbWUgc3BlY2lmaWVkLicpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgZ3JvdXBOYW1lID0gaXNTdHJpbmcgPyBncm91cE5hbWUgOiBvYmpQYXJhbXMuZ3JvdXBOYW1lO1xuICAgICAgICAgICAgdmFyIGNtID0gbmV3IENoYW5uZWxNYW5hZ2VyKG9wdGlvbnMpO1xuICAgICAgICAgICAgcmV0dXJuIGNtLmdldFByZXNlbmNlQ2hhbm5lbChncm91cE5hbWUpO1xuICAgICAgICB9XG4gICAgfTtcblxuICAgICQuZXh0ZW5kKHRoaXMsIHB1YmxpY0FQSSk7XG59O1xuIiwiLyoqXG4gKlxuICogIyMgUnVuIEFQSSBTZXJ2aWNlXG4gKlxuICogVGhlIFJ1biBBUEkgU2VydmljZSBhbGxvd3MgeW91IHRvIHBlcmZvcm0gY29tbW9uIHRhc2tzIGFyb3VuZCBjcmVhdGluZyBhbmQgdXBkYXRpbmcgcnVucywgdmFyaWFibGVzLCBhbmQgZGF0YS5cbiAqXG4gKiBXaGVuIGJ1aWxkaW5nIGludGVyZmFjZXMgdG8gc2hvdyBydW4gb25lIGF0IGEgdGltZSAoYXMgZm9yIHN0YW5kYXJkIGVuZCB1c2VycyksIHR5cGljYWxseSB5b3UgZmlyc3QgaW5zdGFudGlhdGUgYSBbUnVuIE1hbmFnZXJdKC4uL3J1bi1tYW5hZ2VyLykgYW5kIHRoZW4gYWNjZXNzIHRoZSBSdW4gU2VydmljZSB0aGF0IGlzIGF1dG9tYXRpY2FsbHkgcGFydCBvZiB0aGUgbWFuYWdlciwgcmF0aGVyIHRoYW4gaW5zdGFudGlhdGluZyB0aGUgUnVuIFNlcnZpY2UgZGlyZWN0bHkuIFRoaXMgaXMgYmVjYXVzZSB0aGUgUnVuIE1hbmFnZXIgKGFuZCBhc3NvY2lhdGVkIFtydW4gc3RyYXRlZ2llc10oLi4vc3RyYXRlZ2llcy8pKSBnaXZlcyB5b3UgY29udHJvbCBvdmVyIHJ1biBjcmVhdGlvbiBkZXBlbmRpbmcgb24gcnVuIHN0YXRlcy5cbiAqXG4gKiBUaGUgUnVuIEFQSSBTZXJ2aWNlIGlzIHVzZWZ1bCBmb3IgYnVpbGRpbmcgYW4gaW50ZXJmYWNlIHdoZXJlIHlvdSB3YW50IHRvIHNob3cgZGF0YSBhY3Jvc3MgbXVsdGlwbGUgcnVucyAodGhpcyBpcyBlYXN5IHVzaW5nIHRoZSBgZmlsdGVyKClgIGFuZCBgcXVlcnkoKWAgbWV0aG9kcykuIEZvciBpbnN0YW5jZSwgeW91IHdvdWxkIHByb2JhYmx5IHVzZSBhIFJ1biBTZXJ2aWNlIHRvIGJ1aWxkIGEgcGFnZSBmb3IgYSBmYWNpbGl0YXRvci4gVGhpcyBpcyBiZWNhdXNlIGEgZmFjaWxpdGF0b3IgdHlwaWNhbGx5IHdhbnRzIHRvIGV2YWx1YXRlIHBlcmZvcm1hbmNlIGZyb20gbXVsdGlwbGUgZW5kIHVzZXJzLCBlYWNoIG9mIHdob20gaGF2ZSBiZWVuIHdvcmtpbmcgd2l0aCB0aGVpciBvd24gcnVuLlxuICpcbiAqIFRvIHVzZSB0aGUgUnVuIEFQSSBTZXJ2aWNlLCBpbnN0YW50aWF0ZSBpdCBieSBwYXNzaW5nIGluOlxuICpcbiAqICogYGFjY291bnRgOiBFcGljZW50ZXIgYWNjb3VudCBpZCAoKipUZWFtIElEKiogZm9yIHRlYW0gcHJvamVjdHMsICoqVXNlciBJRCoqIGZvciBwZXJzb25hbCBwcm9qZWN0cykuXG4gKiAqIGBwcm9qZWN0YDogRXBpY2VudGVyIHByb2plY3QgaWQuXG4gKlxuICogSWYgeW91IGtub3cgaW4gYWR2YW5jZSB0aGF0IHlvdSB3b3VsZCBsaWtlIHRvIHdvcmsgd2l0aCBwYXJ0aWN1bGFyLCBleGlzdGluZyBydW4ocyksIHlvdSBjYW4gb3B0aW9uYWxseSBwYXNzIGluOlxuICpcbiAqICogYGZpbHRlcmA6IChPcHRpb25hbCkgQ3JpdGVyaWEgYnkgd2hpY2ggdG8gZmlsdGVyIGZvciBleGlzdGluZyBydW5zLiBcbiAqICogYGlkYDogKE9wdGlvbmFsKSBUaGUgcnVuIGlkIG9mIGFuIGV4aXN0aW5nIHJ1bi4gVGhpcyBpcyBhIGNvbnZlbmllbmNlIGFsaWFzIGZvciB1c2luZyBmaWx0ZXIsIGluIHRoZSBjYXNlIHdoZXJlIHlvdSBvbmx5IHdhbnQgdG8gd29yayB3aXRoIG9uZSBydW4uXG4gKlxuICogRm9yIGV4YW1wbGUsXG4gKlxuICogICAgICAgdmFyIHJzID0gbmV3IEYuc2VydmljZS5SdW4oe1xuICogICAgICAgICAgICBhY2NvdW50OiAnYWNtZS1zaW11bGF0aW9ucycsXG4gKiAgICAgICAgICAgIHByb2plY3Q6ICdzdXBwbHktY2hhaW4tZ2FtZScsXG4gKiAgICAgIH0pO1xuICogICAgICBycy5jcmVhdGUoJ3N1cHBseV9jaGFpbl9nYW1lLnB5JykudGhlbihmdW5jdGlvbihydW4pIHtcbiAqICAgICAgICAgICAgIHJzLmRvKCdzb21lT3BlcmF0aW9uJyk7XG4gKiAgICAgIH0pO1xuICpcbiAqXG4gKiBBZGRpdGlvbmFsbHksIGFsbCBBUEkgY2FsbHMgdGFrZSBpbiBhbiBgb3B0aW9uc2Agb2JqZWN0IGFzIHRoZSBsYXN0IHBhcmFtZXRlci4gVGhlIG9wdGlvbnMgY2FuIGJlIHVzZWQgdG8gZXh0ZW5kL292ZXJyaWRlIHRoZSBSdW4gQVBJIFNlcnZpY2UgZGVmYXVsdHMgbGlzdGVkIGJlbG93LiBJbiBwYXJ0aWN1bGFyLCBwYXNzaW5nIGB7IGlkOiAnYS1ydW4taWQnIH1gIGluIHRoaXMgYG9wdGlvbnNgIG9iamVjdCBhbGxvd3MgeW91IHRvIG1ha2UgY2FsbHMgdG8gYW4gZXhpc3RpbmcgcnVuLlxuICpcbiAqIE5vdGUgdGhhdCBpbiBhZGRpdGlvbiB0byB0aGUgYGFjY291bnRgLCBgcHJvamVjdGAsIGFuZCBgbW9kZWxgLCB0aGUgUnVuIFNlcnZpY2UgcGFyYW1ldGVycyBvcHRpb25hbGx5IGluY2x1ZGUgYSBgc2VydmVyYCBvYmplY3QsIHdob3NlIGBob3N0YCBmaWVsZCBjb250YWlucyB0aGUgVVJJIG9mIHRoZSBGb3JpbyBzZXJ2ZXIuIFRoaXMgaXMgYXV0b21hdGljYWxseSBzZXQsIGJ1dCB5b3UgY2FuIHBhc3MgaXQgZXhwbGljaXRseSBpZiBkZXNpcmVkLiBJdCBpcyBtb3N0IGNvbW1vbmx5IHVzZWQgZm9yIGNsYXJpdHkgd2hlbiB5b3UgYXJlIFtob3N0aW5nIGFuIEVwaWNlbnRlciBwcm9qZWN0IG9uIHlvdXIgb3duIHNlcnZlcl0oLi4vLi4vLi4vaG93X3RvL3NlbGZfaG9zdGluZy8pLlxuICpcbiAqICAgICAgIHZhciBybSA9IG5ldyBGLm1hbmFnZXIuUnVuTWFuYWdlcih7XG4gKiAgICAgICAgICAgcnVuOiB7XG4gKiAgICAgICAgICAgICAgIGFjY291bnQ6ICdhY21lLXNpbXVsYXRpb25zJyxcbiAqICAgICAgICAgICAgICAgcHJvamVjdDogJ3N1cHBseS1jaGFpbi1nYW1lJyxcbiAqICAgICAgICAgICAgICAgbW9kZWw6ICdzdXBwbHlfY2hhaW5fZ2FtZS5weScsXG4gKiAgICAgICAgICAgICAgIHNlcnZlcjogeyBob3N0OiAnYXBpLmZvcmlvLmNvbScgfVxuICogICAgICAgICAgIH1cbiAqICAgICAgIH0pO1xuICogICAgICAgcm0uZ2V0UnVuKClcbiAqICAgICAgICAgICAudGhlbihmdW5jdGlvbihydW4pIHtcbiAqICAgICAgICAgICAgICAgLy8gdGhlIFJ1bk1hbmFnZXIucnVuIGNvbnRhaW5zIHRoZSBpbnN0YW50aWF0ZWQgUnVuIFNlcnZpY2UsXG4gKiAgICAgICAgICAgICAgIC8vIHNvIGFueSBSdW4gU2VydmljZSBtZXRob2QgaXMgdmFsaWQgaGVyZVxuICogICAgICAgICAgICAgICB2YXIgcnMgPSBybS5ydW47XG4gKiAgICAgICAgICAgICAgIHJzLmRvKCdzb21lT3BlcmF0aW9uJyk7XG4gKiAgICAgICB9KVxuICpcbiAqL1xuXG4ndXNlIHN0cmljdCc7XG5cbnZhciBDb25maWdTZXJ2aWNlID0gcmVxdWlyZSgnLi9jb25maWd1cmF0aW9uLXNlcnZpY2UnKTtcbnZhciBxdXRpbCA9IHJlcXVpcmUoJy4uL3V0aWwvcXVlcnktdXRpbCcpO1xudmFyIHJ1dGlsID0gcmVxdWlyZSgnLi4vdXRpbC9ydW4tdXRpbCcpO1xudmFyIF9waWNrID0gcmVxdWlyZSgnLi4vdXRpbC9vYmplY3QtdXRpbCcpLl9waWNrO1xudmFyIFRyYW5zcG9ydEZhY3RvcnkgPSByZXF1aXJlKCcuLi90cmFuc3BvcnQvaHR0cC10cmFuc3BvcnQtZmFjdG9yeScpO1xudmFyIFZhcmlhYmxlc1NlcnZpY2UgPSByZXF1aXJlKCcuL3ZhcmlhYmxlcy1hcGktc2VydmljZScpO1xudmFyIEludHJvc3BlY3Rpb25TZXJ2aWNlID0gcmVxdWlyZSgnLi9pbnRyb3NwZWN0aW9uLWFwaS1zZXJ2aWNlJyk7XG52YXIgU2Vzc2lvbk1hbmFnZXIgPSByZXF1aXJlKCcuLi9zdG9yZS9zZXNzaW9uLW1hbmFnZXInKTtcblxubW9kdWxlLmV4cG9ydHMgPSBmdW5jdGlvbiAoY29uZmlnKSB7XG4gICAgdmFyIGRlZmF1bHRzID0ge1xuICAgICAgICAvKipcbiAgICAgICAgICogRm9yIHByb2plY3RzIHRoYXQgcmVxdWlyZSBhdXRoZW50aWNhdGlvbiwgcGFzcyBpbiB0aGUgdXNlciBhY2Nlc3MgdG9rZW4gKGRlZmF1bHRzIHRvIHVuZGVmaW5lZCkuIElmIHRoZSB1c2VyIGlzIGFscmVhZHkgbG9nZ2VkIGluIHRvIEVwaWNlbnRlciwgdGhlIHVzZXIgYWNjZXNzIHRva2VuIGlzIGFscmVhZHkgc2V0IGluIGEgY29va2llIGFuZCBhdXRvbWF0aWNhbGx5IGxvYWRlZCBmcm9tIHRoZXJlLiAoU2VlIFttb3JlIGJhY2tncm91bmQgb24gYWNjZXNzIHRva2Vuc10oLi4vLi4vLi4vcHJvamVjdF9hY2Nlc3MvKSkuXG4gICAgICAgICAqIEBzZWUgW0F1dGhlbnRpY2F0aW9uIEFQSSBTZXJ2aWNlXSguLi9hdXRoLWFwaS1zZXJ2aWNlLykgZm9yIGdldHRpbmcgdG9rZW5zLlxuICAgICAgICAgKiBAdHlwZSB7U3RyaW5nfVxuICAgICAgICAgKi9cbiAgICAgICAgdG9rZW46IHVuZGVmaW5lZCxcblxuICAgICAgICAvKipcbiAgICAgICAgICogVGhlIGFjY291bnQgaWQuIEluIHRoZSBFcGljZW50ZXIgVUksIHRoaXMgaXMgdGhlICoqVGVhbSBJRCoqIChmb3IgdGVhbSBwcm9qZWN0cykgb3IgKipVc2VyIElEKiogKGZvciBwZXJzb25hbCBwcm9qZWN0cykuIERlZmF1bHRzIHRvIHVuZGVmaW5lZC4gSWYgbGVmdCB1bmRlZmluZWQsIHRha2VuIGZyb20gdGhlIFVSTC5cbiAgICAgICAgICogQHR5cGUge1N0cmluZ31cbiAgICAgICAgICovXG4gICAgICAgIGFjY291bnQ6IHVuZGVmaW5lZCxcblxuICAgICAgICAvKipcbiAgICAgICAgICogVGhlIHByb2plY3QgaWQuIERlZmF1bHRzIHRvIHVuZGVmaW5lZC4gSWYgbGVmdCB1bmRlZmluZWQsIHRha2VuIGZyb20gdGhlIFVSTC5cbiAgICAgICAgICogQHR5cGUge1N0cmluZ31cbiAgICAgICAgICovXG4gICAgICAgIHByb2plY3Q6IHVuZGVmaW5lZCxcblxuICAgICAgICAvKipcbiAgICAgICAgICogQ3JpdGVyaWEgYnkgd2hpY2ggdG8gZmlsdGVyIHJ1bnMuIERlZmF1bHRzIHRvIGVtcHR5IHN0cmluZy5cbiAgICAgICAgICogQHR5cGUge1N0cmluZ31cbiAgICAgICAgICovXG4gICAgICAgIGZpbHRlcjogJycsXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIENvbnZlbmllbmNlIGFsaWFzIGZvciBmaWx0ZXIuIFBhc3MgaW4gYW4gZXhpc3RpbmcgcnVuIGlkIHRvIGludGVyYWN0IHdpdGggYSBwYXJ0aWN1bGFyIHJ1bi5cbiAgICAgICAgICogQHR5cGUge1N0cmluZ31cbiAgICAgICAgICovXG4gICAgICAgIGlkOiAnJyxcblxuICAgICAgICAvKipcbiAgICAgICAgICogRmxhZyBkZXRlcm1pbmVzIGlmIGBYLUF1dG9SZXN0b3JlOiB0cnVlYCBoZWFkZXIgaXMgc2VudCB0byBFcGljZW50ZXIsIG1lYW5pbmcgcnVucyBhcmUgYXV0b21hdGljYWxseSBwdWxsZWQgZnJvbSB0aGUgRXBpY2VudGVyIGJhY2tlbmQgZGF0YWJhc2UgaWYgbm90IGN1cnJlbnRseSBpbiBtZW1vcnkgb24gdGhlIEVwaWNlbnRlciBzZXJ2ZXJzLiBEZWZhdWx0cyB0byBgdHJ1ZWAuXG4gICAgICAgICAqIEB0eXBlIHtib29sZWFufVxuICAgICAgICAgKi9cbiAgICAgICAgYXV0b1Jlc3RvcmU6IHRydWUsXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIENhbGxlZCB3aGVuIHRoZSBjYWxsIGNvbXBsZXRlcyBzdWNjZXNzZnVsbHkuIERlZmF1bHRzIHRvIGAkLm5vb3BgLlxuICAgICAgICAgKiBAdHlwZSB7ZnVuY3Rpb259XG4gICAgICAgICAqL1xuICAgICAgICBzdWNjZXNzOiAkLm5vb3AsXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIENhbGxlZCB3aGVuIHRoZSBjYWxsIGZhaWxzLiBEZWZhdWx0cyB0byBgJC5ub29wYC5cbiAgICAgICAgICogQHR5cGUge2Z1bmN0aW9ufVxuICAgICAgICAgKi9cbiAgICAgICAgZXJyb3I6ICQubm9vcCxcblxuICAgICAgICAvKipcbiAgICAgICAgICogT3B0aW9ucyB0byBwYXNzIG9uIHRvIHRoZSB1bmRlcmx5aW5nIHRyYW5zcG9ydCBsYXllci4gQWxsIGpxdWVyeS5hamF4IG9wdGlvbnMgYXQgaHR0cDovL2FwaS5qcXVlcnkuY29tL2pRdWVyeS5hamF4LyBhcmUgYXZhaWxhYmxlLiBEZWZhdWx0cyB0byBlbXB0eSBvYmplY3QuXG4gICAgICAgICAqIEB0eXBlIHtPYmplY3R9XG4gICAgICAgICAqL1xuICAgICAgICB0cmFuc3BvcnQ6IHt9XG4gICAgfTtcblxuICAgIHRoaXMuc2Vzc2lvbk1hbmFnZXIgPSBuZXcgU2Vzc2lvbk1hbmFnZXIoKTtcbiAgICB2YXIgc2VydmljZU9wdGlvbnMgPSB0aGlzLnNlc3Npb25NYW5hZ2VyLmdldE1lcmdlZE9wdGlvbnMoZGVmYXVsdHMsIGNvbmZpZyk7XG4gICAgaWYgKHNlcnZpY2VPcHRpb25zLmlkKSB7XG4gICAgICAgIHNlcnZpY2VPcHRpb25zLmZpbHRlciA9IHNlcnZpY2VPcHRpb25zLmlkO1xuICAgIH1cblxuICAgIGZ1bmN0aW9uIHVwZGF0ZVVSTENvbmZpZyhvcHRzKSB7XG4gICAgICAgIHZhciB1cmxDb25maWcgPSBuZXcgQ29uZmlnU2VydmljZShvcHRzKS5nZXQoJ3NlcnZlcicpO1xuICAgICAgICBpZiAob3B0cy5hY2NvdW50KSB7XG4gICAgICAgICAgICB1cmxDb25maWcuYWNjb3VudFBhdGggPSBvcHRzLmFjY291bnQ7XG4gICAgICAgIH1cbiAgICAgICAgaWYgKG9wdHMucHJvamVjdCkge1xuICAgICAgICAgICAgdXJsQ29uZmlnLnByb2plY3RQYXRoID0gb3B0cy5wcm9qZWN0O1xuICAgICAgICB9XG5cbiAgICAgICAgdXJsQ29uZmlnLmZpbHRlciA9ICc7JztcbiAgICAgICAgdXJsQ29uZmlnLmdldEZpbHRlclVSTCA9IGZ1bmN0aW9uIChmaWx0ZXIpIHtcbiAgICAgICAgICAgIHZhciB1cmwgPSB1cmxDb25maWcuZ2V0QVBJUGF0aCgncnVuJyk7XG4gICAgICAgICAgICB2YXIgZmlsdGVyTWF0cml4ID0gcXV0aWwudG9NYXRyaXhGb3JtYXQoZmlsdGVyIHx8IG9wdHMuZmlsdGVyKTtcblxuICAgICAgICAgICAgaWYgKGZpbHRlck1hdHJpeCkge1xuICAgICAgICAgICAgICAgIHVybCArPSBmaWx0ZXJNYXRyaXggKyAnLyc7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICByZXR1cm4gdXJsO1xuICAgICAgICB9O1xuXG4gICAgICAgIHVybENvbmZpZy5hZGRBdXRvUmVzdG9yZUhlYWRlciA9IGZ1bmN0aW9uIChvcHRpb25zKSB7XG4gICAgICAgICAgICB2YXIgZmlsdGVyID0gb3B0cy5maWx0ZXI7XG4gICAgICAgICAgICAvLyBUaGUgc2VtaWNvbG9uIHNlcGFyYXRlZCBmaWx0ZXIgaXMgdXNlZCB3aGVuIGZpbHRlciBpcyBhbiBvYmplY3RcbiAgICAgICAgICAgIHZhciBpc0ZpbHRlclJ1bklkID0gZmlsdGVyICYmICQudHlwZShmaWx0ZXIpID09PSAnc3RyaW5nJztcbiAgICAgICAgICAgIGlmIChvcHRzLmF1dG9SZXN0b3JlICYmIGlzRmlsdGVyUnVuSWQpIHtcbiAgICAgICAgICAgICAgICAvLyBCeSBkZWZhdWx0IGF1dG9yZXBsYXkgdGhlIHJ1biBieSBzZW5kaW5nIHRoaXMgaGVhZGVyIHRvIGVwaWNlbnRlclxuICAgICAgICAgICAgICAgIC8vIGh0dHBzOi8vZm9yaW8uY29tL2VwaWNlbnRlci9kb2NzL3B1YmxpYy9yZXN0X2FwaXMvYWdncmVnYXRlX3J1bl9hcGkvI3JldHJpZXZpbmdcbiAgICAgICAgICAgICAgICB2YXIgYXV0b3Jlc3RvcmVPcHRzID0ge1xuICAgICAgICAgICAgICAgICAgICBoZWFkZXJzOiB7XG4gICAgICAgICAgICAgICAgICAgICAgICAnWC1BdXRvUmVzdG9yZSc6IHRydWVcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIH07XG4gICAgICAgICAgICAgICAgcmV0dXJuICQuZXh0ZW5kKHRydWUsIGF1dG9yZXN0b3JlT3B0cywgb3B0aW9ucyk7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIHJldHVybiBvcHRpb25zO1xuICAgICAgICB9O1xuICAgICAgICByZXR1cm4gdXJsQ29uZmlnO1xuICAgIH1cblxuICAgIHZhciBodHRwO1xuICAgIHZhciBodHRwT3B0aW9uczsgLy9GSVhNRTogTWFrZSB0aGlzIHNpZGUtZWZmZWN0LWxlc3NcbiAgICBmdW5jdGlvbiB1cGRhdGVIVFRQQ29uZmlnKHNlcnZpY2VPcHRpb25zLCB1cmxDb25maWcpIHtcbiAgICAgICAgaHR0cE9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSwgc2VydmljZU9wdGlvbnMudHJhbnNwb3J0LCB7XG4gICAgICAgICAgICB1cmw6IHVybENvbmZpZy5nZXRGaWx0ZXJVUkxcbiAgICAgICAgfSk7XG5cbiAgICAgICAgaWYgKHNlcnZpY2VPcHRpb25zLnRva2VuKSB7XG4gICAgICAgICAgICBodHRwT3B0aW9ucy5oZWFkZXJzID0ge1xuICAgICAgICAgICAgICAgIEF1dGhvcml6YXRpb246ICdCZWFyZXIgJyArIHNlcnZpY2VPcHRpb25zLnRva2VuXG4gICAgICAgICAgICB9O1xuICAgICAgICB9XG4gICAgICAgIGh0dHAgPSBuZXcgVHJhbnNwb3J0RmFjdG9yeShodHRwT3B0aW9ucyk7XG4gICAgICAgIGh0dHAuc3BsaXRHZXQgPSBydXRpbC5zcGxpdEdldEZhY3RvcnkoaHR0cE9wdGlvbnMpO1xuICAgIH1cblxuICAgIHZhciB1cmxDb25maWcgPSB1cGRhdGVVUkxDb25maWcoc2VydmljZU9wdGlvbnMpOyAvL21ha2luZyBhIGZ1bmN0aW9uIHNvICN1cGRhdGVDb25maWcgY2FuIGNhbGwgdGhpczsgY2hhbmdlIHdoZW4gcmVmYWN0b3JlZFxuICAgIHVwZGF0ZUhUVFBDb25maWcoc2VydmljZU9wdGlvbnMsIHVybENvbmZpZyk7XG4gICBcblxuICAgIGZ1bmN0aW9uIHNldEZpbHRlck9yVGhyb3dFcnJvcihvcHRpb25zKSB7XG4gICAgICAgIGlmIChvcHRpb25zLmlkKSB7XG4gICAgICAgICAgICBzZXJ2aWNlT3B0aW9ucy5maWx0ZXIgPSBzZXJ2aWNlT3B0aW9ucy5pZCA9IG9wdGlvbnMuaWQ7XG4gICAgICAgIH1cbiAgICAgICAgaWYgKG9wdGlvbnMuZmlsdGVyKSB7XG4gICAgICAgICAgICBzZXJ2aWNlT3B0aW9ucy5maWx0ZXIgPSBzZXJ2aWNlT3B0aW9ucy5pZCA9IG9wdGlvbnMuZmlsdGVyO1xuICAgICAgICB9XG4gICAgICAgIGlmICghc2VydmljZU9wdGlvbnMuZmlsdGVyKSB7XG4gICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ05vIGZpbHRlciBzcGVjaWZpZWQgdG8gYXBwbHkgb3BlcmF0aW9ucyBhZ2FpbnN0Jyk7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICB2YXIgcHVibGljQXN5bmNBUEkgPSB7XG4gICAgICAgIHVybENvbmZpZzogdXJsQ29uZmlnLFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBDcmVhdGUgYSBuZXcgcnVuLlxuICAgICAgICAgKlxuICAgICAgICAgKiBOT1RFOiBUeXBpY2FsbHkgdGhpcyBpcyBub3QgdXNlZCEgVXNlIGBSdW5NYW5hZ2VyLmdldFJ1bigpYCB3aXRoIGEgYHN0cmF0ZWd5YCBvZiBgcmV1c2UtbmV2ZXJgLCBvciB1c2UgYFJ1bk1hbmFnZXIucmVzZXQoKWAuIFNlZSBbUnVuIE1hbmFnZXJdKC4uL3J1bi1tYW5hZ2VyLykgZm9yIG1vcmUgZGV0YWlscy5cbiAgICAgICAgICpcbiAgICAgICAgICogICoqRXhhbXBsZSoqXG4gICAgICAgICAqXG4gICAgICAgICAqICAgICAgcnMuY3JlYXRlKCdoZWxsb193b3JsZC5qbCcpO1xuICAgICAgICAgKlxuICAgICAgICAgKiAgKipQYXJhbWV0ZXJzKipcbiAgICAgICAgICogQHBhcmFtIHtTdHJpbmd8T2JqZWN0fSBwYXJhbXMgSWYgYSBzdHJpbmcsIHRoZSBuYW1lIG9mIHRoZSBwcmltYXJ5IFttb2RlbCBmaWxlXSguLi8uLi8uLi93cml0aW5nX3lvdXJfbW9kZWwvKS4gVGhpcyBpcyB0aGUgb25lIGZpbGUgaW4gdGhlIHByb2plY3QgdGhhdCBleHBsaWNpdGx5IGV4cG9zZXMgdmFyaWFibGVzIGFuZCBtZXRob2RzLCBhbmQgaXQgbXVzdCBiZSBzdG9yZWQgaW4gdGhlIE1vZGVsIGZvbGRlciBvZiB5b3VyIEVwaWNlbnRlciBwcm9qZWN0LiBJZiBhbiBvYmplY3QsIG1heSBpbmNsdWRlIGBtb2RlbGAsIGBzY29wZWAsIGFuZCBgZmlsZXNgLiAoU2VlIHRoZSBbUnVuIE1hbmFnZXJdKC4uL3J1bl9tYW5hZ2VyLykgZm9yIG1vcmUgaW5mb3JtYXRpb24gb24gYHNjb3BlYCBhbmQgYGZpbGVzYC4pXG4gICAgICAgICAqIEBwYXJhbSB7T2JqZWN0fSBvcHRpb25zIChPcHRpb25hbCkgT3ZlcnJpZGVzIGZvciBjb25maWd1cmF0aW9uIG9wdGlvbnMuXG4gICAgICAgICAqIEByZXR1cm4ge1Byb21pc2V9XG4gICAgICAgICAqL1xuICAgICAgICBjcmVhdGU6IGZ1bmN0aW9uIChwYXJhbXMsIG9wdGlvbnMpIHtcbiAgICAgICAgICAgIHZhciBjcmVhdGVPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sIHNlcnZpY2VPcHRpb25zLCBvcHRpb25zLCB7IHVybDogdXJsQ29uZmlnLmdldEFQSVBhdGgoJ3J1bicpIH0pO1xuICAgICAgICAgICAgdmFyIHJ1bkFwaVBhcmFtcyA9IFsnbW9kZWwnLCAnc2NvcGUnLCAnZmlsZXMnLCAnZXBoZW1lcmFsJywgJ2NpbkZpbGVzJ107XG4gICAgICAgICAgICBpZiAodHlwZW9mIHBhcmFtcyA9PT0gJ3N0cmluZycpIHtcbiAgICAgICAgICAgICAgICAvLyB0aGlzIGlzIGp1c3QgdGhlIG1vZGVsIG5hbWVcbiAgICAgICAgICAgICAgICBwYXJhbXMgPSB7IG1vZGVsOiBwYXJhbXMgfTtcbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgLy8gd2hpdGVsaXN0IHRoZSBmaWVsZHMgdGhhdCB3ZSBhY3R1YWxseSBjYW4gc2VuZCB0byB0aGUgYXBpXG4gICAgICAgICAgICAgICAgcGFyYW1zID0gX3BpY2socGFyYW1zLCBydW5BcGlQYXJhbXMpO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICB2YXIgb2xkU3VjY2VzcyA9IGNyZWF0ZU9wdGlvbnMuc3VjY2VzcztcbiAgICAgICAgICAgIGNyZWF0ZU9wdGlvbnMuc3VjY2VzcyA9IGZ1bmN0aW9uIChyZXNwb25zZSkge1xuICAgICAgICAgICAgICAgIHNlcnZpY2VPcHRpb25zLmZpbHRlciA9IHJlc3BvbnNlLmlkOyAvL2FsbCBmdXR1cmUgY2hhaW5lZCBjYWxscyB0byBvcGVyYXRlIG9uIHRoaXMgaWRcbiAgICAgICAgICAgICAgICBzZXJ2aWNlT3B0aW9ucy5pZCA9IHJlc3BvbnNlLmlkO1xuICAgICAgICAgICAgICAgIHJldHVybiBvbGRTdWNjZXNzLmFwcGx5KHRoaXMsIGFyZ3VtZW50cyk7XG4gICAgICAgICAgICB9O1xuXG4gICAgICAgICAgICByZXR1cm4gaHR0cC5wb3N0KHBhcmFtcywgY3JlYXRlT3B0aW9ucyk7XG4gICAgICAgIH0sXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIFJldHVybnMgcGFydGljdWxhciBydW5zLCBiYXNlZCBvbiBjb25kaXRpb25zIHNwZWNpZmllZCBpbiB0aGUgYHFzYCBvYmplY3QuXG4gICAgICAgICAqXG4gICAgICAgICAqIFRoZSBlbGVtZW50cyBvZiB0aGUgYHFzYCBvYmplY3QgYXJlIEFORGVkIHRvZ2V0aGVyIHdpdGhpbiBhIHNpbmdsZSBjYWxsIHRvIGAucXVlcnkoKWAuXG4gICAgICAgICAqXG4gICAgICAgICAqICoqRXhhbXBsZSoqXG4gICAgICAgICAqXG4gICAgICAgICAqICAgICAgLy8gcmV0dXJucyBydW5zIHdpdGggc2F2ZWQgPSB0cnVlIGFuZCB2YXJpYWJsZXMucHJpY2UgPiAxLFxuICAgICAgICAgKiAgICAgIC8vIHdoZXJlIHZhcmlhYmxlcy5wcmljZSBoYXMgYmVlbiBwZXJzaXN0ZWQgKHJlY29yZGVkKVxuICAgICAgICAgKiAgICAgIC8vIGluIHRoZSBtb2RlbC5cbiAgICAgICAgICogICAgIHJzLnF1ZXJ5KHtcbiAgICAgICAgICogICAgICAgICAgJ3NhdmVkJzogJ3RydWUnLFxuICAgICAgICAgKiAgICAgICAgICAnLnByaWNlJzogJz4xJ1xuICAgICAgICAgKiAgICAgICB9LFxuICAgICAgICAgKiAgICAgICB7XG4gICAgICAgICAqICAgICAgICAgIHN0YXJ0cmVjb3JkOiAyLFxuICAgICAgICAgKiAgICAgICAgICBlbmRyZWNvcmQ6IDVcbiAgICAgICAgICogICAgICAgfSk7XG4gICAgICAgICAqXG4gICAgICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICAgICAqIEBwYXJhbSB7T2JqZWN0fSBxcyBRdWVyeSBvYmplY3QuIEVhY2gga2V5IGNhbiBiZSBhIHByb3BlcnR5IG9mIHRoZSBydW4gb3IgdGhlIG5hbWUgb2YgdmFyaWFibGUgdGhhdCBoYXMgYmVlbiBzYXZlZCBpbiB0aGUgcnVuIChwcmVmYWNlZCBieSBgdmFyaWFibGVzLmApLiBFYWNoIHZhbHVlIGNhbiBiZSBhIGxpdGVyYWwgdmFsdWUsIG9yIGEgY29tcGFyaXNvbiBvcGVyYXRvciBhbmQgdmFsdWUuIChTZWUgW21vcmUgb24gZmlsdGVyaW5nXSguLi8uLi8uLi9yZXN0X2FwaXMvYWdncmVnYXRlX3J1bl9hcGkvI2ZpbHRlcnMpIGFsbG93ZWQgaW4gdGhlIHVuZGVybHlpbmcgUnVuIEFQSS4pIFF1ZXJ5aW5nIGZvciB2YXJpYWJsZXMgaXMgYXZhaWxhYmxlIGZvciBydW5zIFtpbiBtZW1vcnldKC4uLy4uLy4uL3J1bl9wZXJzaXN0ZW5jZS8jcnVucy1pbi1tZW1vcnkpIGFuZCBmb3IgcnVucyBbaW4gdGhlIGRhdGFiYXNlXSguLi8uLi8uLi9ydW5fcGVyc2lzdGVuY2UvI3J1bnMtaW4tbWVtb3J5KSBpZiB0aGUgdmFyaWFibGVzIGFyZSBwZXJzaXN0ZWQgKGUuZy4gdGhhdCBoYXZlIGJlZW4gYHJlY29yZGBlZCBpbiB5b3VyIG1vZGVsIG9yIG1hcmtlZCBmb3Igc2F2aW5nIGluIHlvdXIgW21vZGVsIGNvbnRleHQgZmlsZV0oLi4vLi4vLi4vbW9kZWxfY29kZS9jb250ZXh0LykpLlxuICAgICAgICAgKiBAcGFyYW0ge09iamVjdH0gb3V0cHV0TW9kaWZpZXIgKE9wdGlvbmFsKSBBdmFpbGFibGUgZmllbGRzIGluY2x1ZGU6IGBzdGFydHJlY29yZGAsIGBlbmRyZWNvcmRgLCBgc29ydGAsIGFuZCBgZGlyZWN0aW9uYCAoYGFzY2Agb3IgYGRlc2NgKS5cbiAgICAgICAgICogQHBhcmFtIHtPYmplY3R9IG9wdGlvbnMgKE9wdGlvbmFsKSBPdmVycmlkZXMgZm9yIGNvbmZpZ3VyYXRpb24gb3B0aW9ucy5cbiAgICAgICAgICogQHJldHVybiB7UHJvbWlzZX1cbiAgICAgICAgICovXG4gICAgICAgIHF1ZXJ5OiBmdW5jdGlvbiAocXMsIG91dHB1dE1vZGlmaWVyLCBvcHRpb25zKSB7XG4gICAgICAgICAgICB2YXIgaHR0cE9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSwgc2VydmljZU9wdGlvbnMsIHsgdXJsOiB1cmxDb25maWcuZ2V0RmlsdGVyVVJMKHFzKSB9LCBvcHRpb25zKTtcbiAgICAgICAgICAgIGh0dHBPcHRpb25zID0gdXJsQ29uZmlnLmFkZEF1dG9SZXN0b3JlSGVhZGVyKGh0dHBPcHRpb25zKTtcblxuICAgICAgICAgICAgcmV0dXJuIGh0dHAuc3BsaXRHZXQob3V0cHV0TW9kaWZpZXIsIGh0dHBPcHRpb25zKS50aGVuKGZ1bmN0aW9uIChyKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuICgkLmlzUGxhaW5PYmplY3QocikgJiYgT2JqZWN0LmtleXMocikubGVuZ3RoID09PSAwKSA/IFtdIDogcjtcbiAgICAgICAgICAgIH0pO1xuICAgICAgICB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBSZXR1cm5zIHBhcnRpY3VsYXIgcnVucywgYmFzZWQgb24gY29uZGl0aW9ucyBzcGVjaWZpZWQgaW4gdGhlIGBxc2Agb2JqZWN0LlxuICAgICAgICAgKlxuICAgICAgICAgKiBTaW1pbGFyIHRvIGAucXVlcnkoKWAuXG4gICAgICAgICAqXG4gICAgICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICAgICAqIEBwYXJhbSB7T2JqZWN0fSBmaWx0ZXIgRmlsdGVyIG9iamVjdC4gRWFjaCBrZXkgY2FuIGJlIGEgcHJvcGVydHkgb2YgdGhlIHJ1biBvciB0aGUgbmFtZSBvZiB2YXJpYWJsZSB0aGF0IGhhcyBiZWVuIHNhdmVkIGluIHRoZSBydW4gKHByZWZhY2VkIGJ5IGB2YXJpYWJsZXMuYCkuIEVhY2ggdmFsdWUgY2FuIGJlIGEgbGl0ZXJhbCB2YWx1ZSwgb3IgYSBjb21wYXJpc29uIG9wZXJhdG9yIGFuZCB2YWx1ZS4gKFNlZSBbbW9yZSBvbiBmaWx0ZXJpbmddKC4uLy4uLy4uL3Jlc3RfYXBpcy9hZ2dyZWdhdGVfcnVuX2FwaS8jZmlsdGVycykgYWxsb3dlZCBpbiB0aGUgdW5kZXJseWluZyBSdW4gQVBJLikgRmlsdGVyaW5nIGZvciB2YXJpYWJsZXMgaXMgYXZhaWxhYmxlIGZvciBydW5zIFtpbiBtZW1vcnldKC4uLy4uLy4uL3J1bl9wZXJzaXN0ZW5jZS8jcnVucy1pbi1tZW1vcnkpIGFuZCBmb3IgcnVucyBbaW4gdGhlIGRhdGFiYXNlXSguLi8uLi8uLi9ydW5fcGVyc2lzdGVuY2UvI3J1bnMtaW4tbWVtb3J5KSBpZiB0aGUgdmFyaWFibGVzIGFyZSBwZXJzaXN0ZWQgKGUuZy4gdGhhdCBoYXZlIGJlZW4gYHJlY29yZGBlZCBpbiB5b3VyIG1vZGVsIG9yIG1hcmtlZCBmb3Igc2F2aW5nIGluIHlvdXIgW21vZGVsIGNvbnRleHQgZmlsZV0oLi4vLi4vLi4vbW9kZWxfY29kZS9jb250ZXh0LykpLlxuICAgICAgICAgKiBAcGFyYW0ge09iamVjdH0gb3V0cHV0TW9kaWZpZXIgKE9wdGlvbmFsKSBBdmFpbGFibGUgZmllbGRzIGluY2x1ZGU6IGBzdGFydHJlY29yZGAsIGBlbmRyZWNvcmRgLCBgc29ydGAsIGFuZCBgZGlyZWN0aW9uYCAoYGFzY2Agb3IgYGRlc2NgKS5cbiAgICAgICAgICogQHBhcmFtIHtPYmplY3R9IG9wdGlvbnMgKE9wdGlvbmFsKSBPdmVycmlkZXMgZm9yIGNvbmZpZ3VyYXRpb24gb3B0aW9ucy5cbiAgICAgICAgICogQHJldHVybiB7UHJvbWlzZX1cbiAgICAgICAgICovXG4gICAgICAgIGZpbHRlcjogZnVuY3Rpb24gKGZpbHRlciwgb3V0cHV0TW9kaWZpZXIsIG9wdGlvbnMpIHtcbiAgICAgICAgICAgIGlmICgkLmlzUGxhaW5PYmplY3Qoc2VydmljZU9wdGlvbnMuZmlsdGVyKSkge1xuICAgICAgICAgICAgICAgICQuZXh0ZW5kKHNlcnZpY2VPcHRpb25zLmZpbHRlciwgZmlsdGVyKTtcbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgc2VydmljZU9wdGlvbnMuZmlsdGVyID0gZmlsdGVyO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgdmFyIGh0dHBPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sIHNlcnZpY2VPcHRpb25zLCBvcHRpb25zKTtcbiAgICAgICAgICAgIGh0dHBPcHRpb25zID0gdXJsQ29uZmlnLmFkZEF1dG9SZXN0b3JlSGVhZGVyKGh0dHBPcHRpb25zKTtcbiAgICAgICAgICAgIHJldHVybiBodHRwLnNwbGl0R2V0KG91dHB1dE1vZGlmaWVyLCBodHRwT3B0aW9ucykudGhlbihmdW5jdGlvbiAocikge1xuICAgICAgICAgICAgICAgIHJldHVybiAoJC5pc1BsYWluT2JqZWN0KHIpICYmIE9iamVjdC5rZXlzKHIpLmxlbmd0aCA9PT0gMCkgPyBbXSA6IHI7XG4gICAgICAgICAgICB9KTtcbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgICogR2V0IGRhdGEgZm9yIGEgc3BlY2lmaWMgcnVuLiBUaGlzIGluY2x1ZGVzIHN0YW5kYXJkIHJ1biBkYXRhIHN1Y2ggYXMgdGhlIGFjY291bnQsIG1vZGVsLCBwcm9qZWN0LCBhbmQgY3JlYXRlZCBhbmQgbGFzdCBtb2RpZmllZCBkYXRlcy4gVG8gcmVxdWVzdCBzcGVjaWZpYyBtb2RlbCB2YXJpYWJsZXMgb3IgcnVuIHJlY29yZCB2YXJpYWJsZXMsIHBhc3MgdGhlbSBhcyBwYXJ0IG9mIHRoZSBgZmlsdGVyc2AgcGFyYW1ldGVyLlxuICAgICAgICAgKlxuICAgICAgICAgKiBOb3RlIHRoYXQgaWYgdGhlIHJ1biBpcyBbaW4gbWVtb3J5XSguLi8uLi8uLi9ydW5fcGVyc2lzdGVuY2UvI3J1bnMtaW4tbWVtb3J5KSwgYW55IG1vZGVsIHZhcmlhYmxlcyBhcmUgYXZhaWxhYmxlOyBpZiB0aGUgcnVuIGlzIFtpbiB0aGUgZGF0YWJhc2VdKC4uLy4uLy4uL3J1bl9wZXJzaXN0ZW5jZS8jcnVucy1pbi1kYiksIG9ubHkgbW9kZWwgdmFyaWFibGVzIHRoYXQgaGF2ZSBiZWVuIHBlcnNpc3RlZCAmbWRhc2g7IHRoYXQgaXMsIGByZWNvcmRgZWQgb3Igc2F2ZWQgaW4geW91ciBtb2RlbCAmbWRhc2g7IGFyZSBhdmFpbGFibGUuXG4gICAgICAgICAqXG4gICAgICAgICAqICoqRXhhbXBsZSoqXG4gICAgICAgICAqXG4gICAgICAgICAqICAgICBycy5sb2FkKCdiYjU4OTY3Ny1kNDc2LTQ5NzEtYTY4ZS0wYzU4ZDE5MWU0NTAnLCB7IGluY2x1ZGU6IFsnLnByaWNlJywgJy5zYWxlcyddIH0pO1xuICAgICAgICAgKlxuICAgICAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAgKiBAcGFyYW0ge1N0cmluZ30gcnVuSUQgVGhlIHJ1biBpZC5cbiAgICAgICAgICogQHBhcmFtIHtPYmplY3R9IGZpbHRlcnMgKE9wdGlvbmFsKSBPYmplY3QgY29udGFpbmluZyBmaWx0ZXJzIGFuZCBvcGVyYXRpb24gbW9kaWZpZXJzLiBVc2Uga2V5IGBpbmNsdWRlYCB0byBsaXN0IG1vZGVsIHZhcmlhYmxlcyB0aGF0IHlvdSB3YW50IHRvIGluY2x1ZGUgaW4gdGhlIHJlc3BvbnNlLiBPdGhlciBhdmFpbGFibGUgZmllbGRzIGluY2x1ZGU6IGBzdGFydHJlY29yZGAsIGBlbmRyZWNvcmRgLCBgc29ydGAsIGFuZCBgZGlyZWN0aW9uYCAoYGFzY2Agb3IgYGRlc2NgKS5cbiAgICAgICAgICogQHBhcmFtIHtPYmplY3R9IG9wdGlvbnMgKE9wdGlvbmFsKSBPdmVycmlkZXMgZm9yIGNvbmZpZ3VyYXRpb24gb3B0aW9ucy5cbiAgICAgICAgICogQHJldHVybiB7UHJvbWlzZX1cbiAgICAgICAgICovXG4gICAgICAgIGxvYWQ6IGZ1bmN0aW9uIChydW5JRCwgZmlsdGVycywgb3B0aW9ucykge1xuICAgICAgICAgICAgaWYgKHJ1bklEKSB7XG4gICAgICAgICAgICAgICAgc2VydmljZU9wdGlvbnMuZmlsdGVyID0gcnVuSUQ7IC8vc2hvdWxkbid0IGJlIGFibGUgdG8gb3Zlci1yaWRlXG4gICAgICAgICAgICB9XG4gICAgICAgICAgICB2YXIgaHR0cE9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSwgc2VydmljZU9wdGlvbnMsIG9wdGlvbnMpO1xuICAgICAgICAgICAgaHR0cE9wdGlvbnMgPSB1cmxDb25maWcuYWRkQXV0b1Jlc3RvcmVIZWFkZXIoaHR0cE9wdGlvbnMpO1xuICAgICAgICAgICAgcmV0dXJuIGh0dHAuZ2V0KGZpbHRlcnMsIGh0dHBPcHRpb25zKTtcbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgICogUmVtb3ZlcyBzcGVjaWZpZWQgcnVuaWQgZnJvbSBtZW1vcnlcbiAgICAgICAgICpcbiAgICAgICAgICogU2VlIFtkZXRhaWxzIG9uIHJ1biBwZXJzaXN0ZW5jZV0oLi4vLi4vLi4vcnVuX3BlcnNpc3RlbmNlLyNydW5zLWluLW1lbW9yeSlcbiAgICAgICAgICogQHBhcmFtICB7U3RyaW5nfSBbcnVuSURdICAgaWQgb2YgcnVuIHRvIHJlbW92ZVxuICAgICAgICAgKiBAcGFyYW0gIHtPYmplY3R9IFtmaWx0ZXJzXSAoT3B0aW9uYWwpIE9iamVjdCBjb250YWluaW5nIGZpbHRlcnMgYW5kIG9wZXJhdGlvbiBtb2RpZmllcnMuIFVzZSBrZXkgYGluY2x1ZGVgIHRvIGxpc3QgbW9kZWwgdmFyaWFibGVzIHRoYXQgeW91IHdhbnQgdG8gaW5jbHVkZSBpbiB0aGUgcmVzcG9uc2UuIE90aGVyIGF2YWlsYWJsZSBmaWVsZHMgaW5jbHVkZTogYHN0YXJ0cmVjb3JkYCwgYGVuZHJlY29yZGAsIGBzb3J0YCwgYW5kIGBkaXJlY3Rpb25gIChgYXNjYCBvciBgZGVzY2ApLlxuICAgICAgICAgKiBAcGFyYW0gIHtPYmplY3R9IFtvcHRpb25zXSAoT3B0aW9uYWwpIE92ZXJyaWRlcyBmb3IgY29uZmlndXJhdGlvbiBvcHRpb25zLlxuICAgICAgICAgKiBAcmV0dXJuIHtQcm9taXNlfVxuICAgICAgICAgKi9cbiAgICAgICAgcmVtb3ZlRnJvbU1lbW9yeTogZnVuY3Rpb24gKHJ1bklELCBmaWx0ZXJzLCBvcHRpb25zKSB7XG4gICAgICAgICAgICB2YXIgaHR0cE9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSwgc2VydmljZU9wdGlvbnMsIG9wdGlvbnMpO1xuICAgICAgICAgICAgaWYgKHJ1bklEKSB7XG4gICAgICAgICAgICAgICAgaHR0cE9wdGlvbnMudXJsID0gdXJsQ29uZmlnLmdldEFQSVBhdGgoJ3J1bicpICsgcnVuSUQ7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICByZXR1cm4gaHR0cC5kZWxldGUoe30sIGh0dHBPcHRpb25zKTtcbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgICogU2F2ZSBhdHRyaWJ1dGVzIChkYXRhLCBtb2RlbCB2YXJpYWJsZXMpIG9mIHRoZSBydW4uXG4gICAgICAgICAqXG4gICAgICAgICAqICoqRXhhbXBsZXMqKlxuICAgICAgICAgKlxuICAgICAgICAgKiAgICAgLy8gYWRkICdjb21wbGV0ZWQnIGZpZWxkIHRvIHJ1biByZWNvcmRcbiAgICAgICAgICogICAgIHJzLnNhdmUoeyBjb21wbGV0ZWQ6IHRydWUgfSk7XG4gICAgICAgICAqXG4gICAgICAgICAqICAgICAvLyB1cGRhdGUgJ3NhdmVkJyBmaWVsZCBvZiBydW4gcmVjb3JkLCBhbmQgdXBkYXRlIHZhbHVlcyBvZiBtb2RlbCB2YXJpYWJsZXMgZm9yIHRoaXMgcnVuXG4gICAgICAgICAqICAgICBycy5zYXZlKHsgc2F2ZWQ6IHRydWUsIHZhcmlhYmxlczogeyBhOiAyMywgYjogMjMgfSB9KTtcbiAgICAgICAgICpcbiAgICAgICAgICogICAgIC8vIHVwZGF0ZSAnc2F2ZWQnIGZpZWxkIG9mIHJ1biByZWNvcmQgZm9yIGEgcGFydGljdWxhciBydW5cbiAgICAgICAgICogICAgIHJzLnNhdmUoeyBzYXZlZDogdHJ1ZSB9LCB7IGlkOiAnMDAwMDAxNWJmMmEwNDk5NTg4MGRmNmI4NjhkMjNlYjNkMjI5JyB9KTtcbiAgICAgICAgICpcbiAgICAgICAgICogKipQYXJhbWV0ZXJzKipcbiAgICAgICAgICogQHBhcmFtIHtPYmplY3R9IGF0dHJpYnV0ZXMgVGhlIHJ1biBkYXRhIGFuZCB2YXJpYWJsZXMgdG8gc2F2ZS5cbiAgICAgICAgICogQHBhcmFtIHtPYmplY3R9IGF0dHJpYnV0ZXMudmFyaWFibGVzIE1vZGVsIHZhcmlhYmxlcyBtdXN0IGJlIGluY2x1ZGVkIGluIGEgYHZhcmlhYmxlc2AgZmllbGQgd2l0aGluIHRoZSBgYXR0cmlidXRlc2Agb2JqZWN0LiAoT3RoZXJ3aXNlIHRoZXkgYXJlIHRyZWF0ZWQgYXMgcnVuIGRhdGEgYW5kIGFkZGVkIHRvIHRoZSBydW4gcmVjb3JkIGRpcmVjdGx5LilcbiAgICAgICAgICogQHBhcmFtIHtPYmplY3R9IG9wdGlvbnMgKE9wdGlvbmFsKSBPdmVycmlkZXMgZm9yIGNvbmZpZ3VyYXRpb24gb3B0aW9ucy5cbiAgICAgICAgICogQHJldHVybiB7UHJvbWlzZX1cbiAgICAgICAgICovXG4gICAgICAgIHNhdmU6IGZ1bmN0aW9uIChhdHRyaWJ1dGVzLCBvcHRpb25zKSB7XG4gICAgICAgICAgICB2YXIgaHR0cE9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSwgc2VydmljZU9wdGlvbnMsIG9wdGlvbnMpO1xuICAgICAgICAgICAgc2V0RmlsdGVyT3JUaHJvd0Vycm9yKGh0dHBPcHRpb25zKTtcbiAgICAgICAgICAgIHJldHVybiBodHRwLnBhdGNoKGF0dHJpYnV0ZXMsIGh0dHBPcHRpb25zKTtcbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgICogQ2FsbCBhbiBvcGVyYXRpb24gZnJvbSB0aGUgbW9kZWwuXG4gICAgICAgICAqXG4gICAgICAgICAqIERlcGVuZGluZyBvbiB0aGUgbGFuZ3VhZ2UgaW4gd2hpY2ggeW91IGhhdmUgd3JpdHRlbiB5b3VyIG1vZGVsLCB0aGUgb3BlcmF0aW9uIChmdW5jdGlvbiBvciBtZXRob2QpIG1heSBuZWVkIHRvIGJlIGV4cG9zZWQgKGUuZy4gYGV4cG9ydGAgZm9yIGEgSnVsaWEgbW9kZWwpIGluIHRoZSBtb2RlbCBmaWxlIGluIG9yZGVyIHRvIGJlIGNhbGxlZCB0aHJvdWdoIHRoZSBBUEkuIFNlZSBbV3JpdGluZyB5b3VyIE1vZGVsXSguLi8uLi8uLi93cml0aW5nX3lvdXJfbW9kZWwvKSkuXG4gICAgICAgICAqXG4gICAgICAgICAqIFRoZSBgcGFyYW1zYCBhcmd1bWVudCBpcyBub3JtYWxseSBhbiBhcnJheSBvZiBhcmd1bWVudHMgdG8gdGhlIGBvcGVyYXRpb25gLiBJbiB0aGUgc3BlY2lhbCBjYXNlIHdoZXJlIGBvcGVyYXRpb25gIG9ubHkgdGFrZXMgb25lIGFyZ3VtZW50LCB5b3UgYXJlIG5vdCByZXF1aXJlZCB0byBwdXQgdGhhdCBhcmd1bWVudCBpbnRvIGFuIGFycmF5LlxuICAgICAgICAgKlxuICAgICAgICAgKiBOb3RlIHRoYXQgeW91IGNhbiBjb21iaW5lIHRoZSBgb3BlcmF0aW9uYCBhbmQgYHBhcmFtc2AgYXJndW1lbnRzIGludG8gYSBzaW5nbGUgb2JqZWN0IGlmIHlvdSBwcmVmZXIsIGFzIGluIHRoZSBsYXN0IGV4YW1wbGUuXG4gICAgICAgICAqXG4gICAgICAgICAqICoqRXhhbXBsZXMqKlxuICAgICAgICAgKlxuICAgICAgICAgKiAgICAgIC8vIG9wZXJhdGlvbiBcInNvbHZlXCIgdGFrZXMgbm8gYXJndW1lbnRzXG4gICAgICAgICAqICAgICBycy5kbygnc29sdmUnKTtcbiAgICAgICAgICogICAgICAvLyBvcGVyYXRpb24gXCJlY2hvXCIgdGFrZXMgb25lIGFyZ3VtZW50LCBhIHN0cmluZ1xuICAgICAgICAgKiAgICAgcnMuZG8oJ2VjaG8nLCBbJ2hlbGxvJ10pO1xuICAgICAgICAgKiAgICAgIC8vIG9wZXJhdGlvbiBcImVjaG9cIiB0YWtlcyBvbmUgYXJndW1lbnQsIGEgc3RyaW5nXG4gICAgICAgICAqICAgICBycy5kbygnZWNobycsICdoZWxsbycpO1xuICAgICAgICAgKiAgICAgIC8vIG9wZXJhdGlvbiBcInN1bUFycmF5XCIgdGFrZXMgb25lIGFyZ3VtZW50LCBhbiBhcnJheVxuICAgICAgICAgKiAgICAgcnMuZG8oJ3N1bUFycmF5JywgW1s0LDIsMV1dKTtcbiAgICAgICAgICogICAgICAvLyBvcGVyYXRpb24gXCJhZGRcIiB0YWtlcyB0d28gYXJndW1lbnRzLCBib3RoIGludGVnZXJzXG4gICAgICAgICAqICAgICBycy5kbyh7IG5hbWU6J2FkZCcsIHBhcmFtczpbMiw0XSB9KTtcbiAgICAgICAgICogICAgICAvLyBjYWxsIG9wZXJhdGlvbiBcInNvbHZlXCIgb24gYSBkaWZmZXJlbnQgcnVuIFxuICAgICAgICAgKiAgICAgcnMuZG8oJ3NvbHZlJywgeyBpZDogJzAwMDAwMTViZjJhMDQ5OTU4ODBkZjZiODY4ZDIzZWIzZDIyOScgfSk7XG4gICAgICAgICAqXG4gICAgICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICAgICAqIEBwYXJhbSB7U3RyaW5nfSBvcGVyYXRpb24gTmFtZSBvZiBvcGVyYXRpb24uXG4gICAgICAgICAqIEBwYXJhbSB7QXJyYXl9IHBhcmFtcyAoT3B0aW9uYWwpIEFueSBwYXJhbWV0ZXJzIHRoZSBvcGVyYXRpb24gdGFrZXMsIHBhc3NlZCBhcyBhbiBhcnJheS4gSW4gdGhlIHNwZWNpYWwgY2FzZSB3aGVyZSBgb3BlcmF0aW9uYCBvbmx5IHRha2VzIG9uZSBhcmd1bWVudCwgeW91IGFyZSBub3QgcmVxdWlyZWQgdG8gcHV0IHRoYXQgYXJndW1lbnQgaW50byBhbiBhcnJheSwgYW5kIGNhbiBqdXN0IHBhc3MgaXQgZGlyZWN0bHkuXG4gICAgICAgICAqIEBwYXJhbSB7T2JqZWN0fSBvcHRpb25zIChPcHRpb25hbCkgT3ZlcnJpZGVzIGZvciBjb25maWd1cmF0aW9uIG9wdGlvbnMuXG4gICAgICAgICAqIEByZXR1cm4ge1Byb21pc2V9XG4gICAgICAgICAqL1xuICAgICAgICBkbzogZnVuY3Rpb24gKG9wZXJhdGlvbiwgcGFyYW1zLCBvcHRpb25zKSB7XG4gICAgICAgICAgICAvLyBjb25zb2xlLmxvZygnZG8nLCBvcGVyYXRpb24sIHBhcmFtcyk7XG4gICAgICAgICAgICB2YXIgb3BzQXJncztcbiAgICAgICAgICAgIHZhciBwb3N0T3B0aW9ucztcbiAgICAgICAgICAgIGlmIChvcHRpb25zKSB7XG4gICAgICAgICAgICAgICAgb3BzQXJncyA9IHBhcmFtcztcbiAgICAgICAgICAgICAgICBwb3N0T3B0aW9ucyA9IG9wdGlvbnM7XG4gICAgICAgICAgICB9IGVsc2UgaWYgKCQuaXNQbGFpbk9iamVjdChwYXJhbXMpKSB7XG4gICAgICAgICAgICAgICAgb3BzQXJncyA9IG51bGw7XG4gICAgICAgICAgICAgICAgcG9zdE9wdGlvbnMgPSBwYXJhbXM7XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgIG9wc0FyZ3MgPSBwYXJhbXM7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICB2YXIgcmVzdWx0ID0gcnV0aWwubm9ybWFsaXplT3BlcmF0aW9ucyhvcGVyYXRpb24sIG9wc0FyZ3MpO1xuICAgICAgICAgICAgdmFyIGh0dHBPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sIHNlcnZpY2VPcHRpb25zLCBwb3N0T3B0aW9ucyk7XG5cbiAgICAgICAgICAgIHNldEZpbHRlck9yVGhyb3dFcnJvcihodHRwT3B0aW9ucyk7XG5cbiAgICAgICAgICAgIHZhciBwcm1zID0gKHJlc3VsdC5hcmdzWzBdLmxlbmd0aCAmJiAocmVzdWx0LmFyZ3NbMF0gIT09IG51bGwgJiYgcmVzdWx0LmFyZ3NbMF0gIT09IHVuZGVmaW5lZCkpID8gcmVzdWx0LmFyZ3NbMF0gOiBbXTtcbiAgICAgICAgICAgIHJldHVybiBodHRwLnBvc3QoeyBhcmd1bWVudHM6IHBybXMgfSwgJC5leHRlbmQodHJ1ZSwge30sIGh0dHBPcHRpb25zLCB7XG4gICAgICAgICAgICAgICAgdXJsOiB1cmxDb25maWcuZ2V0RmlsdGVyVVJMKCkgKyAnb3BlcmF0aW9ucy8nICsgcmVzdWx0Lm9wc1swXSArICcvJ1xuICAgICAgICAgICAgfSkpO1xuICAgICAgICB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBDYWxsIHNldmVyYWwgb3BlcmF0aW9ucyBmcm9tIHRoZSBtb2RlbCwgc2VxdWVudGlhbGx5LlxuICAgICAgICAgKlxuICAgICAgICAgKiBEZXBlbmRpbmcgb24gdGhlIGxhbmd1YWdlIGluIHdoaWNoIHlvdSBoYXZlIHdyaXR0ZW4geW91ciBtb2RlbCwgdGhlIG9wZXJhdGlvbiAoZnVuY3Rpb24gb3IgbWV0aG9kKSBtYXkgbmVlZCB0byBiZSBleHBvc2VkIChlLmcuIGBleHBvcnRgIGZvciBhIEp1bGlhIG1vZGVsKSBpbiB0aGUgbW9kZWwgZmlsZSBpbiBvcmRlciB0byBiZSBjYWxsZWQgdGhyb3VnaCB0aGUgQVBJLiBTZWUgW1dyaXRpbmcgeW91ciBNb2RlbF0oLi4vLi4vLi4vd3JpdGluZ195b3VyX21vZGVsLykpLlxuICAgICAgICAgKlxuICAgICAgICAgKiAqKkV4YW1wbGVzKipcbiAgICAgICAgICpcbiAgICAgICAgICogICAgICAvLyBvcGVyYXRpb25zIFwiaW5pdGlhbGl6ZVwiIGFuZCBcInNvbHZlXCIgZG8gbm90IHRha2UgYW55IGFyZ3VtZW50c1xuICAgICAgICAgKiAgICAgcnMuc2VyaWFsKFsnaW5pdGlhbGl6ZScsICdzb2x2ZSddKTtcbiAgICAgICAgICogICAgICAvLyBvcGVyYXRpb25zIFwiaW5pdFwiIGFuZCBcInJlc2V0XCIgdGFrZSB0d28gYXJndW1lbnRzIGVhY2hcbiAgICAgICAgICogICAgIHJzLnNlcmlhbChbICB7IG5hbWU6ICdpbml0JywgcGFyYW1zOiBbMSwyXSB9LFxuICAgICAgICAgKiAgICAgICAgICAgICAgICAgIHsgbmFtZTogJ3Jlc2V0JywgcGFyYW1zOiBbMiwzXSB9XSk7XG4gICAgICAgICAqICAgICAgLy8gb3BlcmF0aW9uIFwiaW5pdFwiIHRha2VzIHR3byBhcmd1bWVudHMsXG4gICAgICAgICAqICAgICAgLy8gb3BlcmF0aW9uIFwicnVubW9kZWxcIiB0YWtlcyBub25lXG4gICAgICAgICAqICAgICBycy5zZXJpYWwoWyAgeyBuYW1lOiAnaW5pdCcsIHBhcmFtczogWzEsMl0gfSxcbiAgICAgICAgICogICAgICAgICAgICAgICAgICB7IG5hbWU6ICdydW5tb2RlbCcsIHBhcmFtczogW10gfV0pO1xuICAgICAgICAgKlxuICAgICAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAgKiBAcGFyYW0ge0FycmF5fSBvcGVyYXRpb25zIElmIG5vbmUgb2YgdGhlIG9wZXJhdGlvbnMgdGFrZSBwYXJhbWV0ZXJzLCBwYXNzIGFuIGFycmF5IG9mIHRoZSBvcGVyYXRpb24gbmFtZXMgKHN0cmluZ3MpLiBJZiBhbnkgb2YgdGhlIG9wZXJhdGlvbnMgZG8gdGFrZSBwYXJhbWV0ZXJzLCBwYXNzIGFuIGFycmF5IG9mIG9iamVjdHMsIGVhY2ggb2Ygd2hpY2ggY29udGFpbnMgYW4gb3BlcmF0aW9uIG5hbWUgYW5kIGl0cyBvd24gKHBvc3NpYmx5IGVtcHR5KSBhcnJheSBvZiBwYXJhbWV0ZXJzLlxuICAgICAgICAgKiBAcGFyYW0geyp9IHBhcmFtcyBQYXJhbWV0ZXJzIHRvIHBhc3MgdG8gb3BlcmF0aW9ucy5cbiAgICAgICAgICogQHBhcmFtIHtPYmplY3R9IG9wdGlvbnMgKE9wdGlvbmFsKSBPdmVycmlkZXMgZm9yIGNvbmZpZ3VyYXRpb24gb3B0aW9ucy5cbiAgICAgICAgICogQHJldHVybiB7UHJvbWlzZX0gVGhlIHBhcmFtZXRlciB0byB0aGUgY2FsbGJhY2sgaXMgYW4gYXJyYXkuIEVhY2ggYXJyYXkgZWxlbWVudCBpcyBhbiBvYmplY3QgY29udGFpbmluZyB0aGUgcmVzdWx0cyBvZiBvbmUgb3BlcmF0aW9uLlxuICAgICAgICAgKi9cbiAgICAgICAgc2VyaWFsOiBmdW5jdGlvbiAob3BlcmF0aW9ucywgcGFyYW1zLCBvcHRpb25zKSB7XG4gICAgICAgICAgICB2YXIgb3BQYXJhbXMgPSBydXRpbC5ub3JtYWxpemVPcGVyYXRpb25zKG9wZXJhdGlvbnMsIHBhcmFtcyk7XG4gICAgICAgICAgICB2YXIgb3BzID0gb3BQYXJhbXMub3BzO1xuICAgICAgICAgICAgdmFyIGFyZ3MgPSBvcFBhcmFtcy5hcmdzO1xuICAgICAgICAgICAgdmFyIG1lID0gdGhpcztcblxuICAgICAgICAgICAgdmFyICRkID0gJC5EZWZlcnJlZCgpO1xuICAgICAgICAgICAgdmFyIHBvc3RPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sIHNlcnZpY2VPcHRpb25zLCBvcHRpb25zKTtcblxuICAgICAgICAgICAgdmFyIHJlc3BvbnNlcyA9IFtdO1xuICAgICAgICAgICAgdmFyIGRvU2luZ2xlT3AgPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICAgICAgdmFyIG9wID0gb3BzLnNoaWZ0KCk7XG4gICAgICAgICAgICAgICAgdmFyIGFyZyA9IGFyZ3Muc2hpZnQoKTtcblxuICAgICAgICAgICAgICAgIG1lLmRvKG9wLCBhcmcsIHtcbiAgICAgICAgICAgICAgICAgICAgc3VjY2VzczogZnVuY3Rpb24gKHJlc3VsdCkge1xuICAgICAgICAgICAgICAgICAgICAgICAgcmVzcG9uc2VzLnB1c2gocmVzdWx0KTtcbiAgICAgICAgICAgICAgICAgICAgICAgIGlmIChvcHMubGVuZ3RoKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgZG9TaW5nbGVPcCgpO1xuICAgICAgICAgICAgICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAkZC5yZXNvbHZlKHJlc3BvbnNlcyk7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgcG9zdE9wdGlvbnMuc3VjY2VzcyhyZXNwb25zZXMsIG1lKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgICAgICAgICAgZXJyb3I6IGZ1bmN0aW9uIChlcnIpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHJlc3BvbnNlcy5wdXNoKGVycik7XG4gICAgICAgICAgICAgICAgICAgICAgICAkZC5yZWplY3QocmVzcG9uc2VzKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIHBvc3RPcHRpb25zLmVycm9yKHJlc3BvbnNlcywgbWUpO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICB9O1xuXG4gICAgICAgICAgICBkb1NpbmdsZU9wKCk7XG5cbiAgICAgICAgICAgIHJldHVybiAkZC5wcm9taXNlKCk7XG4gICAgICAgIH0sXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIENhbGwgc2V2ZXJhbCBvcGVyYXRpb25zIGZyb20gdGhlIG1vZGVsLCBleGVjdXRpbmcgdGhlbSBpbiBwYXJhbGxlbC5cbiAgICAgICAgICpcbiAgICAgICAgICogRGVwZW5kaW5nIG9uIHRoZSBsYW5ndWFnZSBpbiB3aGljaCB5b3UgaGF2ZSB3cml0dGVuIHlvdXIgbW9kZWwsIHRoZSBvcGVyYXRpb24gKGZ1bmN0aW9uIG9yIG1ldGhvZCkgbWF5IG5lZWQgdG8gYmUgZXhwb3NlZCAoZS5nLiBgZXhwb3J0YCBmb3IgYSBKdWxpYSBtb2RlbCkgaW4gdGhlIG1vZGVsIGZpbGUgaW4gb3JkZXIgdG8gYmUgY2FsbGVkIHRocm91Z2ggdGhlIEFQSS4gU2VlIFtXcml0aW5nIHlvdXIgTW9kZWxdKC4uLy4uLy4uL3dyaXRpbmdfeW91cl9tb2RlbC8pKS5cbiAgICAgICAgICpcbiAgICAgICAgICogKipFeGFtcGxlKipcbiAgICAgICAgICpcbiAgICAgICAgICogICAgICAvLyBvcGVyYXRpb25zIFwic29sdmVcIiBhbmQgXCJyZXNldFwiIGRvIG5vdCB0YWtlIGFueSBhcmd1bWVudHNcbiAgICAgICAgICogICAgIHJzLnBhcmFsbGVsKFsnc29sdmUnLCAncmVzZXQnXSk7XG4gICAgICAgICAqICAgICAgLy8gb3BlcmF0aW9ucyBcImFkZFwiIGFuZCBcInN1YnRyYWN0XCIgdGFrZSB0d28gYXJndW1lbnRzIGVhY2hcbiAgICAgICAgICogICAgIHJzLnBhcmFsbGVsKFsgeyBuYW1lOiAnYWRkJywgcGFyYW1zOiBbMSwyXSB9LFxuICAgICAgICAgKiAgICAgICAgICAgICAgICAgICB7IG5hbWU6ICdzdWJ0cmFjdCcsIHBhcmFtczpbMiwzXSB9XSk7XG4gICAgICAgICAqICAgICAgLy8gb3BlcmF0aW9ucyBcImFkZFwiIGFuZCBcInN1YnRyYWN0XCIgdGFrZSB0d28gYXJndW1lbnRzIGVhY2hcbiAgICAgICAgICogICAgIHJzLnBhcmFsbGVsKHsgYWRkOiBbMSwyXSwgc3VidHJhY3Q6IFsyLDRdIH0pO1xuICAgICAgICAgKlxuICAgICAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAgKiBAcGFyYW0ge0FycmF5fE9iamVjdH0gb3BlcmF0aW9ucyBJZiBub25lIG9mIHRoZSBvcGVyYXRpb25zIHRha2UgcGFyYW1ldGVycywgcGFzcyBhbiBhcnJheSBvZiB0aGUgb3BlcmF0aW9uIG5hbWVzIChhcyBzdHJpbmdzKS4gSWYgYW55IG9mIHRoZSBvcGVyYXRpb25zIGRvIHRha2UgcGFyYW1ldGVycywgeW91IGhhdmUgdHdvIG9wdGlvbnMuIFlvdSBjYW4gcGFzcyBhbiBhcnJheSBvZiBvYmplY3RzLCBlYWNoIG9mIHdoaWNoIGNvbnRhaW5zIGFuIG9wZXJhdGlvbiBuYW1lIGFuZCBpdHMgb3duIChwb3NzaWJseSBlbXB0eSkgYXJyYXkgb2YgcGFyYW1ldGVycy4gQWx0ZXJuYXRpdmVseSwgeW91IGNhbiBwYXNzIGEgc2luZ2xlIG9iamVjdCB3aXRoIHRoZSBvcGVyYXRpb24gbmFtZSBhbmQgYSAocG9zc2libHkgZW1wdHkpIGFycmF5IG9mIHBhcmFtZXRlcnMuXG4gICAgICAgICAqIEBwYXJhbSB7Kn0gcGFyYW1zIFBhcmFtZXRlcnMgdG8gcGFzcyB0byBvcGVyYXRpb25zLlxuICAgICAgICAgKiBAcGFyYW0ge09iamVjdH0gb3B0aW9ucyAoT3B0aW9uYWwpIE92ZXJyaWRlcyBmb3IgY29uZmlndXJhdGlvbiBvcHRpb25zLlxuICAgICAgICAgKiBAcmV0dXJuIHtQcm9taXNlfSBUaGUgcGFyYW1ldGVyIHRvIHRoZSBjYWxsYmFjayBpcyBhbiBhcnJheS4gRWFjaCBhcnJheSBlbGVtZW50IGlzIGFuIG9iamVjdCBjb250YWluaW5nIHRoZSByZXN1bHRzIG9mIG9uZSBvcGVyYXRpb24uXG4gICAgICAgICAqL1xuICAgICAgICBwYXJhbGxlbDogZnVuY3Rpb24gKG9wZXJhdGlvbnMsIHBhcmFtcywgb3B0aW9ucykge1xuICAgICAgICAgICAgdmFyICRkID0gJC5EZWZlcnJlZCgpO1xuXG4gICAgICAgICAgICB2YXIgb3BQYXJhbXMgPSBydXRpbC5ub3JtYWxpemVPcGVyYXRpb25zKG9wZXJhdGlvbnMsIHBhcmFtcyk7XG4gICAgICAgICAgICB2YXIgb3BzID0gb3BQYXJhbXMub3BzO1xuICAgICAgICAgICAgdmFyIGFyZ3MgPSBvcFBhcmFtcy5hcmdzO1xuICAgICAgICAgICAgdmFyIHBvc3RPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sIHNlcnZpY2VPcHRpb25zLCBvcHRpb25zKTtcblxuICAgICAgICAgICAgdmFyIHF1ZXVlID0gW107XG4gICAgICAgICAgICBmb3IgKHZhciBpID0gMDsgaSA8IG9wcy5sZW5ndGg7IGkrKykge1xuICAgICAgICAgICAgICAgIHF1ZXVlLnB1c2goXG4gICAgICAgICAgICAgICAgICAgIHRoaXMuZG8ob3BzW2ldLCBhcmdzW2ldKVxuICAgICAgICAgICAgICAgICk7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIHZhciBtZSA9IHRoaXM7XG4gICAgICAgICAgICAkLndoZW4uYXBwbHkodGhpcywgcXVldWUpXG4gICAgICAgICAgICAgICAgLnRoZW4oZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgICAgICAgICB2YXIgYXJncyA9IEFycmF5LnByb3RvdHlwZS5zbGljZS5jYWxsKGFyZ3VtZW50cyk7XG4gICAgICAgICAgICAgICAgICAgIHZhciBhY3R1YWxSZXNwb25zZSA9IGFyZ3MubWFwKGZ1bmN0aW9uIChhKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICByZXR1cm4gYVswXTtcbiAgICAgICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgICAgICAgICRkLnJlc29sdmUoYWN0dWFsUmVzcG9uc2UpO1xuICAgICAgICAgICAgICAgICAgICBwb3N0T3B0aW9ucy5zdWNjZXNzKGFjdHVhbFJlc3BvbnNlLCBtZSk7XG4gICAgICAgICAgICAgICAgfSlcbiAgICAgICAgICAgICAgICAuZmFpbChmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICAgICAgICAgIHZhciBhcmdzID0gQXJyYXkucHJvdG90eXBlLnNsaWNlLmNhbGwoYXJndW1lbnRzKTtcbiAgICAgICAgICAgICAgICAgICAgdmFyIGFjdHVhbFJlc3BvbnNlID0gYXJncy5tYXAoZnVuY3Rpb24gKGEpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybiBhWzBdO1xuICAgICAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgICAgICAgJGQucmVqZWN0KGFjdHVhbFJlc3BvbnNlKTtcbiAgICAgICAgICAgICAgICAgICAgcG9zdE9wdGlvbnMuZXJyb3IoYWN0dWFsUmVzcG9uc2UsIG1lKTtcbiAgICAgICAgICAgICAgICB9KTtcblxuICAgICAgICAgICAgcmV0dXJuICRkLnByb21pc2UoKTtcbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgICogU2hvcnRjdXQgdG8gdXNpbmcgdGhlIFtJbnRyb3NwZWN0aW9uIEFQSSBTZXJ2aWNlXSguLi9pbnRyb3NwZWN0aW9uLWFwaS1zZXJ2aWNlLykuIEFsbG93cyB5b3UgdG8gdmlldyBhIGxpc3Qgb2YgdGhlIHZhcmlhYmxlcyBhbmQgb3BlcmF0aW9ucyBpbiBhIG1vZGVsLlxuICAgICAgICAgKlxuICAgICAgICAgKiAqKkV4YW1wbGUqKlxuICAgICAgICAgKlxuICAgICAgICAgKiAgICAgcnMuaW50cm9zcGVjdCh7IHJ1bklEOiAnY2JmODU0MzctYjUzOS00OTc3LWExZmMtMjM1MTVjZjA3MWJiJyB9KS50aGVuKGZ1bmN0aW9uIChkYXRhKSB7XG4gICAgICAgICAqICAgICAgICAgIGNvbnNvbGUubG9nKGRhdGEuZnVuY3Rpb25zKTtcbiAgICAgICAgICogICAgICAgICAgY29uc29sZS5sb2coZGF0YS52YXJpYWJsZXMpO1xuICAgICAgICAgKiAgICAgfSk7XG4gICAgICAgICAqXG4gICAgICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICAgICAqIEBwYXJhbSAge09iamVjdH0gb3B0aW9ucyBPcHRpb25zIGNhbiBlaXRoZXIgYmUgb2YgdGhlIGZvcm0gYHsgcnVuSUQ6IDxydW5pZD4gfWAgb3IgYHsgbW9kZWw6IDxtb2RlbEZpbGVOYW1lPiB9YC4gTm90ZSB0aGF0IHRoZSBgcnVuSURgIGlzIG9wdGlvbmFsIGlmIHRoZSBSdW4gU2VydmljZSBpcyBhbHJlYWR5IGFzc29jaWF0ZWQgd2l0aCBhIHBhcnRpY3VsYXIgcnVuIChiZWNhdXNlIGBpZGAgd2FzIHBhc3NlZCBpbiB3aGVuIHRoZSBSdW4gU2VydmljZSB3YXMgaW5pdGlhbGl6ZWQpLiBJZiBwcm92aWRlZCwgdGhlIGBydW5JRGAgb3ZlcnJpZGVzIHRoZSBgaWRgIGN1cnJlbnRseSBhc3NvY2lhdGVkIHdpdGggdGhlIFJ1biBTZXJ2aWNlLlxuICAgICAgICAgKiBAcGFyYW0gIHtPYmplY3R9IGludHJvc3BlY3Rpb25Db25maWcgKE9wdGlvbmFsKSBTZXJ2aWNlIG9wdGlvbnMgZm9yIEludHJvc3BlY3Rpb24gU2VydmljZVxuICAgICAgICAgKiBAcmV0dXJuIHtQcm9taXNlfVxuICAgICAgICAgKi9cbiAgICAgICAgaW50cm9zcGVjdDogZnVuY3Rpb24gKG9wdGlvbnMsIGludHJvc3BlY3Rpb25Db25maWcpIHtcbiAgICAgICAgICAgIHZhciBpbnRyb3NwZWN0aW9uID0gbmV3IEludHJvc3BlY3Rpb25TZXJ2aWNlKCQuZXh0ZW5kKHRydWUsIHt9LCBzZXJ2aWNlT3B0aW9ucywgaW50cm9zcGVjdGlvbkNvbmZpZykpO1xuICAgICAgICAgICAgaWYgKG9wdGlvbnMpIHtcbiAgICAgICAgICAgICAgICBpZiAob3B0aW9ucy5ydW5JRCkge1xuICAgICAgICAgICAgICAgICAgICByZXR1cm4gaW50cm9zcGVjdGlvbi5ieVJ1bklEKG9wdGlvbnMucnVuSUQpO1xuICAgICAgICAgICAgICAgIH0gZWxzZSBpZiAob3B0aW9ucy5tb2RlbCkge1xuICAgICAgICAgICAgICAgICAgICByZXR1cm4gaW50cm9zcGVjdGlvbi5ieU1vZGVsKG9wdGlvbnMubW9kZWwpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH0gZWxzZSBpZiAoc2VydmljZU9wdGlvbnMuaWQpIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gaW50cm9zcGVjdGlvbi5ieVJ1bklEKHNlcnZpY2VPcHRpb25zLmlkKTtcbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdQbGVhc2Ugc3BlY2lmeSBlaXRoZXIgdGhlIG1vZGVsIG9yIHJ1bmlkIHRvIGludHJvc3BlY3QnKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgIH07XG5cbiAgICB2YXIgcHVibGljU3luY0FQSSA9IHtcbiAgICAgICAgZ2V0Q3VycmVudENvbmZpZzogZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgcmV0dXJuIHNlcnZpY2VPcHRpb25zO1xuICAgICAgICB9LFxuICAgICAgICB1cGRhdGVDb25maWc6IGZ1bmN0aW9uIChjb25maWcpIHtcbiAgICAgICAgICAgIGlmIChjb25maWcgJiYgY29uZmlnLmlkKSB7XG4gICAgICAgICAgICAgICAgY29uZmlnLmZpbHRlciA9IGNvbmZpZy5pZDtcbiAgICAgICAgICAgIH0gZWxzZSBpZiAoY29uZmlnICYmIGNvbmZpZy5maWx0ZXIpIHtcbiAgICAgICAgICAgICAgICBjb25maWcuaWQgPSBjb25maWcuZmlsdGVyO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgc2VydmljZU9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSwgc2VydmljZU9wdGlvbnMsIGNvbmZpZyk7XG4gICAgICAgICAgICB1cmxDb25maWcgPSB1cGRhdGVVUkxDb25maWcoc2VydmljZU9wdGlvbnMpO1xuICAgICAgICAgICAgdGhpcy51cmxDb25maWcgPSB1cmxDb25maWc7XG4gICAgICAgICAgICB1cGRhdGVIVFRQQ29uZmlnKHNlcnZpY2VPcHRpb25zLCB1cmxDb25maWcpO1xuICAgICAgICB9LFxuICAgICAgICAvKipcbiAgICAgICAgICAqIFJldHVybnMgYSBWYXJpYWJsZXMgU2VydmljZSBpbnN0YW5jZS4gVXNlIHRoZSB2YXJpYWJsZXMgaW5zdGFuY2UgdG8gbG9hZCwgc2F2ZSwgYW5kIHF1ZXJ5IGZvciBzcGVjaWZpYyBtb2RlbCB2YXJpYWJsZXMuIFNlZSB0aGUgW1ZhcmlhYmxlIEFQSSBTZXJ2aWNlXSguLi92YXJpYWJsZXMtYXBpLXNlcnZpY2UvKSBmb3IgbW9yZSBpbmZvcm1hdGlvbi5cbiAgICAgICAgICAqXG4gICAgICAgICAgKiAqKkV4YW1wbGUqKlxuICAgICAgICAgICpcbiAgICAgICAgICAqICAgICAgdmFyIHZzID0gcnMudmFyaWFibGVzKCk7XG4gICAgICAgICAgKiAgICAgIHZzLnNhdmUoeyBzYW1wbGVfaW50OiA0IH0pO1xuICAgICAgICAgICpcbiAgICAgICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICAgICAgKiBAcGFyYW0ge09iamVjdH0gY29uZmlnIChPcHRpb25hbCkgT3ZlcnJpZGVzIGZvciBjb25maWd1cmF0aW9uIG9wdGlvbnMuXG4gICAgICAgICAgKiBAcmV0dXJuIHtPYmplY3R9IHZhcmlhYmxlc1NlcnZpY2UgSW5zdGFuY2VcbiAgICAgICAgICAqL1xuICAgICAgICB2YXJpYWJsZXM6IGZ1bmN0aW9uIChjb25maWcpIHtcbiAgICAgICAgICAgIHZhciB2cyA9IG5ldyBWYXJpYWJsZXNTZXJ2aWNlKCQuZXh0ZW5kKHRydWUsIHt9LCBzZXJ2aWNlT3B0aW9ucywgY29uZmlnLCB7XG4gICAgICAgICAgICAgICAgcnVuU2VydmljZTogdGhpc1xuICAgICAgICAgICAgfSkpO1xuICAgICAgICAgICAgcmV0dXJuIHZzO1xuICAgICAgICB9XG4gICAgfTtcblxuICAgICQuZXh0ZW5kKHRoaXMsIHB1YmxpY0FzeW5jQVBJKTtcbiAgICAkLmV4dGVuZCh0aGlzLCBwdWJsaWNTeW5jQVBJKTtcbn07XG4iLCIndXNlIHN0cmljdCc7XG5cbnZhciBDb25maWdTZXJ2aWNlID0gcmVxdWlyZSgnLi9jb25maWd1cmF0aW9uLXNlcnZpY2UnKTtcbnZhciBTZXNzaW9uTWFuYWdlciA9IHJlcXVpcmUoJy4uL3N0b3JlL3Nlc3Npb24tbWFuYWdlcicpO1xudmFyIG9iamVjdEFzc2lnbiA9IHJlcXVpcmUoJ29iamVjdC1hc3NpZ24nKTtcblxudmFyIHNlcnZpY2VVdGlscyA9IHtcbiAgICAvKlxuICAgICogR2V0cyB0aGUgZGVmYXVsdCBvcHRpb25zIGZvciBhIGFwaSBzZXJ2aWNlLlxuICAgICogSXQgd2lsbCBtZXJnZTpcbiAgICAqIC0gVGhlIFNlc3Npb24gb3B0aW9ucyAoVXNpbmcgdGhlIFNlc3Npb24gTWFuYWdlcilcbiAgICAqIC0gVGhlIEF1dGhvcml6YXRpb24gSGVhZGVyIGZyb20gdGhlIHRva2VuIG9wdGlvblxuICAgICogLSBUaGUgZnVsbCB1cmwgZnJvbSB0aGUgZW5kcG9pbnQgb3B0aW9uXG4gICAgKiBXaXRoIHRoZSBzdXBwbGllZCBvdmVycmlkZXMgYW5kIGRlZmF1bHRzXG4gICAgKlxuICAgICovXG4gICAgZ2V0RGVmYXVsdE9wdGlvbnM6IGZ1bmN0aW9uIChkZWZhdWx0cykge1xuICAgICAgICB2YXIgcmVzdCA9IEFycmF5LnByb3RvdHlwZS5zbGljZS5jYWxsKGFyZ3VtZW50cywgMSk7XG4gICAgICAgIHZhciBzZXNzaW9uTWFuYWdlciA9IG5ldyBTZXNzaW9uTWFuYWdlcigpO1xuICAgICAgICB2YXIgc2VydmljZU9wdGlvbnMgPSBzZXNzaW9uTWFuYWdlci5nZXRNZXJnZWRPcHRpb25zLmFwcGx5KHNlc3Npb25NYW5hZ2VyLCBbZGVmYXVsdHNdLmNvbmNhdChyZXN0KSk7XG5cbiAgICAgICAgc2VydmljZU9wdGlvbnMudHJhbnNwb3J0ID0gb2JqZWN0QXNzaWduKHt9LCBzZXJ2aWNlT3B0aW9ucy50cmFuc3BvcnQsIHtcbiAgICAgICAgICAgIHVybDogdGhpcy5nZXRBcGlVcmwoc2VydmljZU9wdGlvbnMuYXBpRW5kcG9pbnQsIHNlcnZpY2VPcHRpb25zKVxuICAgICAgICB9KTtcblxuICAgICAgICBpZiAoc2VydmljZU9wdGlvbnMudG9rZW4pIHtcbiAgICAgICAgICAgIHNlcnZpY2VPcHRpb25zLnRyYW5zcG9ydC5oZWFkZXJzID0ge1xuICAgICAgICAgICAgICAgIEF1dGhvcml6YXRpb246ICdCZWFyZXIgJyArIHNlcnZpY2VPcHRpb25zLnRva2VuXG4gICAgICAgICAgICB9O1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiBzZXJ2aWNlT3B0aW9ucztcbiAgICB9LFxuXG4gICAgZ2V0QXBpVXJsOiBmdW5jdGlvbiAoYXBpRW5kcG9pbnQsIHNlcnZpY2VPcHRpb25zKSB7XG4gICAgICAgIHZhciB1cmxDb25maWcgPSBuZXcgQ29uZmlnU2VydmljZShzZXJ2aWNlT3B0aW9ucykuZ2V0KCdzZXJ2ZXInKTtcbiAgICAgICAgcmV0dXJuIHVybENvbmZpZy5nZXRBUElQYXRoKGFwaUVuZHBvaW50KTtcbiAgICB9XG59O1xuXG5tb2R1bGUuZXhwb3J0cyA9IHNlcnZpY2VVdGlsczsiLCIndXNlIHN0cmljdCc7XG4vKipcbiAqICMjIFN0YXRlIEFQSSBBZGFwdGVyXG4gKlxuICogVGhlIFN0YXRlIEFQSSBBZGFwdGVyIGFsbG93cyB5b3UgdG8gdmlldyB0aGUgaGlzdG9yeSBvZiBhIHJ1biwgYW5kIHRvIHJlcGxheSBvciBjbG9uZSBydW5zLiBcbiAqXG4gKiBUaGUgU3RhdGUgQVBJIEFkYXB0ZXIgYnJpbmdzIGV4aXN0aW5nLCBwZXJzaXN0ZWQgcnVuIGRhdGEgZnJvbSB0aGUgZGF0YWJhc2UgYmFjayBpbnRvIG1lbW9yeSwgdXNpbmcgdGhlIHNhbWUgcnVuIGlkIChgcmVwbGF5YCkgb3IgYSBuZXcgcnVuIGlkIChgY2xvbmVgKS4gUnVucyBtdXN0IGJlIGluIG1lbW9yeSBpbiBvcmRlciBmb3IgeW91IHRvIHVwZGF0ZSB2YXJpYWJsZXMgb3IgY2FsbCBvcGVyYXRpb25zIG9uIHRoZW0uXG4gKlxuICogU3BlY2lmaWNhbGx5LCB0aGUgU3RhdGUgQVBJIEFkYXB0ZXIgd29ya3MgYnkgXCJyZS1ydW5uaW5nXCIgdGhlIHJ1biAodXNlciBpbnRlcmFjdGlvbnMpIGZyb20gdGhlIGNyZWF0aW9uIG9mIHRoZSBydW4gdXAgdG8gdGhlIHRpbWUgaXQgd2FzIGxhc3QgcGVyc2lzdGVkIGluIHRoZSBkYXRhYmFzZS4gVGhpcyBwcm9jZXNzIHVzZXMgdGhlIGN1cnJlbnQgdmVyc2lvbiBvZiB0aGUgcnVuJ3MgbW9kZWwuIFRoZXJlZm9yZSwgaWYgdGhlIG1vZGVsIGhhcyBjaGFuZ2VkIHNpbmNlIHRoZSBvcmlnaW5hbCBydW4gd2FzIGNyZWF0ZWQsIHRoZSByZXRyaWV2ZWQgcnVuIHdpbGwgdXNlIHRoZSBuZXcgbW9kZWwg4oCUIGFuZCBtYXkgZW5kIHVwIGhhdmluZyBkaWZmZXJlbnQgdmFsdWVzIG9yIGJlaGF2aW9yIGFzIGEgcmVzdWx0LiBVc2Ugd2l0aCBjYXJlIVxuICpcbiAqIFRvIHVzZSB0aGUgU3RhdGUgQVBJIEFkYXB0ZXIsIGluc3RhbnRpYXRlIGl0IGFuZCB0aGVuIGNhbGwgaXRzIG1ldGhvZHM6XG4gKlxuICogICAgICB2YXIgc2EgPSBuZXcgRi5zZXJ2aWNlLlN0YXRlKCk7XG4gKiAgICAgIHNhLnJlcGxheSh7cnVuSWQ6ICcxODQyYmI1Yy04M2FkLTRiYTgtYTk1NS1iZDEzY2MyZmRiNGYnfSk7XG4gKlxuICogVGhlIGNvbnN0cnVjdG9yIHRha2VzIGFuIG9wdGlvbmFsIGBvcHRpb25zYCBwYXJhbWV0ZXIgaW4gd2hpY2ggeW91IGNhbiBzcGVjaWZ5IHRoZSBgYWNjb3VudGAgYW5kIGBwcm9qZWN0YCBpZiB0aGV5IGFyZSBub3QgYWxyZWFkeSBhdmFpbGFibGUgaW4gdGhlIGN1cnJlbnQgY29udGV4dC5cbiAqXG4gKi9cblxudmFyIENvbmZpZ1NlcnZpY2UgPSByZXF1aXJlKCcuL2NvbmZpZ3VyYXRpb24tc2VydmljZScpO1xudmFyIFRyYW5zcG9ydEZhY3RvcnkgPSByZXF1aXJlKCcuLi90cmFuc3BvcnQvaHR0cC10cmFuc3BvcnQtZmFjdG9yeScpO1xudmFyIF9waWNrID0gcmVxdWlyZSgnLi4vdXRpbC9vYmplY3QtdXRpbCcpLl9waWNrO1xudmFyIFNlc3Npb25NYW5hZ2VyID0gcmVxdWlyZSgnLi4vc3RvcmUvc2Vzc2lvbi1tYW5hZ2VyJyk7XG52YXIgYXBpRW5kcG9pbnQgPSAnbW9kZWwvc3RhdGUnO1xuXG5tb2R1bGUuZXhwb3J0cyA9IGZ1bmN0aW9uIChjb25maWcpIHtcblxuICAgIHZhciBkZWZhdWx0cyA9IHtcblxuICAgIH07XG5cbiAgICB0aGlzLnNlc3Npb25NYW5hZ2VyID0gbmV3IFNlc3Npb25NYW5hZ2VyKCk7XG4gICAgdmFyIHNlcnZpY2VPcHRpb25zID0gdGhpcy5zZXNzaW9uTWFuYWdlci5nZXRNZXJnZWRPcHRpb25zKGRlZmF1bHRzLCBjb25maWcpO1xuICAgIHZhciB1cmxDb25maWcgPSBuZXcgQ29uZmlnU2VydmljZShzZXJ2aWNlT3B0aW9ucykuZ2V0KCdzZXJ2ZXInKTtcblxuICAgIHZhciB0cmFuc3BvcnRPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sIHNlcnZpY2VPcHRpb25zLnRyYW5zcG9ydCwge1xuICAgICAgICB1cmw6IHVybENvbmZpZy5nZXRBUElQYXRoKGFwaUVuZHBvaW50KVxuICAgIH0pO1xuXG4gICAgaWYgKHNlcnZpY2VPcHRpb25zLnRva2VuKSB7XG4gICAgICAgIHRyYW5zcG9ydE9wdGlvbnMuaGVhZGVycyA9IHtcbiAgICAgICAgICAgIEF1dGhvcml6YXRpb246ICdCZWFyZXIgJyArIHNlcnZpY2VPcHRpb25zLnRva2VuXG4gICAgICAgIH07XG4gICAgfVxuXG4gICAgdmFyIGh0dHAgPSBuZXcgVHJhbnNwb3J0RmFjdG9yeSh0cmFuc3BvcnRPcHRpb25zKTtcbiAgICB2YXIgcGFyc2VSdW5JZE9yRXJyb3IgPSBmdW5jdGlvbiAocGFyYW1zKSB7XG4gICAgICAgIGlmICgkLmlzUGxhaW5PYmplY3QocGFyYW1zKSAmJiBwYXJhbXMucnVuSWQpIHtcbiAgICAgICAgICAgIHJldHVybiBwYXJhbXMucnVuSWQ7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ1BsZWFzZSBwYXNzIGluIGEgcnVuIGlkJyk7XG4gICAgICAgIH1cbiAgICB9O1xuXG4gICAgdmFyIHB1YmxpY0FQSSA9IHtcblxuICAgICAgICAvKipcbiAgICAgICAgKiBWaWV3IHRoZSBoaXN0b3J5IG9mIGEgcnVuLlxuICAgICAgICAqIFxuICAgICAgICAqICAqKkV4YW1wbGUqKlxuICAgICAgICAqXG4gICAgICAgICogICAgICB2YXIgc2EgPSBuZXcgRi5zZXJ2aWNlLlN0YXRlKCk7XG4gICAgICAgICogICAgICBzYS5sb2FkKCcwMDAwMDE1YTA2YmI1ODYxM2IyOGI1NzM2NTY3N2VjODllYzUnKS50aGVuKGZ1bmN0aW9uKGhpc3RvcnkpIHtcbiAgICAgICAgKiAgICAgICAgICAgIGNvbnNvbGUubG9nKCdoaXN0b3J5ID0gJywgaGlzdG9yeSk7XG4gICAgICAgICogICAgICB9KTtcbiAgICAgICAgKlxuICAgICAgICAqICAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAqIEBwYXJhbSB7c3RyaW5nfSBydW5JZCBUaGUgaWQgb2YgdGhlIHJ1bi5cbiAgICAgICAgKiBAcGFyYW0ge29iamVjdH0gb3B0aW9ucyAoT3B0aW9uYWwpIE92ZXJyaWRlcyBmb3IgY29uZmlndXJhdGlvbiBvcHRpb25zLlxuICAgICAgICAqIEByZXR1cm4ge1Byb21pc2V9XG4gICAgICAgICovXG4gICAgICAgIGxvYWQ6IGZ1bmN0aW9uIChydW5JZCwgb3B0aW9ucykge1xuICAgICAgICAgICAgdmFyIGh0dHBQYXJhbXMgPSAkLmV4dGVuZCh0cnVlLCB7fSxcbiAgICAgICAgICAgICAgICBzZXJ2aWNlT3B0aW9ucyxcbiAgICAgICAgICAgICAgICBvcHRpb25zLFxuICAgICAgICAgICAgICAgIHsgdXJsOiB1cmxDb25maWcuZ2V0QVBJUGF0aChhcGlFbmRwb2ludCkgKyBydW5JZCB9XG4gICAgICAgICAgICApO1xuICAgICAgICAgICAgcmV0dXJuIGh0dHAuZ2V0KCcnLCBodHRwUGFyYW1zKTtcbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgKiBSZXBsYXkgYSBydW4uIEFmdGVyIHRoaXMgY2FsbCwgdGhlIHJ1biwgd2l0aCBpdHMgb3JpZ2luYWwgcnVuIGlkLCBpcyBub3cgYXZhaWxhYmxlIFtpbiBtZW1vcnldKC4uLy4uLy4uL3J1bl9wZXJzaXN0ZW5jZS8jcnVucy1pbi1tZW1vcnkpLiAoSXQgY29udGludWVzIHRvIGJlIHBlcnNpc3RlZCBpbnRvIHRoZSBFcGljZW50ZXIgZGF0YWJhc2UgYXQgcmVndWxhciBpbnRlcnZhbHMuKVxuICAgICAgICAqXG4gICAgICAgICogICoqRXhhbXBsZSoqXG4gICAgICAgICpcbiAgICAgICAgKiAgICAgIHZhciBzYSA9IG5ldyBGLnNlcnZpY2UuU3RhdGUoKTtcbiAgICAgICAgKiAgICAgIHNhLnJlcGxheSh7cnVuSWQ6ICcxODQyYmI1Yy04M2FkLTRiYTgtYTk1NS1iZDEzY2MyZmRiNGYnLCBzdG9wQmVmb3JlOiAnY2FsY3VsYXRlU2NvcmUnfSk7XG4gICAgICAgICpcbiAgICAgICAgKiAgKipQYXJhbWV0ZXJzKipcbiAgICAgICAgKiBAcGFyYW0ge29iamVjdH0gcGFyYW1zIFBhcmFtZXRlcnMgb2JqZWN0LlxuICAgICAgICAqIEBwYXJhbSB7c3RyaW5nfSBwYXJhbXMucnVuSWQgVGhlIGlkIG9mIHRoZSBydW4gdG8gYnJpbmcgYmFjayB0byBtZW1vcnkuXG4gICAgICAgICogQHBhcmFtIHtzdHJpbmd9IHBhcmFtcy5zdG9wQmVmb3JlIChPcHRpb25hbCkgVGhlIHJ1biBpcyBhZHZhbmNlZCBvbmx5IHVwIHRvIHRoZSBmaXJzdCBvY2N1cnJlbmNlIG9mIHRoaXMgbWV0aG9kLlxuICAgICAgICAqIEBwYXJhbSB7YXJyYXl9IHBhcmFtcy5leGNsdWRlIChPcHRpb25hbCkgQXJyYXkgb2YgbWV0aG9kcyB0byBleGNsdWRlIHdoZW4gYWR2YW5jaW5nIHRoZSBydW4uXG4gICAgICAgICogQHBhcmFtIHtvYmplY3R9IG9wdGlvbnMgKE9wdGlvbmFsKSBPdmVycmlkZXMgZm9yIGNvbmZpZ3VyYXRpb24gb3B0aW9ucy5cbiAgICAgICAgKiBAcmV0dXJuIHtQcm9taXNlfVxuICAgICAgICAqL1xuICAgICAgICByZXBsYXk6IGZ1bmN0aW9uIChwYXJhbXMsIG9wdGlvbnMpIHtcbiAgICAgICAgICAgIHZhciBydW5JZCA9IHBhcnNlUnVuSWRPckVycm9yKHBhcmFtcyk7XG5cbiAgICAgICAgICAgIHZhciByZXBsYXlPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sXG4gICAgICAgICAgICAgICAgc2VydmljZU9wdGlvbnMsXG4gICAgICAgICAgICAgICAgb3B0aW9ucyxcbiAgICAgICAgICAgICAgICB7IHVybDogdXJsQ29uZmlnLmdldEFQSVBhdGgoYXBpRW5kcG9pbnQpICsgcnVuSWQgfVxuICAgICAgICAgICAgKTtcblxuICAgICAgICAgICAgcGFyYW1zID0gJC5leHRlbmQodHJ1ZSwgeyBhY3Rpb246ICdyZXBsYXknIH0sIF9waWNrKHBhcmFtcywgWydzdG9wQmVmb3JlJywgJ2V4Y2x1ZGUnXSkpO1xuXG4gICAgICAgICAgICByZXR1cm4gaHR0cC5wb3N0KHBhcmFtcywgcmVwbGF5T3B0aW9ucyk7XG4gICAgICAgIH0sXG5cbiAgICAgICAgLyoqXG4gICAgICAgICogQ2xvbmUgYSBnaXZlbiBydW4gYW5kIHJldHVybiBhIG5ldyBydW4gaW4gdGhlIHNhbWUgc3RhdGUgYXMgdGhlIGdpdmVuIHJ1bi5cbiAgICAgICAgKlxuICAgICAgICAqIFRoZSBuZXcgcnVuIGlkIGlzIG5vdyBhdmFpbGFibGUgW2luIG1lbW9yeV0oLi4vLi4vLi4vcnVuX3BlcnNpc3RlbmNlLyNydW5zLWluLW1lbW9yeSkuIFRoZSBuZXcgcnVuIGluY2x1ZGVzIGEgY29weSBvZiBhbGwgb2YgdGhlIGRhdGEgZnJvbSB0aGUgb3JpZ2luYWwgcnVuLCBFWENFUFQ6XG4gICAgICAgICpcbiAgICAgICAgKiAqIFRoZSBgc2F2ZWRgIGZpZWxkIGluIHRoZSBuZXcgcnVuIHJlY29yZCBpcyBub3QgY29waWVkIGZyb20gdGhlIG9yaWdpbmFsIHJ1biByZWNvcmQuIEl0IGRlZmF1bHRzIHRvIGBmYWxzZWAuXG4gICAgICAgICogKiBUaGUgYGluaXRpYWxpemVkYCBmaWVsZCBpbiB0aGUgbmV3IHJ1biByZWNvcmQgaXMgbm90IGNvcGllZCBmcm9tIHRoZSBvcmlnaW5hbCBydW4gcmVjb3JkLiBJdCBkZWZhdWx0cyB0byBgZmFsc2VgIGJ1dCBtYXkgY2hhbmdlIHRvIGB0cnVlYCBhcyB0aGUgbmV3IHJ1biBpcyBhZHZhbmNlZC4gRm9yIGV4YW1wbGUsIGlmIHRoZXJlIGhhcyBiZWVuIGEgY2FsbCB0byB0aGUgYHN0ZXBgIGZ1bmN0aW9uIChmb3IgVmVuc2ltIG1vZGVscyksIHRoZSBgaW5pdGlhbGl6ZWRgIGZpZWxkIGlzIHNldCB0byBgdHJ1ZWAuXG4gICAgICAgICogKiBUaGUgYGNyZWF0ZWRgIGZpZWxkIGluIHRoZSBuZXcgcnVuIHJlY29yZCBpcyB0aGUgZGF0ZSBhbmQgdGltZSBhdCB3aGljaCB0aGUgY2xvbmUgd2FzIGNyZWF0ZWQgKG5vdCB0aGUgdGltZSB0aGF0IHRoZSBvcmlnaW5hbCBydW4gd2FzIGNyZWF0ZWQuKVxuICAgICAgICAqXG4gICAgICAgICogVGhlIG9yaWdpbmFsIHJ1biByZW1haW5zIG9ubHkgW2luIHRoZSBkYXRhYmFzZV0oLi4vLi4vLi4vcnVuX3BlcnNpc3RlbmNlLyNydW5zLWluLWRiKS5cbiAgICAgICAgKlxuICAgICAgICAqICAqKkV4YW1wbGUqKlxuICAgICAgICAqXG4gICAgICAgICogICAgICB2YXIgc2EgPSBuZXcgRi5zZXJ2aWNlLlN0YXRlKCk7XG4gICAgICAgICogICAgICBzYS5jbG9uZSh7cnVuSWQ6ICcxODQyYmI1Yy04M2FkLTRiYTgtYTk1NS1iZDEzY2MyZmRiNGYnLCBzdG9wQmVmb3JlOiAnY2FsY3VsYXRlU2NvcmUnLCBleGNsdWRlOiBbJ2ludGVyaW1DYWxjdWxhdGlvbiddIH0pO1xuICAgICAgICAqXG4gICAgICAgICogICoqUGFyYW1ldGVycyoqXG4gICAgICAgICogQHBhcmFtIHtvYmplY3R9IHBhcmFtcyBQYXJhbWV0ZXJzIG9iamVjdC5cbiAgICAgICAgKiBAcGFyYW0ge3N0cmluZ30gcGFyYW1zLnJ1bklkIFRoZSBpZCBvZiB0aGUgcnVuIHRvIGNsb25lIGZyb20gbWVtb3J5LlxuICAgICAgICAqIEBwYXJhbSB7c3RyaW5nfSBwYXJhbXMuc3RvcEJlZm9yZSAoT3B0aW9uYWwpIFRoZSBuZXdseSBjbG9uZWQgcnVuIGlzIGFkdmFuY2VkIG9ubHkgdXAgdG8gdGhlIGZpcnN0IG9jY3VycmVuY2Ugb2YgdGhpcyBtZXRob2QuXG4gICAgICAgICogQHBhcmFtIHthcnJheX0gcGFyYW1zLmV4Y2x1ZGUgKE9wdGlvbmFsKSBBcnJheSBvZiBtZXRob2RzIHRvIGV4Y2x1ZGUgd2hlbiBhZHZhbmNpbmcgdGhlIG5ld2x5IGNsb25lZCBydW4uXG4gICAgICAgICogQHBhcmFtIHtvYmplY3R9IG9wdGlvbnMgKE9wdGlvbmFsKSBPdmVycmlkZXMgZm9yIGNvbmZpZ3VyYXRpb24gb3B0aW9ucy5cbiAgICAgICAgKiBAcmV0dXJuIHtQcm9taXNlfVxuICAgICAgICAqL1xuICAgICAgICBjbG9uZTogZnVuY3Rpb24gKHBhcmFtcywgb3B0aW9ucykge1xuICAgICAgICAgICAgdmFyIHJ1bklkID0gcGFyc2VSdW5JZE9yRXJyb3IocGFyYW1zKTtcblxuICAgICAgICAgICAgdmFyIHJlcGxheU9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSxcbiAgICAgICAgICAgICAgICBzZXJ2aWNlT3B0aW9ucyxcbiAgICAgICAgICAgICAgICBvcHRpb25zLFxuICAgICAgICAgICAgICAgIHsgdXJsOiB1cmxDb25maWcuZ2V0QVBJUGF0aChhcGlFbmRwb2ludCkgKyBydW5JZCB9XG4gICAgICAgICAgICApO1xuXG4gICAgICAgICAgICBwYXJhbXMgPSAkLmV4dGVuZCh0cnVlLCB7IGFjdGlvbjogJ2Nsb25lJyB9LCBfcGljayhwYXJhbXMsIFsnc3RvcEJlZm9yZScsICdleGNsdWRlJ10pKTtcblxuICAgICAgICAgICAgcmV0dXJuIGh0dHAucG9zdChwYXJhbXMsIHJlcGxheU9wdGlvbnMpO1xuICAgICAgICB9XG4gICAgfTtcblxuICAgICQuZXh0ZW5kKHRoaXMsIHB1YmxpY0FQSSk7XG59O1xuIiwiJ3VzZSBzdHJpY3QnO1xuXG52YXIgZXBpVmVyc2lvbiA9IHJlcXVpcmUoJy4uL2FwaS12ZXJzaW9uLmpzb24nKTtcblxuLy9UT0RPOiB1cmx1dGlscyB0byBnZXQgaG9zdCwgc2luY2Ugbm8gd2luZG93IG9uIG5vZGVcbnZhciBkZWZhdWx0cyA9IHtcbiAgICBob3N0OiB3aW5kb3cubG9jYXRpb24uaG9zdCxcbiAgICBwYXRobmFtZTogd2luZG93LmxvY2F0aW9uLnBhdGhuYW1lXG59O1xuXG5mdW5jdGlvbiBnZXRMb2NhbEhvc3QoZXhpc3RpbmdGbiwgaG9zdCkge1xuICAgIHZhciBsb2NhbEhvc3RGbjtcbiAgICBpZiAoZXhpc3RpbmdGbiAhPT0gdW5kZWZpbmVkKSB7XG4gICAgICAgIGlmICghJC5pc0Z1bmN0aW9uKGV4aXN0aW5nRm4pKSB7XG4gICAgICAgICAgICBsb2NhbEhvc3RGbiA9IGZ1bmN0aW9uICgpIHsgcmV0dXJuIGV4aXN0aW5nRm47IH07XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICBsb2NhbEhvc3RGbiA9IGV4aXN0aW5nRm47XG4gICAgICAgIH1cbiAgICB9IGVsc2Uge1xuICAgICAgICBsb2NhbEhvc3RGbiA9IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIHZhciBpc0xvY2FsID0gIWhvc3QgfHwgLy9waGFudG9tanNcbiAgICAgICAgICAgICAgICBob3N0ID09PSAnMTI3LjAuMC4xJyB8fCBcbiAgICAgICAgICAgICAgICBob3N0LmluZGV4T2YoJ2xvY2FsLicpID09PSAwIHx8IFxuICAgICAgICAgICAgICAgIGhvc3QuaW5kZXhPZignbG9jYWxob3N0JykgPT09IDA7XG4gICAgICAgICAgICByZXR1cm4gaXNMb2NhbDtcbiAgICAgICAgfTtcbiAgICB9XG4gICAgcmV0dXJuIGxvY2FsSG9zdEZuO1xufVxuXG52YXIgVXJsQ29uZmlnU2VydmljZSA9IGZ1bmN0aW9uIChjb25maWcpIHtcbiAgICB2YXIgZW52Q29uZiA9IFVybENvbmZpZ1NlcnZpY2UuZGVmYXVsdHM7XG5cbiAgICBpZiAoIWNvbmZpZykge1xuICAgICAgICBjb25maWcgPSB7fTtcbiAgICB9XG4gICAgLy8gY29uc29sZS5sb2codGhpcy5kZWZhdWx0cyk7XG4gICAgdmFyIG92ZXJyaWRlcyA9ICQuZXh0ZW5kKHt9LCBlbnZDb25mLCBjb25maWcpO1xuICAgIHZhciBvcHRpb25zID0gJC5leHRlbmQoe30sIGRlZmF1bHRzLCBvdmVycmlkZXMpO1xuXG4gICAgb3ZlcnJpZGVzLmlzTG9jYWxob3N0ID0gb3B0aW9ucy5pc0xvY2FsaG9zdCA9IGdldExvY2FsSG9zdChvcHRpb25zLmlzTG9jYWxob3N0LCBvcHRpb25zLmhvc3QpO1xuICAgIFxuICAgIC8vIGNvbnNvbGUubG9nKGlzTG9jYWxob3N0KCksICdfX19fX19fX19fXycpO1xuICAgIHZhciBhY3RpbmdIb3N0ID0gY29uZmlnICYmIGNvbmZpZy5ob3N0O1xuICAgIGlmICghYWN0aW5nSG9zdCAmJiBvcHRpb25zLmlzTG9jYWxob3N0KCkpIHtcbiAgICAgICAgYWN0aW5nSG9zdCA9ICdmb3Jpby5jb20nO1xuICAgIH0gZWxzZSB7XG4gICAgICAgIGFjdGluZ0hvc3QgPSBvcHRpb25zLmhvc3Q7XG4gICAgfVxuXG4gICAgdmFyIEFQSV9QUk9UT0NPTCA9ICdodHRwcyc7XG4gICAgdmFyIEhPU1RfQVBJX01BUFBJTkcgPSB7XG4gICAgICAgICdmb3Jpby5jb20nOiAnYXBpLmZvcmlvLmNvbScsXG4gICAgICAgICdmb3Jpb2Rldi5jb20nOiAnYXBpLmVwaWNlbnRlci5mb3Jpb2Rldi5jb20nXG4gICAgfTtcblxuICAgIHZhciBwdWJsaWNFeHBvcnRzID0ge1xuICAgICAgICBwcm90b2NvbDogQVBJX1BST1RPQ09MLFxuXG4gICAgICAgIGFwaTogJycsXG5cbiAgICAgICAgLy9UT0RPOiB0aGlzIHNob3VsZCByZWFsbHkgYmUgY2FsbGVkICdhcGlob3N0JywgYnV0IGNhbid0IGJlY2F1c2UgdGhhdCB3b3VsZCBicmVhayB0b28gbWFueSB0aGluZ3NcbiAgICAgICAgaG9zdDogKGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIHZhciBhcGlIb3N0ID0gKEhPU1RfQVBJX01BUFBJTkdbYWN0aW5nSG9zdF0pID8gSE9TVF9BUElfTUFQUElOR1thY3RpbmdIb3N0XSA6IGFjdGluZ0hvc3Q7XG4gICAgICAgICAgICAvLyBjb25zb2xlLmxvZyhhY3RpbmdIb3N0LCBjb25maWcsIGFwaUhvc3QpO1xuICAgICAgICAgICAgcmV0dXJuIGFwaUhvc3Q7XG4gICAgICAgIH0oKSksXG5cbiAgICAgICAgaXNDdXN0b21Eb21haW46IChmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICB2YXIgcGF0aCA9IG9wdGlvbnMucGF0aG5hbWUuc3BsaXQoJ1xcLycpO1xuICAgICAgICAgICAgdmFyIHBhdGhIYXNBcHAgPSBwYXRoICYmIHBhdGhbMV0gPT09ICdhcHAnO1xuICAgICAgICAgICAgcmV0dXJuICghb3B0aW9ucy5pc0xvY2FsaG9zdCgpICYmICFwYXRoSGFzQXBwKTtcbiAgICAgICAgfSgpKSxcblxuICAgICAgICBhcHBQYXRoOiAoZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgdmFyIHBhdGggPSBvcHRpb25zLnBhdGhuYW1lLnNwbGl0KCdcXC8nKTtcblxuICAgICAgICAgICAgcmV0dXJuIHBhdGggJiYgcGF0aFsxXSB8fCAnJztcbiAgICAgICAgfSgpKSxcblxuICAgICAgICBhY2NvdW50UGF0aDogKGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIHZhciBhY2NudCA9ICcnO1xuICAgICAgICAgICAgdmFyIHBhdGggPSBvcHRpb25zLnBhdGhuYW1lLnNwbGl0KCdcXC8nKTtcbiAgICAgICAgICAgIGlmIChwYXRoICYmIHBhdGhbMV0gPT09ICdhcHAnKSB7XG4gICAgICAgICAgICAgICAgYWNjbnQgPSBwYXRoWzJdO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgcmV0dXJuIGFjY250O1xuICAgICAgICB9KCkpLFxuXG4gICAgICAgIHByb2plY3RQYXRoOiAoZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgdmFyIHByaiA9ICcnO1xuICAgICAgICAgICAgdmFyIHBhdGggPSBvcHRpb25zLnBhdGhuYW1lLnNwbGl0KCdcXC8nKTtcbiAgICAgICAgICAgIGlmIChwYXRoICYmIHBhdGhbMV0gPT09ICdhcHAnKSB7XG4gICAgICAgICAgICAgICAgcHJqID0gcGF0aFszXTsgLy9lc2xpbnQtZGlzYWJsZS1saW5lIG5vLW1hZ2ljLW51bWJlcnNcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHJldHVybiBwcmo7XG4gICAgICAgIH0oKSksXG5cbiAgICAgICAgdmVyc2lvblBhdGg6IChmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICB2YXIgdmVyc2lvbiA9IGVwaVZlcnNpb24udmVyc2lvbiA/IGVwaVZlcnNpb24udmVyc2lvbiArICcvJyA6ICcnO1xuICAgICAgICAgICAgcmV0dXJuIHZlcnNpb247XG4gICAgICAgIH0oKSksXG5cbiAgICAgICAgZ2V0QVBJUGF0aDogZnVuY3Rpb24gKGFwaSkge1xuICAgICAgICAgICAgdmFyIFBST0pFQ1RfQVBJUyA9IFsncnVuJywgJ2RhdGEnLCAnZmlsZScsICdwcmVzZW5jZSddO1xuICAgICAgICAgICAgdmFyIGFwaU1hcHBpbmcgPSB7XG4gICAgICAgICAgICAgICAgY2hhbm5lbDogJ2NoYW5uZWwvc3Vic2NyaWJlJ1xuICAgICAgICAgICAgfTtcbiAgICAgICAgICAgIHZhciBhcGlFbmRwb2ludCA9IGFwaU1hcHBpbmdbYXBpXSB8fCBhcGk7XG4gICAgICAgICAgICBcbiAgICAgICAgICAgIGlmIChhcGlFbmRwb2ludCA9PT0gJ2NvbmZpZycpIHtcbiAgICAgICAgICAgICAgICB2YXIgYWN0dWFsUHJvdG9jb2wgPSB3aW5kb3cubG9jYXRpb24ucHJvdG9jb2wucmVwbGFjZSgnOicsICcnKTtcbiAgICAgICAgICAgICAgICB2YXIgY29uZmlnUHJvdG9jb2wgPSAob3B0aW9ucy5pc0xvY2FsaG9zdCgpKSA/IHRoaXMucHJvdG9jb2wgOiBhY3R1YWxQcm90b2NvbDtcbiAgICAgICAgICAgICAgICByZXR1cm4gY29uZmlnUHJvdG9jb2wgKyAnOi8vJyArIGFjdGluZ0hvc3QgKyAnL2VwaWNlbnRlci8nICsgdGhpcy52ZXJzaW9uUGF0aCArICdjb25maWcnO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgdmFyIGFwaVBhdGggPSB0aGlzLnByb3RvY29sICsgJzovLycgKyB0aGlzLmhvc3QgKyAnLycgKyB0aGlzLnZlcnNpb25QYXRoICsgYXBpRW5kcG9pbnQgKyAnLyc7XG5cbiAgICAgICAgICAgIGlmICgkLmluQXJyYXkoYXBpRW5kcG9pbnQsIFBST0pFQ1RfQVBJUykgIT09IC0xKSB7XG4gICAgICAgICAgICAgICAgYXBpUGF0aCArPSB0aGlzLmFjY291bnRQYXRoICsgJy8nICsgdGhpcy5wcm9qZWN0UGF0aCArICcvJztcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHJldHVybiBhcGlQYXRoO1xuICAgICAgICB9XG4gICAgfTtcblxuXG4gICAgJC5leHRlbmQocHVibGljRXhwb3J0cywgb3ZlcnJpZGVzKTtcbiAgICByZXR1cm4gcHVibGljRXhwb3J0cztcbn07XG4vLyBUaGlzIGRhdGEgY2FuIGJlIHNldCBieSBleHRlcm5hbCBzY3JpcHRzLCBmb3IgbG9hZGluZyBmcm9tIGFuIGVudiBzZXJ2ZXIgZm9yIGVnO1xuVXJsQ29uZmlnU2VydmljZS5kZWZhdWx0cyA9IHt9O1xuXG5tb2R1bGUuZXhwb3J0cyA9IFVybENvbmZpZ1NlcnZpY2U7XG4iLCIndXNlIHN0cmljdCc7XG4vKipcbiogIyMgVXNlciBBUEkgQWRhcHRlclxuKlxuKiBUaGUgVXNlciBBUEkgQWRhcHRlciBhbGxvd3MgeW91IHRvIHJldHJpZXZlIGRldGFpbHMgYWJvdXQgZW5kIHVzZXJzIGluIHlvdXIgdGVhbSAoYWNjb3VudCkuIEl0IGlzIGJhc2VkIG9uIHRoZSBxdWVyeWluZyBjYXBhYmlsaXRpZXMgb2YgdGhlIHVuZGVybHlpbmcgUkVTVGZ1bCBbVXNlciBBUEldKC4uLy4uLy4uL3Jlc3RfYXBpcy91c2VyX21hbmFnZW1lbnQvdXNlci8pLlxuKlxuKiBUbyB1c2UgdGhlIFVzZXIgQVBJIEFkYXB0ZXIsIGluc3RhbnRpYXRlIGl0IGFuZCB0aGVuIGNhbGwgaXRzIG1ldGhvZHMuXG4qXG4qICAgICAgIHZhciB1YSA9IG5ldyBGLnNlcnZpY2UuVXNlcih7XG4qICAgICAgICAgICBhY2NvdW50OiAnYWNtZS1zaW11bGF0aW9ucycsXG4qICAgICAgICAgICB0b2tlbjogJ3VzZXItb3ItcHJvamVjdC1hY2Nlc3MtdG9rZW4nXG4qICAgICAgIH0pO1xuKiAgICAgICB1YS5nZXRCeUlkKCc0MjgzNmQ0Yi01YjYxLTRmZTQtODBlYi0zMTM2ZTk1NmVlNWMnKTtcbiogICAgICAgdWEuZ2V0KHsgdXNlck5hbWU6ICdqc21pdGgnIH0pO1xuKiAgICAgICB1YS5nZXQoeyBpZDogWyc0MjgzNmQ0Yi01YjYxLTRmZTQtODBlYi0zMTM2ZTk1NmVlNWMnLFxuKiAgICAgICAgICAgICAgICAgICAnNGVhNzU2MzEtNGM4ZC00ODcyLTlkODAtYjQ2MDAxNDY0NzhlJ10gfSk7XG4qXG4qIFRoZSBjb25zdHJ1Y3RvciB0YWtlcyBhbiBvcHRpb25hbCBgb3B0aW9uc2AgcGFyYW1ldGVyIGluIHdoaWNoIHlvdSBjYW4gc3BlY2lmeSB0aGUgYGFjY291bnRgIGFuZCBgdG9rZW5gIGlmIHRoZXkgYXJlIG5vdCBhbHJlYWR5IGF2YWlsYWJsZSBpbiB0aGUgY3VycmVudCBjb250ZXh0LlxuKi9cblxudmFyIENvbmZpZ1NlcnZpY2UgPSByZXF1aXJlKCcuL2NvbmZpZ3VyYXRpb24tc2VydmljZScpO1xudmFyIFRyYW5zcG9ydEZhY3RvcnkgPSByZXF1aXJlKCcuLi90cmFuc3BvcnQvaHR0cC10cmFuc3BvcnQtZmFjdG9yeScpO1xudmFyIFNlc3Npb25NYW5hZ2VyID0gcmVxdWlyZSgnLi4vc3RvcmUvc2Vzc2lvbi1tYW5hZ2VyJyk7XG52YXIgcXV0aWwgPSByZXF1aXJlKCcuLi91dGlsL3F1ZXJ5LXV0aWwnKTtcblxubW9kdWxlLmV4cG9ydHMgPSBmdW5jdGlvbiAoY29uZmlnKSB7XG4gICAgdmFyIGRlZmF1bHRzID0ge1xuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBUaGUgYWNjb3VudCBpZC4gSW4gdGhlIEVwaWNlbnRlciBVSSwgdGhpcyBpcyB0aGUgKipUZWFtIElEKiogKGZvciB0ZWFtIHByb2plY3RzKSBvciAqKlVzZXIgSUQqKiAoZm9yIHBlcnNvbmFsIHByb2plY3RzKS4gRGVmYXVsdHMgdG8gZW1wdHkgc3RyaW5nLlxuICAgICAgICAgKiBAdHlwZSB7U3RyaW5nfVxuICAgICAgICAgKi9cbiAgICAgICAgYWNjb3VudDogdW5kZWZpbmVkLFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBUaGUgYWNjZXNzIHRva2VuIHRvIHVzZSB3aGVuIHNlYXJjaGluZyBmb3IgZW5kIHVzZXJzLiAoU2VlIFttb3JlIGJhY2tncm91bmQgb24gYWNjZXNzIHRva2Vuc10oLi4vLi4vLi4vcHJvamVjdF9hY2Nlc3MvKSkuXG4gICAgICAgICAqIEB0eXBlIHtTdHJpbmd9XG4gICAgICAgICAqL1xuICAgICAgICB0b2tlbjogdW5kZWZpbmVkLFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBPcHRpb25zIHRvIHBhc3Mgb24gdG8gdGhlIHVuZGVybHlpbmcgdHJhbnNwb3J0IGxheWVyLiBBbGwganF1ZXJ5LmFqYXggb3B0aW9ucyBhdCBodHRwOi8vYXBpLmpxdWVyeS5jb20valF1ZXJ5LmFqYXgvIGFyZSBhdmFpbGFibGUuIERlZmF1bHRzIHRvIGVtcHR5IG9iamVjdC5cbiAgICAgICAgICogQHR5cGUge09iamVjdH1cbiAgICAgICAgICovXG4gICAgICAgIHRyYW5zcG9ydDoge31cbiAgICB9O1xuXG4gICAgdGhpcy5zZXNzaW9uTWFuYWdlciA9IG5ldyBTZXNzaW9uTWFuYWdlcigpO1xuICAgIHZhciBzZXJ2aWNlT3B0aW9ucyA9IHRoaXMuc2Vzc2lvbk1hbmFnZXIuZ2V0TWVyZ2VkT3B0aW9ucyhkZWZhdWx0cywgY29uZmlnKTtcbiAgICB2YXIgdXJsQ29uZmlnID0gbmV3IENvbmZpZ1NlcnZpY2Uoc2VydmljZU9wdGlvbnMpLmdldCgnc2VydmVyJyk7XG4gICAgdmFyIHRyYW5zcG9ydE9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSwgc2VydmljZU9wdGlvbnMudHJhbnNwb3J0LCB7XG4gICAgICAgIHVybDogdXJsQ29uZmlnLmdldEFQSVBhdGgoJ3VzZXInKVxuICAgIH0pO1xuXG4gICAgaWYgKHNlcnZpY2VPcHRpb25zLnRva2VuKSB7XG4gICAgICAgIHRyYW5zcG9ydE9wdGlvbnMuaGVhZGVycyA9IHtcbiAgICAgICAgICAgIEF1dGhvcml6YXRpb246ICdCZWFyZXIgJyArIHNlcnZpY2VPcHRpb25zLnRva2VuXG4gICAgICAgIH07XG4gICAgfVxuXG4gICAgdmFyIGh0dHAgPSBuZXcgVHJhbnNwb3J0RmFjdG9yeSh0cmFuc3BvcnRPcHRpb25zKTtcblxuICAgIHZhciBwdWJsaWNBUEkgPSB7XG5cbiAgICAgICAgLyoqXG4gICAgICAgICogUmV0cmlldmUgZGV0YWlscyBhYm91dCBwYXJ0aWN1bGFyIGVuZCB1c2VycyBpbiB5b3VyIHRlYW0sIGJhc2VkIG9uIHVzZXIgbmFtZSBvciB1c2VyIGlkLlxuICAgICAgICAqXG4gICAgICAgICogKipFeGFtcGxlKipcbiAgICAgICAgKlxuICAgICAgICAqICAgICAgIHZhciB1YSA9IG5ldyBGLnNlcnZpY2UuVXNlcih7XG4gICAgICAgICogICAgICAgICAgIGFjY291bnQ6ICdhY21lLXNpbXVsYXRpb25zJyxcbiAgICAgICAgKiAgICAgICAgICAgdG9rZW46ICd1c2VyLW9yLXByb2plY3QtYWNjZXNzLXRva2VuJ1xuICAgICAgICAqICAgICAgIH0pO1xuICAgICAgICAqICAgICAgIHVhLmdldCh7IHVzZXJOYW1lOiAnanNtaXRoJyB9KTtcbiAgICAgICAgKiAgICAgICB1YS5nZXQoeyBpZDogWyc0MjgzNmQ0Yi01YjYxLTRmZTQtODBlYi0zMTM2ZTk1NmVlNWMnLFxuICAgICAgICAqICAgICAgICAgICAgICAgICAgICc0ZWE3NTYzMS00YzhkLTQ4NzItOWQ4MC1iNDYwMDE0NjQ3OGUnXSB9KTtcbiAgICAgICAgKlxuICAgICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICAgICogQHBhcmFtIHtvYmplY3R9IGZpbHRlciBPYmplY3Qgd2l0aCBmaWVsZCBgdXNlck5hbWVgIGFuZCB2YWx1ZSBvZiB0aGUgdXNlcm5hbWUuIEFsdGVybmF0aXZlbHksIG9iamVjdCB3aXRoIGZpZWxkIGBpZGAgYW5kIHZhbHVlIG9mIGFuIGFycmF5IG9mIHVzZXIgaWRzLlxuICAgICAgICAqIEBwYXJhbSB7b2JqZWN0fSBvcHRpb25zIChPcHRpb25hbCkgT3ZlcnJpZGVzIGZvciBjb25maWd1cmF0aW9uIG9wdGlvbnMuXG4gICAgICAgICogQHJldHVybiB7UHJvbWlzZX1cbiAgICAgICAgKi9cblxuICAgICAgICBnZXQ6IGZ1bmN0aW9uIChmaWx0ZXIsIG9wdGlvbnMpIHtcbiAgICAgICAgICAgIG9wdGlvbnMgPSBvcHRpb25zIHx8IHt9O1xuICAgICAgICAgICAgZmlsdGVyID0gZmlsdGVyIHx8IHt9O1xuXG4gICAgICAgICAgICB2YXIgZ2V0T3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LFxuICAgICAgICAgICAgICAgIHNlcnZpY2VPcHRpb25zLFxuICAgICAgICAgICAgICAgIG9wdGlvbnNcbiAgICAgICAgICAgICk7XG5cbiAgICAgICAgICAgIHZhciB0b1FGaWx0ZXIgPSBmdW5jdGlvbiAoZmlsdGVyKSB7XG4gICAgICAgICAgICAgICAgdmFyIHJlcyA9IHt9O1xuXG4gICAgICAgICAgICAgICAgLy8gQVBJIG9ubHkgc3VwcG9ydHMgZmlsdGVyaW5nIGJ5IHVzZXJuYW1lIGZvciBub3dcbiAgICAgICAgICAgICAgICBpZiAoZmlsdGVyLnVzZXJOYW1lKSB7XG4gICAgICAgICAgICAgICAgICAgIHJlcy5xID0gZmlsdGVyLnVzZXJOYW1lO1xuICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgIHJldHVybiByZXM7XG4gICAgICAgICAgICB9O1xuXG4gICAgICAgICAgICB2YXIgdG9JZEZpbHRlcnMgPSBmdW5jdGlvbiAoaWQpIHtcbiAgICAgICAgICAgICAgICBpZiAoIWlkKSB7XG4gICAgICAgICAgICAgICAgICAgIHJldHVybiAnJztcbiAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICBpZCA9ICQuaXNBcnJheShpZCkgPyBpZCA6IFtpZF07XG4gICAgICAgICAgICAgICAgcmV0dXJuICdpZD0nICsgaWQuam9pbignJmlkPScpO1xuICAgICAgICAgICAgfTtcblxuICAgICAgICAgICAgdmFyIGdldEZpbHRlcnMgPSBbXG4gICAgICAgICAgICAgICAgJ2FjY291bnQ9JyArIGdldE9wdGlvbnMuYWNjb3VudCxcbiAgICAgICAgICAgICAgICB0b0lkRmlsdGVycyhmaWx0ZXIuaWQpLFxuICAgICAgICAgICAgICAgIHF1dGlsLnRvUXVlcnlGb3JtYXQodG9RRmlsdGVyKGZpbHRlcikpXG4gICAgICAgICAgICBdLmpvaW4oJyYnKTtcblxuICAgICAgICAgICAgLy8gc3BlY2lhbCBjYXNlIGZvciBxdWVyaWVzIHdpdGggbGFyZ2UgbnVtYmVyIG9mIGlkc1xuICAgICAgICAgICAgLy8gbWFrZSBpdCBhcyBhIHBvc3Qgd2l0aCBHRVQgc2VtYW50aWNzXG4gICAgICAgICAgICB2YXIgdGhyZXNob2xkID0gMzA7XG4gICAgICAgICAgICBpZiAoZmlsdGVyLmlkICYmICQuaXNBcnJheShmaWx0ZXIuaWQpICYmIGZpbHRlci5pZC5sZW5ndGggPj0gdGhyZXNob2xkKSB7XG4gICAgICAgICAgICAgICAgZ2V0T3B0aW9ucy51cmwgPSB1cmxDb25maWcuZ2V0QVBJUGF0aCgndXNlcicpICsgJz9fbWV0aG9kPUdFVCc7XG4gICAgICAgICAgICAgICAgcmV0dXJuIGh0dHAucG9zdCh7IGlkOiBmaWx0ZXIuaWQgfSwgZ2V0T3B0aW9ucyk7XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgIHJldHVybiBodHRwLmdldChnZXRGaWx0ZXJzLCBnZXRPcHRpb25zKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgKiBSZXRyaWV2ZSBkZXRhaWxzIGFib3V0IGEgc2luZ2xlIGVuZCB1c2VyIGluIHlvdXIgdGVhbSwgYmFzZWQgb24gdXNlciBpZC5cbiAgICAgICAgKlxuICAgICAgICAqICoqRXhhbXBsZSoqXG4gICAgICAgICpcbiAgICAgICAgKiAgICAgICB2YXIgdWEgPSBuZXcgRi5zZXJ2aWNlLlVzZXIoe1xuICAgICAgICAqICAgICAgICAgICBhY2NvdW50OiAnYWNtZS1zaW11bGF0aW9ucycsXG4gICAgICAgICogICAgICAgICAgIHRva2VuOiAndXNlci1vci1wcm9qZWN0LWFjY2Vzcy10b2tlbidcbiAgICAgICAgKiAgICAgICB9KTtcbiAgICAgICAgKiAgICAgICB1YS5nZXRCeUlkKCc0MjgzNmQ0Yi01YjYxLTRmZTQtODBlYi0zMTM2ZTk1NmVlNWMnKTtcbiAgICAgICAgKlxuICAgICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICAgICogQHBhcmFtIHtzdHJpbmd9IHVzZXJJZCBUaGUgdXNlciBpZCBmb3IgdGhlIGVuZCB1c2VyIGluIHlvdXIgdGVhbS5cbiAgICAgICAgKiBAcGFyYW0ge29iamVjdH0gb3B0aW9ucyAoT3B0aW9uYWwpIE92ZXJyaWRlcyBmb3IgY29uZmlndXJhdGlvbiBvcHRpb25zLlxuICAgICAgICAqIEByZXR1cm4ge1Byb21pc2V9XG4gICAgICAgICovXG5cbiAgICAgICAgZ2V0QnlJZDogZnVuY3Rpb24gKHVzZXJJZCwgb3B0aW9ucykge1xuICAgICAgICAgICAgcmV0dXJuIHB1YmxpY0FQSS5nZXQoeyBpZDogdXNlcklkIH0sIG9wdGlvbnMpO1xuICAgICAgICB9XG4gICAgfTtcblxuICAgICQuZXh0ZW5kKHRoaXMsIHB1YmxpY0FQSSk7XG59O1xuXG5cbiIsIi8qKlxuICpcbiAqICMjIFZhcmlhYmxlcyBBUEkgU2VydmljZVxuICpcbiAqIFVzZWQgaW4gY29uanVuY3Rpb24gd2l0aCB0aGUgW1J1biBBUEkgU2VydmljZV0oLi4vcnVuLWFwaS1zZXJ2aWNlLykgdG8gcmVhZCwgd3JpdGUsIGFuZCBzZWFyY2ggZm9yIHNwZWNpZmljIG1vZGVsIHZhcmlhYmxlcy5cbiAqXG4gKiAgICAgdmFyIHJtID0gbmV3IEYubWFuYWdlci5SdW5NYW5hZ2VyKHtcbiAqICAgICAgICAgICBydW46IHtcbiAqICAgICAgICAgICAgICAgYWNjb3VudDogJ2FjbWUtc2ltdWxhdGlvbnMnLFxuICogICAgICAgICAgICAgICBwcm9qZWN0OiAnc3VwcGx5LWNoYWluLWdhbWUnLFxuICogICAgICAgICAgICAgICBtb2RlbDogJ3N1cHBseS1jaGFpbi1tb2RlbC5qbCdcbiAqICAgICAgICAgICB9XG4gKiAgICAgIH0pO1xuICogICAgIHJtLmdldFJ1bigpXG4gKiAgICAgICAudGhlbihmdW5jdGlvbigpIHtcbiAqICAgICAgICAgIHZhciB2cyA9IHJtLnJ1bi52YXJpYWJsZXMoKTtcbiAqICAgICAgICAgIHZzLnNhdmUoe3NhbXBsZV9pbnQ6IDR9KTtcbiAqICAgICAgICB9KTtcbiAqXG4gKi9cblxuXG4gJ3VzZSBzdHJpY3QnO1xuXG4gdmFyIFRyYW5zcG9ydEZhY3RvcnkgPSByZXF1aXJlKCcuLi90cmFuc3BvcnQvaHR0cC10cmFuc3BvcnQtZmFjdG9yeScpO1xuIHZhciBydXRpbCA9IHJlcXVpcmUoJy4uL3V0aWwvcnVuLXV0aWwnKTtcblxuIG1vZHVsZS5leHBvcnRzID0gZnVuY3Rpb24gKGNvbmZpZykge1xuICAgICB2YXIgZGVmYXVsdHMgPSB7XG4gICAgICAgIC8qKlxuICAgICAgICAgKiBUaGUgcnVucyBvYmplY3QgdG8gd2hpY2ggdGhlIHZhcmlhYmxlIGZpbHRlcnMgYXBwbHkuIERlZmF1bHRzIHRvIG51bGwuXG4gICAgICAgICAqIEB0eXBlIHtydW5TZXJ2aWNlfVxuICAgICAgICAgKi9cbiAgICAgICAgIHJ1blNlcnZpY2U6IG51bGxcbiAgICAgfTtcbiAgICAgdmFyIHNlcnZpY2VPcHRpb25zID0gJC5leHRlbmQoe30sIGRlZmF1bHRzLCBjb25maWcpO1xuXG4gICAgIHZhciBnZXRVUkwgPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgIC8vVE9ETzogUmVwbGFjZSB3aXRoIGdldEN1cnJlbnRjb25maWcgaW5zdGVhZD9cbiAgICAgICAgIHJldHVybiBzZXJ2aWNlT3B0aW9ucy5ydW5TZXJ2aWNlLnVybENvbmZpZy5nZXRGaWx0ZXJVUkwoKSArICd2YXJpYWJsZXMvJztcbiAgICAgfTtcblxuICAgICB2YXIgYWRkQXV0b1Jlc3RvcmVIZWFkZXIgPSBmdW5jdGlvbiAob3B0aW9ucykge1xuICAgICAgICAgcmV0dXJuIHNlcnZpY2VPcHRpb25zLnJ1blNlcnZpY2UudXJsQ29uZmlnLmFkZEF1dG9SZXN0b3JlSGVhZGVyKG9wdGlvbnMpO1xuICAgICB9O1xuXG4gICAgIHZhciBodHRwT3B0aW9ucyA9IHtcbiAgICAgICAgIHVybDogZ2V0VVJMXG4gICAgIH07XG4gICAgIGlmIChzZXJ2aWNlT3B0aW9ucy50b2tlbikge1xuICAgICAgICAgaHR0cE9wdGlvbnMuaGVhZGVycyA9IHtcbiAgICAgICAgICAgICBBdXRob3JpemF0aW9uOiAnQmVhcmVyICcgKyBzZXJ2aWNlT3B0aW9ucy50b2tlblxuICAgICAgICAgfTtcbiAgICAgfVxuICAgICB2YXIgaHR0cCA9IG5ldyBUcmFuc3BvcnRGYWN0b3J5KGh0dHBPcHRpb25zKTtcbiAgICAgaHR0cC5zcGxpdEdldCA9IHJ1dGlsLnNwbGl0R2V0RmFjdG9yeShodHRwT3B0aW9ucyk7XG5cbiAgICAgdmFyIHB1YmxpY0FQSSA9IHtcblxuICAgICAgICAvKipcbiAgICAgICAgICogR2V0IHZhbHVlcyBmb3IgYSB2YXJpYWJsZS5cbiAgICAgICAgICpcbiAgICAgICAgICogKipFeGFtcGxlKipcbiAgICAgICAgICpcbiAgICAgICAgICogICAgICB2cy5sb2FkKCdzYW1wbGVfaW50JylcbiAgICAgICAgICogICAgICAgICAgLnRoZW4oZnVuY3Rpb24odmFsKXtcbiAgICAgICAgICogICAgICAgICAgICAgIC8vIHZhbCBjb250YWlucyB0aGUgdmFsdWUgb2Ygc2FtcGxlX2ludFxuICAgICAgICAgKiAgICAgICAgICB9KTtcbiAgICAgICAgICpcbiAgICAgICAgICogKipQYXJhbWV0ZXJzKipcbiAgICAgICAgICogQHBhcmFtIHtTdHJpbmd9IHZhcmlhYmxlIE5hbWUgb2YgdmFyaWFibGUgdG8gbG9hZC5cbiAgICAgICAgICogQHBhcmFtIHtPYmplY3R9IG91dHB1dE1vZGlmaWVyIChPcHRpb25hbCkgQXZhaWxhYmxlIGZpZWxkcyBpbmNsdWRlOiBgc3RhcnRyZWNvcmRgLCBgZW5kcmVjb3JkYCwgYHNvcnRgLCBhbmQgYGRpcmVjdGlvbmAgKGBhc2NgIG9yIGBkZXNjYCkuXG4gICAgICAgICAqIEBwYXJhbSB7T2JqZWN0fSBvcHRpb25zIChPcHRpb25hbCkgT3ZlcnJpZGVzIGZvciBjb25maWd1cmF0aW9uIG9wdGlvbnMuXG4gICAgICAgICAqIEByZXR1cm4ge1Byb21pc2V9XG4gICAgICAgICAqL1xuICAgICAgICAgbG9hZDogZnVuY3Rpb24gKHZhcmlhYmxlLCBvdXRwdXRNb2RpZmllciwgb3B0aW9ucykge1xuICAgICAgICAgICAgIHZhciBodHRwT3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LCBzZXJ2aWNlT3B0aW9ucywgb3B0aW9ucyk7XG4gICAgICAgICAgICAgaHR0cE9wdGlvbnMgPSBhZGRBdXRvUmVzdG9yZUhlYWRlcihodHRwT3B0aW9ucyk7XG4gICAgICAgICAgICAgcmV0dXJuIGh0dHAuZ2V0KG91dHB1dE1vZGlmaWVyLCAkLmV4dGVuZCh7fSwgaHR0cE9wdGlvbnMsIHtcbiAgICAgICAgICAgICAgICAgdXJsOiBnZXRVUkwoKSArIHZhcmlhYmxlICsgJy8nXG4gICAgICAgICAgICAgfSkpO1xuICAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgICogUmV0dXJucyBwYXJ0aWN1bGFyIHZhcmlhYmxlcywgYmFzZWQgb24gY29uZGl0aW9ucyBzcGVjaWZpZWQgaW4gdGhlIGBxdWVyeWAgb2JqZWN0LlxuICAgICAgICAgKlxuICAgICAgICAgKiAqKkV4YW1wbGUqKlxuICAgICAgICAgKlxuICAgICAgICAgKiAgICAgIHZzLnF1ZXJ5KFsncHJpY2UnLCAnc2FsZXMnXSlcbiAgICAgICAgICogICAgICAgICAgLnRoZW4oZnVuY3Rpb24odmFsKSB7XG4gICAgICAgICAqICAgICAgICAgICAgICAvLyB2YWwgaXMgYW4gb2JqZWN0IHdpdGggdGhlIHZhbHVlcyBvZiB0aGUgcmVxdWVzdGVkIHZhcmlhYmxlczogdmFsLnByaWNlLCB2YWwuc2FsZXNcbiAgICAgICAgICogICAgICAgICAgfSk7XG4gICAgICAgICAqXG4gICAgICAgICAqICAgICAgdnMucXVlcnkoeyBpbmNsdWRlOlsncHJpY2UnLCAnc2FsZXMnXSB9KTtcbiAgICAgICAgICpcbiAgICAgICAgICogKipQYXJhbWV0ZXJzKipcbiAgICAgICAgICogQHBhcmFtIHtPYmplY3R8QXJyYXl9IHF1ZXJ5IFRoZSBuYW1lcyBvZiB0aGUgdmFyaWFibGVzIHJlcXVlc3RlZC5cbiAgICAgICAgICogQHBhcmFtIHtPYmplY3R9IG91dHB1dE1vZGlmaWVyIChPcHRpb25hbCkgQXZhaWxhYmxlIGZpZWxkcyBpbmNsdWRlOiBgc3RhcnRyZWNvcmRgLCBgZW5kcmVjb3JkYCwgYHNvcnRgLCBhbmQgYGRpcmVjdGlvbmAgKGBhc2NgIG9yIGBkZXNjYCkuXG4gICAgICAgICAqIEBwYXJhbSB7T2JqZWN0fSBvcHRpb25zIChPcHRpb25hbCkgT3ZlcnJpZGVzIGZvciBjb25maWd1cmF0aW9uIG9wdGlvbnMuXG4gICAgICAgICAqIEByZXR1cm4ge1Byb21pc2V9XG4gICAgICAgICAqL1xuICAgICAgICAgcXVlcnk6IGZ1bmN0aW9uIChxdWVyeSwgb3V0cHV0TW9kaWZpZXIsIG9wdGlvbnMpIHtcbiAgICAgICAgICAgIC8vUXVlcnkgYW5kIG91dHB1dE1vZGlmaWVyIGFyZSBib3RoIHF1ZXJ5c3RyaW5ncyBpbiB0aGUgdXJsOyBvbmx5IGNhbGxpbmcgdGhlbSBvdXQgc2VwYXJhdGVseSBoZXJlIHRvIGJlIGNvbnNpc3RlbnQgd2l0aCB0aGUgb3RoZXIgY2FsbHNcbiAgICAgICAgICAgICB2YXIgaHR0cE9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSwgc2VydmljZU9wdGlvbnMsIG9wdGlvbnMpO1xuICAgICAgICAgICAgIGh0dHBPcHRpb25zID0gYWRkQXV0b1Jlc3RvcmVIZWFkZXIoaHR0cE9wdGlvbnMpO1xuXG4gICAgICAgICAgICAgaWYgKCQuaXNBcnJheShxdWVyeSkpIHtcbiAgICAgICAgICAgICAgICAgcXVlcnkgPSB7IGluY2x1ZGU6IHF1ZXJ5IH07XG4gICAgICAgICAgICAgfVxuICAgICAgICAgICAgICQuZXh0ZW5kKHF1ZXJ5LCBvdXRwdXRNb2RpZmllcik7XG4gICAgICAgICAgICAgcmV0dXJuIGh0dHAuc3BsaXRHZXQocXVlcnksIGh0dHBPcHRpb25zKTtcbiAgICAgICAgIH0sXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIFNhdmUgdmFsdWVzIHRvIG1vZGVsIHZhcmlhYmxlcy4gT3ZlcndyaXRlcyBleGlzdGluZyB2YWx1ZXMuIE5vdGUgdGhhdCB5b3UgY2FuIG9ubHkgdXBkYXRlIG1vZGVsIHZhcmlhYmxlcyBpZiB0aGUgcnVuIGlzIFtpbiBtZW1vcnldKC4uLy4uLy4uL3J1bl9wZXJzaXN0ZW5jZS8jcnVucy1pbi1tZW1vcnkpLiAoQW4gYWx0ZXJuYXRlIHdheSB0byB1cGRhdGUgbW9kZWwgdmFyaWFibGVzIGlzIHRvIGNhbGwgYSBtZXRob2QgZnJvbSB0aGUgbW9kZWwgYW5kIG1ha2Ugc3VyZSB0aGF0IHRoZSBtZXRob2QgcGVyc2lzdHMgdGhlIHZhcmlhYmxlcy4gU2VlIGBkb2AsIGBzZXJpYWxgLCBhbmQgYHBhcmFsbGVsYCBpbiB0aGUgW1J1biBBUEkgU2VydmljZV0oLi4vcnVuLWFwaS1zZXJ2aWNlLykgZm9yIGNhbGxpbmcgbWV0aG9kcyBmcm9tIHRoZSBtb2RlbC4pXG4gICAgICAgICAqXG4gICAgICAgICAqICoqRXhhbXBsZSoqXG4gICAgICAgICAqXG4gICAgICAgICAqICAgICAgdnMuc2F2ZSgncHJpY2UnLCA0KTtcbiAgICAgICAgICogICAgICB2cy5zYXZlKHsgcHJpY2U6IDQsIHF1YW50aXR5OiA1LCBwcm9kdWN0czogWzIsMyw0XSB9KTtcbiAgICAgICAgICpcbiAgICAgICAgICogKipQYXJhbWV0ZXJzKipcbiAgICAgICAgICogQHBhcmFtIHtPYmplY3R8U3RyaW5nfSB2YXJpYWJsZSBBbiBvYmplY3QgY29tcG9zZWQgb2YgdGhlIG1vZGVsIHZhcmlhYmxlcyBhbmQgdGhlIHZhbHVlcyB0byBzYXZlLiBBbHRlcm5hdGl2ZWx5LCBhIHN0cmluZyB3aXRoIHRoZSBuYW1lIG9mIHRoZSB2YXJpYWJsZS5cbiAgICAgICAgICogQHBhcmFtIHtPYmplY3R9IHZhbCAoT3B0aW9uYWwpIElmIHBhc3NpbmcgYSBzdHJpbmcgZm9yIGB2YXJpYWJsZWAsIHVzZSB0aGlzIGFyZ3VtZW50IGZvciB0aGUgdmFsdWUgdG8gc2F2ZS5cbiAgICAgICAgICogQHBhcmFtIHtPYmplY3R9IG9wdGlvbnMgKE9wdGlvbmFsKSBPdmVycmlkZXMgZm9yIGNvbmZpZ3VyYXRpb24gb3B0aW9ucy5cbiAgICAgICAgICogQHJldHVybiB7UHJvbWlzZX1cbiAgICAgICAgICovXG4gICAgICAgICBzYXZlOiBmdW5jdGlvbiAodmFyaWFibGUsIHZhbCwgb3B0aW9ucykge1xuICAgICAgICAgICAgIHZhciBhdHRycztcbiAgICAgICAgICAgICBpZiAodHlwZW9mIHZhcmlhYmxlID09PSAnb2JqZWN0Jykge1xuICAgICAgICAgICAgICAgICBhdHRycyA9IHZhcmlhYmxlO1xuICAgICAgICAgICAgICAgICBvcHRpb25zID0gdmFsO1xuICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgIChhdHRycyA9IHt9KVt2YXJpYWJsZV0gPSB2YWw7XG4gICAgICAgICAgICAgfVxuICAgICAgICAgICAgIHZhciBodHRwT3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LCBzZXJ2aWNlT3B0aW9ucywgb3B0aW9ucyk7XG5cbiAgICAgICAgICAgICByZXR1cm4gaHR0cC5wYXRjaC5jYWxsKHRoaXMsIGF0dHJzLCBodHRwT3B0aW9ucyk7XG4gICAgICAgICB9XG5cbiAgICAgICAgLy8gTm90IEF2YWlsYWJsZSB1bnRpbCB1bmRlcmx5aW5nIEFQSSBzdXBwb3J0cyBQVVQuIE90aGVyd2lzZSBzYXZlIHdvdWxkIGJlIFBVVCBhbmQgbWVyZ2Ugd291bGQgYmUgUEFUQ0hcbiAgICAgICAgLy8gKlxuICAgICAgICAvLyAgKiBTYXZlIHZhbHVlcyB0byB0aGUgYXBpLiBNZXJnZXMgYXJyYXlzLCBidXQgb3RoZXJ3aXNlIHNhbWUgYXMgc2F2ZVxuICAgICAgICAvLyAgKiBAcGFyYW0ge09iamVjdHxTdHJpbmd9IHZhcmlhYmxlIE9iamVjdCB3aXRoIGF0dHJpYnV0ZXMsIG9yIHN0cmluZyBrZXlcbiAgICAgICAgLy8gICogQHBhcmFtIHtPYmplY3R9IHZhbCBPcHRpb25hbCBpZiBwcmV2IHBhcmFtZXRlciB3YXMgYSBzdHJpbmcsIHNldCB2YWx1ZSBoZXJlXG4gICAgICAgIC8vICAqIEBwYXJhbSB7T2JqZWN0fSBvcHRpb25zIE92ZXJyaWRlcyBmb3IgY29uZmlndXJhdGlvbiBvcHRpb25zXG4gICAgICAgIC8vICAqXG4gICAgICAgIC8vICAqIEBleGFtcGxlXG4gICAgICAgIC8vICAqICAgICB2cy5tZXJnZSh7IHByaWNlOiA0LCBxdWFudGl0eTogNSwgcHJvZHVjdHM6IFsyLDMsNF0gfSlcbiAgICAgICAgLy8gICogICAgIHZzLm1lcmdlKCdwcmljZScsIDQpO1xuXG4gICAgICAgIC8vIG1lcmdlOiBmdW5jdGlvbiAodmFyaWFibGUsIHZhbCwgb3B0aW9ucykge1xuICAgICAgICAvLyAgICAgdmFyIGF0dHJzO1xuICAgICAgICAvLyAgICAgaWYgKHR5cGVvZiB2YXJpYWJsZSA9PT0gJ29iamVjdCcpIHtcbiAgICAgICAgLy8gICAgICAgYXR0cnMgPSB2YXJpYWJsZTtcbiAgICAgICAgLy8gICAgICAgb3B0aW9ucyA9IHZhbDtcbiAgICAgICAgLy8gICAgIH0gZWxzZSB7XG4gICAgICAgIC8vICAgICAgIChhdHRycyA9IHt9KVt2YXJpYWJsZV0gPSB2YWw7XG4gICAgICAgIC8vICAgICB9XG4gICAgICAgIC8vICAgICB2YXIgaHR0cE9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSwgc2VydmljZU9wdGlvbnMsIG9wdGlvbnMpO1xuXG4gICAgICAgIC8vICAgICByZXR1cm4gaHR0cC5wYXRjaC5jYWxsKHRoaXMsIGF0dHJzLCBodHRwT3B0aW9ucyk7XG4gICAgICAgIC8vIH1cbiAgICAgfTtcbiAgICAgJC5leHRlbmQodGhpcywgcHVibGljQVBJKTtcbiB9O1xuIiwiLyoqXG4gKiAjIyBXb3JsZCBBUEkgQWRhcHRlclxuICpcbiAqIEEgW3J1bl0oLi4vLi4vLi4vZ2xvc3NhcnkvI3J1bikgaXMgYSBjb2xsZWN0aW9uIG9mIGVuZCB1c2VyIGludGVyYWN0aW9ucyB3aXRoIGEgcHJvamVjdCBhbmQgaXRzIG1vZGVsIC0tIGluY2x1ZGluZyBzZXR0aW5nIHZhcmlhYmxlcywgbWFraW5nIGRlY2lzaW9ucywgYW5kIGNhbGxpbmcgb3BlcmF0aW9ucy4gRm9yIGJ1aWxkaW5nIG11bHRpcGxheWVyIHNpbXVsYXRpb25zIHlvdSB0eXBpY2FsbHkgd2FudCBtdWx0aXBsZSBlbmQgdXNlcnMgdG8gc2hhcmUgdGhlIHNhbWUgc2V0IG9mIGludGVyYWN0aW9ucywgYW5kIHdvcmsgd2l0aGluIGEgY29tbW9uIHN0YXRlLiBFcGljZW50ZXIgYWxsb3dzIHlvdSB0byBjcmVhdGUgXCJ3b3JsZHNcIiB0byBoYW5kbGUgc3VjaCBjYXNlcy4gT25seSBbdGVhbSBwcm9qZWN0c10oLi4vLi4vLi4vZ2xvc3NhcnkvI3RlYW0pIGNhbiBiZSBtdWx0aXBsYXllci5cbiAqXG4gKiBUaGUgV29ybGQgQVBJIEFkYXB0ZXIgYWxsb3dzIHlvdSB0byBjcmVhdGUsIGFjY2VzcywgYW5kIG1hbmlwdWxhdGUgbXVsdGlwbGF5ZXIgd29ybGRzIHdpdGhpbiB5b3VyIEVwaWNlbnRlciBwcm9qZWN0LiBZb3UgY2FuIHVzZSB0aGlzIHRvIGFkZCBhbmQgcmVtb3ZlIGVuZCB1c2VycyBmcm9tIHRoZSB3b3JsZCwgYW5kIHRvIGNyZWF0ZSwgYWNjZXNzLCBhbmQgcmVtb3ZlIHRoZWlyIHJ1bnMuIEJlY2F1c2Ugb2YgdGhpcywgdHlwaWNhbGx5IHRoZSBXb3JsZCBBZGFwdGVyIGlzIHVzZWQgZm9yIGZhY2lsaXRhdG9yIHBhZ2VzIGluIHlvdXIgcHJvamVjdC4gKFRoZSByZWxhdGVkIFtXb3JsZCBNYW5hZ2VyXSguLi93b3JsZC1tYW5hZ2VyLykgcHJvdmlkZXMgYW4gZWFzeSB3YXkgdG8gYWNjZXNzIHJ1bnMgYW5kIHdvcmxkcyBmb3IgcGFydGljdWxhciBlbmQgdXNlcnMsIHNvIGlzIHR5cGljYWxseSB1c2VkIGluIHBhZ2VzIHRoYXQgZW5kIHVzZXJzIHdpbGwgaW50ZXJhY3Qgd2l0aC4pXG4gKlxuICogQXMgd2l0aCBhbGwgdGhlIG90aGVyIFtBUEkgQWRhcHRlcnNdKC4uLy4uLyksIGFsbCBtZXRob2RzIHRha2UgaW4gYW4gXCJvcHRpb25zXCIgb2JqZWN0IGFzIHRoZSBsYXN0IHBhcmFtZXRlci4gVGhlIG9wdGlvbnMgY2FuIGJlIHVzZWQgdG8gZXh0ZW5kL292ZXJyaWRlIHRoZSBXb3JsZCBBUEkgU2VydmljZSBkZWZhdWx0cy5cbiAqXG4gKiBUbyB1c2UgdGhlIFdvcmxkIEFkYXB0ZXIsIGluc3RhbnRpYXRlIGl0IGFuZCB0aGVuIGFjY2VzcyB0aGUgbWV0aG9kcyBwcm92aWRlZC4gSW5zdGFudGlhdGluZyByZXF1aXJlcyB0aGUgYWNjb3VudCBpZCAoKipUZWFtIElEKiogaW4gdGhlIEVwaWNlbnRlciB1c2VyIGludGVyZmFjZSksIHByb2plY3QgaWQgKCoqUHJvamVjdCBJRCoqKSwgYW5kIGdyb3VwICgqKkdyb3VwIE5hbWUqKikuXG4gKlxuICogICAgICAgdmFyIHdhID0gbmV3IEYuc2VydmljZS5Xb3JsZCh7XG4gKiAgICAgICAgICBhY2NvdW50OiAnYWNtZS1zaW11bGF0aW9ucycsXG4gKiAgICAgICAgICBwcm9qZWN0OiAnc3VwcGx5LWNoYWluLWdhbWUnLFxuICogICAgICAgICAgZ3JvdXA6ICd0ZWFtMScgfSk7XG4gKiAgICAgICB3YS5jcmVhdGUoKVxuICogICAgICAgICAgLnRoZW4oZnVuY3Rpb24od29ybGQpIHtcbiAqICAgICAgICAgICAgICAvLyBjYWxsIG1ldGhvZHMsIGUuZy4gd2EuYWRkVXNlcnMoKVxuICogICAgICAgICAgfSk7XG4gKi9cblxuJ3VzZSBzdHJpY3QnO1xuXG52YXIgQ29uZmlnU2VydmljZSA9IHJlcXVpcmUoJy4vY29uZmlndXJhdGlvbi1zZXJ2aWNlJyk7XG4vLyB2YXIgcXV0aWwgPSByZXF1aXJlKCcuLi91dGlsL3F1ZXJ5LXV0aWwnKTtcbnZhciBUcmFuc3BvcnRGYWN0b3J5ID0gcmVxdWlyZSgnLi4vdHJhbnNwb3J0L2h0dHAtdHJhbnNwb3J0LWZhY3RvcnknKTtcbnZhciBTZXNzaW9uTWFuYWdlciA9IHJlcXVpcmUoJy4uL3N0b3JlL3Nlc3Npb24tbWFuYWdlcicpO1xudmFyIF9waWNrID0gcmVxdWlyZSgnLi4vdXRpbC9vYmplY3QtdXRpbCcpLl9waWNrO1xuXG52YXIgYXBpQmFzZSA9ICdtdWx0aXBsYXllci8nO1xudmFyIGFzc2lnbm1lbnRFbmRwb2ludCA9IGFwaUJhc2UgKyAnYXNzaWduJztcbnZhciBhcGlFbmRwb2ludCA9IGFwaUJhc2UgKyAnd29ybGQnO1xudmFyIHByb2plY3RFbmRwb2ludCA9IGFwaUJhc2UgKyAncHJvamVjdCc7XG5cbm1vZHVsZS5leHBvcnRzID0gZnVuY3Rpb24gKGNvbmZpZykge1xuICAgIHZhciBkZWZhdWx0cyA9IHtcbiAgICAgICAgLyoqXG4gICAgICAgICAqIEZvciBwcm9qZWN0cyB0aGF0IHJlcXVpcmUgYXV0aGVudGljYXRpb24sIHBhc3MgaW4gdGhlIHVzZXIgYWNjZXNzIHRva2VuIChkZWZhdWx0cyB0byBlbXB0eSBzdHJpbmcpLiBJZiB0aGUgdXNlciBpcyBhbHJlYWR5IGxvZ2dlZCBpbiB0byBFcGljZW50ZXIsIHRoZSB1c2VyIGFjY2VzcyB0b2tlbiBpcyBhbHJlYWR5IHNldCBpbiBhIGNvb2tpZSBhbmQgYXV0b21hdGljYWxseSBsb2FkZWQgZnJvbSB0aGVyZS4gKFNlZSBbbW9yZSBiYWNrZ3JvdW5kIG9uIGFjY2VzcyB0b2tlbnNdKC4uLy4uLy4uL3Byb2plY3RfYWNjZXNzLykpLlxuICAgICAgICAgKiBAc2VlIFtBdXRoZW50aWNhdGlvbiBBUEkgU2VydmljZV0oLi4vYXV0aC1hcGktc2VydmljZS8pIGZvciBnZXR0aW5nIHRva2Vucy5cbiAgICAgICAgICogQHR5cGUge1N0cmluZ31cbiAgICAgICAgICovXG4gICAgICAgIHRva2VuOiB1bmRlZmluZWQsXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIFRoZSBwcm9qZWN0IGlkLiBJZiBsZWZ0IHVuZGVmaW5lZCwgdGFrZW4gZnJvbSB0aGUgVVJMLlxuICAgICAgICAgKiBAdHlwZSB7U3RyaW5nfVxuICAgICAgICAgKi9cbiAgICAgICAgcHJvamVjdDogdW5kZWZpbmVkLFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBUaGUgYWNjb3VudCBpZC4gSW4gdGhlIEVwaWNlbnRlciBVSSwgdGhpcyBpcyB0aGUgKipUZWFtIElEKiogKGZvciB0ZWFtIHByb2plY3RzKS4gSWYgbGVmdCB1bmRlZmluZWQsIHRha2VuIGZyb20gdGhlIFVSTC5cbiAgICAgICAgICogQHR5cGUge1N0cmluZ31cbiAgICAgICAgICovXG4gICAgICAgIGFjY291bnQ6IHVuZGVmaW5lZCxcblxuICAgICAgICAvKipcbiAgICAgICAgICogVGhlIGdyb3VwIG5hbWUuIERlZmF1bHRzIHRvIHVuZGVmaW5lZC5cbiAgICAgICAgICogQHR5cGUge1N0cmluZ31cbiAgICAgICAgICovXG4gICAgICAgIGdyb3VwOiB1bmRlZmluZWQsXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIFRoZSBtb2RlbCBmaWxlIHRvIHVzZSB0byBjcmVhdGUgcnVucyBpbiB0aGlzIHdvcmxkLiBEZWZhdWx0cyB0byB1bmRlZmluZWQuXG4gICAgICAgICAqIEB0eXBlIHtTdHJpbmd9XG4gICAgICAgICAqL1xuICAgICAgICBtb2RlbDogdW5kZWZpbmVkLFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBDcml0ZXJpYSBieSB3aGljaCB0byBmaWx0ZXIgd29ybGQuIEN1cnJlbnRseSBvbmx5IHN1cHBvcnRzIHdvcmxkLWlkcyBhcyBmaWx0ZXJzLlxuICAgICAgICAgKiBAdHlwZSB7U3RyaW5nfVxuICAgICAgICAgKi9cbiAgICAgICAgZmlsdGVyOiAnJyxcblxuICAgICAgICAvKipcbiAgICAgICAgICogQ29udmVuaWVuY2UgYWxpYXMgZm9yIGZpbHRlclxuICAgICAgICAgKiBAdHlwZSB7U3RyaW5nfVxuICAgICAgICAgKi9cbiAgICAgICAgaWQ6ICcnLFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBPcHRpb25zIHRvIHBhc3Mgb24gdG8gdGhlIHVuZGVybHlpbmcgdHJhbnNwb3J0IGxheWVyLiBBbGwganF1ZXJ5LmFqYXggb3B0aW9ucyBhdCBodHRwOi8vYXBpLmpxdWVyeS5jb20valF1ZXJ5LmFqYXgvIGFyZSBhdmFpbGFibGUuIERlZmF1bHRzIHRvIGVtcHR5IG9iamVjdC5cbiAgICAgICAgICogQHR5cGUge09iamVjdH1cbiAgICAgICAgICovXG4gICAgICAgIHRyYW5zcG9ydDoge30sXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIENhbGxlZCB3aGVuIHRoZSBjYWxsIGNvbXBsZXRlcyBzdWNjZXNzZnVsbHkuIERlZmF1bHRzIHRvIGAkLm5vb3BgLlxuICAgICAgICAgKiBAdHlwZSB7ZnVuY3Rpb259XG4gICAgICAgICAqL1xuICAgICAgICBzdWNjZXNzOiAkLm5vb3AsXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIENhbGxlZCB3aGVuIHRoZSBjYWxsIGZhaWxzLiBEZWZhdWx0cyB0byBgJC5ub29wYC5cbiAgICAgICAgICogQHR5cGUge2Z1bmN0aW9ufVxuICAgICAgICAgKi9cbiAgICAgICAgZXJyb3I6ICQubm9vcFxuICAgIH07XG5cbiAgICB0aGlzLnNlc3Npb25NYW5hZ2VyID0gbmV3IFNlc3Npb25NYW5hZ2VyKCk7XG4gICAgdmFyIHNlcnZpY2VPcHRpb25zID0gdGhpcy5zZXNzaW9uTWFuYWdlci5nZXRNZXJnZWRPcHRpb25zKGRlZmF1bHRzLCBjb25maWcpO1xuICAgIGlmIChzZXJ2aWNlT3B0aW9ucy5pZCkge1xuICAgICAgICBzZXJ2aWNlT3B0aW9ucy5maWx0ZXIgPSBzZXJ2aWNlT3B0aW9ucy5pZDtcbiAgICB9XG5cbiAgICB2YXIgdXJsQ29uZmlnID0gbmV3IENvbmZpZ1NlcnZpY2Uoc2VydmljZU9wdGlvbnMpLmdldCgnc2VydmVyJyk7XG5cbiAgICBpZiAoIXNlcnZpY2VPcHRpb25zLmFjY291bnQpIHtcbiAgICAgICAgc2VydmljZU9wdGlvbnMuYWNjb3VudCA9IHVybENvbmZpZy5hY2NvdW50UGF0aDtcbiAgICB9XG5cbiAgICBpZiAoIXNlcnZpY2VPcHRpb25zLnByb2plY3QpIHtcbiAgICAgICAgc2VydmljZU9wdGlvbnMucHJvamVjdCA9IHVybENvbmZpZy5wcm9qZWN0UGF0aDtcbiAgICB9XG5cbiAgICB2YXIgdHJhbnNwb3J0T3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LCBzZXJ2aWNlT3B0aW9ucy50cmFuc3BvcnQsIHtcbiAgICAgICAgdXJsOiB1cmxDb25maWcuZ2V0QVBJUGF0aChhcGlFbmRwb2ludClcbiAgICB9KTtcblxuICAgIGlmIChzZXJ2aWNlT3B0aW9ucy50b2tlbikge1xuICAgICAgICB0cmFuc3BvcnRPcHRpb25zLmhlYWRlcnMgPSB7XG4gICAgICAgICAgICBBdXRob3JpemF0aW9uOiAnQmVhcmVyICcgKyBzZXJ2aWNlT3B0aW9ucy50b2tlblxuICAgICAgICB9O1xuICAgIH1cblxuICAgIHZhciBodHRwID0gbmV3IFRyYW5zcG9ydEZhY3RvcnkodHJhbnNwb3J0T3B0aW9ucyk7XG5cbiAgICB2YXIgc2V0SWRGaWx0ZXJPclRocm93RXJyb3IgPSBmdW5jdGlvbiAob3B0aW9ucykge1xuICAgICAgICBpZiAob3B0aW9ucy5pZCkge1xuICAgICAgICAgICAgc2VydmljZU9wdGlvbnMuZmlsdGVyID0gb3B0aW9ucy5pZDtcbiAgICAgICAgfVxuICAgICAgICBpZiAob3B0aW9ucy5maWx0ZXIpIHtcbiAgICAgICAgICAgIHNlcnZpY2VPcHRpb25zLmZpbHRlciA9IG9wdGlvbnMuZmlsdGVyO1xuICAgICAgICB9XG4gICAgICAgIGlmICghc2VydmljZU9wdGlvbnMuZmlsdGVyKSB7XG4gICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ05vIHdvcmxkIGlkIHNwZWNpZmllZCB0byBhcHBseSBvcGVyYXRpb25zIGFnYWluc3QuIFRoaXMgY291bGQgaGFwcGVuIGlmIHRoZSB1c2VyIGlzIG5vdCBhc3NpZ25lZCB0byBhIHdvcmxkIGFuZCBpcyB0cnlpbmcgdG8gd29yayB3aXRoIHJ1bnMgZnJvbSB0aGF0IHdvcmxkLicpO1xuICAgICAgICB9XG4gICAgfTtcblxuICAgIHZhciB2YWxpZGF0ZU1vZGVsT3JUaHJvd0Vycm9yID0gZnVuY3Rpb24gKG9wdGlvbnMpIHtcbiAgICAgICAgaWYgKCFvcHRpb25zLm1vZGVsKSB7XG4gICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ05vIG1vZGVsIHNwZWNpZmllZCB0byBnZXQgdGhlIGN1cnJlbnQgcnVuJyk7XG4gICAgICAgIH1cbiAgICB9O1xuXG4gICAgdmFyIHB1YmxpY0FQSSA9IHtcblxuICAgICAgICAvKipcbiAgICAgICAgKiBDcmVhdGVzIGEgbmV3IFdvcmxkLlxuICAgICAgICAqXG4gICAgICAgICogVXNpbmcgdGhpcyBtZXRob2QgaXMgcmFyZS4gSXQgaXMgbW9yZSBjb21tb24gdG8gY3JlYXRlIHdvcmxkcyBhdXRvbWF0aWNhbGx5IHdoaWxlIHlvdSBgYXV0b0Fzc2lnbigpYCBlbmQgdXNlcnMgdG8gd29ybGRzLiAoSW4gdGhpcyBjYXNlLCBjb25maWd1cmF0aW9uIGRhdGEgZm9yIHRoZSB3b3JsZCwgc3VjaCBhcyB0aGUgcm9sZXMsIGFyZSByZWFkIGZyb20gdGhlIHByb2plY3QtbGV2ZWwgd29ybGQgY29uZmlndXJhdGlvbiBpbmZvcm1hdGlvbiwgZm9yIGV4YW1wbGUgYnkgYGdldFByb2plY3RTZXR0aW5ncygpYC4pXG4gICAgICAgICpcbiAgICAgICAgKiAgKipFeGFtcGxlKipcbiAgICAgICAgKlxuICAgICAgICAqICAgICAgdmFyIHdhID0gbmV3IEYuc2VydmljZS5Xb3JsZCh7XG4gICAgICAgICogICAgICAgICAgIGFjY291bnQ6ICdhY21lLXNpbXVsYXRpb25zJyxcbiAgICAgICAgKiAgICAgICAgICAgcHJvamVjdDogJ3N1cHBseS1jaGFpbi1nYW1lJyxcbiAgICAgICAgKiAgICAgICAgICAgZ3JvdXA6ICd0ZWFtMScgfSk7XG4gICAgICAgICogICAgICB3YS5jcmVhdGUoe1xuICAgICAgICAqICAgICAgICAgICByb2xlczogWydWUCBNYXJrZXRpbmcnLCAnVlAgU2FsZXMnLCAnVlAgRW5naW5lZXJpbmcnXVxuICAgICAgICAqICAgICAgIH0pO1xuICAgICAgICAqXG4gICAgICAgICogICoqUGFyYW1ldGVycyoqXG4gICAgICAgICogQHBhcmFtIHtvYmplY3R9IHBhcmFtcyBQYXJhbWV0ZXJzIHRvIGNyZWF0ZSB0aGUgd29ybGQuXG4gICAgICAgICogQHBhcmFtIHtzdHJpbmd9IHBhcmFtcy5ncm91cCAoT3B0aW9uYWwpIFRoZSAqKkdyb3VwIE5hbWUqKiB0byBjcmVhdGUgdGhpcyB3b3JsZCB1bmRlci4gT25seSBlbmQgdXNlcnMgaW4gdGhpcyBncm91cCBhcmUgZWxpZ2libGUgdG8gam9pbiB0aGUgd29ybGQuIE9wdGlvbmFsIGhlcmU7IHJlcXVpcmVkIHdoZW4gaW5zdGFudGlhdGluZyB0aGUgc2VydmljZSAoYG5ldyBGLnNlcnZpY2UuV29ybGQoKWApLlxuICAgICAgICAqIEBwYXJhbSB7b2JqZWN0fSBwYXJhbXMucm9sZXMgKE9wdGlvbmFsKSBUaGUgbGlzdCBvZiByb2xlcyAoc3RyaW5ncykgZm9yIHRoaXMgd29ybGQuIFNvbWUgd29ybGRzIGhhdmUgc3BlY2lmaWMgcm9sZXMgdGhhdCAqKm11c3QqKiBiZSBmaWxsZWQgYnkgZW5kIHVzZXJzLiBMaXN0aW5nIHRoZSByb2xlcyBhbGxvd3MgeW91IHRvIGF1dG9hc3NpZ24gdXNlcnMgdG8gd29ybGRzIGFuZCBlbnN1cmUgdGhhdCBhbGwgcm9sZXMgYXJlIGZpbGxlZCBpbiBlYWNoIHdvcmxkLlxuICAgICAgICAqIEBwYXJhbSB7b2JqZWN0fSBwYXJhbXMub3B0aW9uYWxSb2xlcyAoT3B0aW9uYWwpIFRoZSBsaXN0IG9mIG9wdGlvbmFsIHJvbGVzIChzdHJpbmdzKSBmb3IgdGhpcyB3b3JsZC4gU29tZSB3b3JsZHMgaGF2ZSBzcGVjaWZpYyByb2xlcyB0aGF0ICoqbWF5KiogYmUgZmlsbGVkIGJ5IGVuZCB1c2Vycy4gTGlzdGluZyB0aGUgb3B0aW9uYWwgcm9sZXMgYXMgcGFydCBvZiB0aGUgd29ybGQgb2JqZWN0IGFsbG93cyB5b3UgdG8gYXV0b2Fzc2lnbiB1c2VycyB0byB3b3JsZHMgYW5kIGVuc3VyZSB0aGF0IGFsbCByb2xlcyBhcmUgZmlsbGVkIGluIGVhY2ggd29ybGQuXG4gICAgICAgICogQHBhcmFtIHtpbnRlZ2VyfSBwYXJhbXMubWluVXNlcnMgKE9wdGlvbmFsKSBUaGUgbWluaW11bSBudW1iZXIgb2YgdXNlcnMgZm9yIHRoZSB3b3JsZC4gSW5jbHVkaW5nIHRoaXMgbnVtYmVyIGFsbG93cyB5b3UgdG8gYXV0b2Fzc2lnbiBlbmQgdXNlcnMgdG8gd29ybGRzIGFuZCBlbnN1cmUgdGhhdCB0aGUgY29ycmVjdCBudW1iZXIgb2YgdXNlcnMgYXJlIGluIGVhY2ggd29ybGQuXG4gICAgICAgICogQHBhcmFtIHtvYmplY3R9IG9wdGlvbnMgKE9wdGlvbmFsKSBPcHRpb25zIG9iamVjdCB0byBvdmVycmlkZSBnbG9iYWwgb3B0aW9ucy5cbiAgICAgICAgKiBAcmV0dXJuIHtQcm9taXNlfVxuICAgICAgICAqL1xuICAgICAgICBjcmVhdGU6IGZ1bmN0aW9uIChwYXJhbXMsIG9wdGlvbnMpIHtcbiAgICAgICAgICAgIHZhciBjcmVhdGVPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sIHNlcnZpY2VPcHRpb25zLCBvcHRpb25zLCB7IHVybDogdXJsQ29uZmlnLmdldEFQSVBhdGgoYXBpRW5kcG9pbnQpIH0pO1xuICAgICAgICAgICAgdmFyIHdvcmxkQXBpUGFyYW1zID0gWydzY29wZScsICdmaWxlcycsICdyb2xlcycsICdvcHRpb25hbFJvbGVzJywgJ21pblVzZXJzJywgJ2dyb3VwJywgJ25hbWUnXTtcbiAgICAgICAgICAgIHZhciB2YWxpZFBhcmFtcyA9IF9waWNrKHNlcnZpY2VPcHRpb25zLCBbJ2FjY291bnQnLCAncHJvamVjdCcsICdncm91cCddKTtcbiAgICAgICAgICAgIC8vIHdoaXRlbGlzdCB0aGUgZmllbGRzIHRoYXQgd2UgYWN0dWFsbHkgY2FuIHNlbmQgdG8gdGhlIGFwaVxuICAgICAgICAgICAgcGFyYW1zID0gX3BpY2socGFyYW1zLCB3b3JsZEFwaVBhcmFtcyk7XG5cbiAgICAgICAgICAgIC8vIGFjY291bnQgYW5kIHByb2plY3QgZ28gaW4gdGhlIGJvZHksIG5vdCBpbiB0aGUgdXJsXG4gICAgICAgICAgICBwYXJhbXMgPSAkLmV4dGVuZCh7fSwgdmFsaWRQYXJhbXMsIHBhcmFtcyk7XG5cbiAgICAgICAgICAgIHZhciBvbGRTdWNjZXNzID0gY3JlYXRlT3B0aW9ucy5zdWNjZXNzO1xuICAgICAgICAgICAgY3JlYXRlT3B0aW9ucy5zdWNjZXNzID0gZnVuY3Rpb24gKHJlc3BvbnNlKSB7XG4gICAgICAgICAgICAgICAgc2VydmljZU9wdGlvbnMuZmlsdGVyID0gcmVzcG9uc2UuaWQ7IC8vYWxsIGZ1dHVyZSBjaGFpbmVkIGNhbGxzIHRvIG9wZXJhdGUgb24gdGhpcyBpZFxuICAgICAgICAgICAgICAgIHJldHVybiBvbGRTdWNjZXNzLmFwcGx5KHRoaXMsIGFyZ3VtZW50cyk7XG4gICAgICAgICAgICB9O1xuXG4gICAgICAgICAgICByZXR1cm4gaHR0cC5wb3N0KHBhcmFtcywgY3JlYXRlT3B0aW9ucyk7XG4gICAgICAgIH0sXG5cbiAgICAgICAgLyoqXG4gICAgICAgICogVXBkYXRlcyBhIFdvcmxkLCBmb3IgZXhhbXBsZSB0byByZXBsYWNlIHRoZSByb2xlcyBpbiB0aGUgd29ybGQuXG4gICAgICAgICpcbiAgICAgICAgKiBUeXBpY2FsbHksIHlvdSBjb21wbGV0ZSB3b3JsZCBjb25maWd1cmF0aW9uIGF0IHRoZSBwcm9qZWN0IGxldmVsLCByYXRoZXIgdGhhbiBhdCB0aGUgd29ybGQgbGV2ZWwuIEZvciBleGFtcGxlLCBlYWNoIHdvcmxkIGluIHlvdXIgcHJvamVjdCBwcm9iYWJseSBoYXMgdGhlIHNhbWUgcm9sZXMgZm9yIGVuZCB1c2Vycy4gQW5kIHlvdXIgcHJvamVjdCBpcyBwcm9iYWJseSBlaXRoZXIgY29uZmlndXJlZCBzbyB0aGF0IGFsbCBlbmQgdXNlcnMgc2hhcmUgdGhlIHNhbWUgd29ybGQgKGFuZCBydW4pLCBvciBzbWFsbGVyIHNldHMgb2YgZW5kIHVzZXJzIHNoYXJlIHdvcmxkcyDigJQgYnV0IG5vdCBib3RoLiBIb3dldmVyLCB0aGlzIG1ldGhvZCBpcyBhdmFpbGFibGUgaWYgeW91IG5lZWQgdG8gdXBkYXRlIHRoZSBjb25maWd1cmF0aW9uIG9mIGEgcGFydGljdWxhciB3b3JsZC5cbiAgICAgICAgKlxuICAgICAgICAqICAqKkV4YW1wbGUqKlxuICAgICAgICAqXG4gICAgICAgICogICAgICB2YXIgd2EgPSBuZXcgRi5zZXJ2aWNlLldvcmxkKHtcbiAgICAgICAgKiAgICAgICAgICAgYWNjb3VudDogJ2FjbWUtc2ltdWxhdGlvbnMnLFxuICAgICAgICAqICAgICAgICAgICBwcm9qZWN0OiAnc3VwcGx5LWNoYWluLWdhbWUnLFxuICAgICAgICAqICAgICAgICAgICBncm91cDogJ3RlYW0xJyB9KTtcbiAgICAgICAgKiAgICAgIHdhLmNyZWF0ZSgpXG4gICAgICAgICogICAgICAgICAgIC50aGVuKGZ1bmN0aW9uKHdvcmxkKSB7XG4gICAgICAgICogICAgICAgICAgICAgICB3YS51cGRhdGUoeyByb2xlczogWydWUCBNYXJrZXRpbmcnLCAnVlAgU2FsZXMnLCAnVlAgRW5naW5lZXJpbmcnXSB9KTtcbiAgICAgICAgKiAgICAgICAgICAgfSk7XG4gICAgICAgICpcbiAgICAgICAgKiAgKipQYXJhbWV0ZXJzKipcbiAgICAgICAgKiBAcGFyYW0ge29iamVjdH0gcGFyYW1zIFBhcmFtZXRlcnMgdG8gdXBkYXRlIHRoZSB3b3JsZC5cbiAgICAgICAgKiBAcGFyYW0ge3N0cmluZ30gcGFyYW1zLm5hbWUgQSBzdHJpbmcgaWRlbnRpZmllciBmb3IgdGhlIGxpbmtlZCBlbmQgdXNlcnMsIGZvciBleGFtcGxlLCBcIm5hbWVcIjogXCJPdXIgVGVhbVwiLlxuICAgICAgICAqIEBwYXJhbSB7b2JqZWN0fSBwYXJhbXMucm9sZXMgKE9wdGlvbmFsKSBUaGUgbGlzdCBvZiByb2xlcyAoc3RyaW5ncykgZm9yIHRoaXMgd29ybGQuIFNvbWUgd29ybGRzIGhhdmUgc3BlY2lmaWMgcm9sZXMgdGhhdCAqKm11c3QqKiBiZSBmaWxsZWQgYnkgZW5kIHVzZXJzLiBMaXN0aW5nIHRoZSByb2xlcyBhbGxvd3MgeW91IHRvIGF1dG9hc3NpZ24gdXNlcnMgdG8gd29ybGRzIGFuZCBlbnN1cmUgdGhhdCBhbGwgcm9sZXMgYXJlIGZpbGxlZCBpbiBlYWNoIHdvcmxkLlxuICAgICAgICAqIEBwYXJhbSB7b2JqZWN0fSBwYXJhbXMub3B0aW9uYWxSb2xlcyAoT3B0aW9uYWwpIFRoZSBsaXN0IG9mIG9wdGlvbmFsIHJvbGVzIChzdHJpbmdzKSBmb3IgdGhpcyB3b3JsZC4gU29tZSB3b3JsZHMgaGF2ZSBzcGVjaWZpYyByb2xlcyB0aGF0ICoqbWF5KiogYmUgZmlsbGVkIGJ5IGVuZCB1c2Vycy4gTGlzdGluZyB0aGUgb3B0aW9uYWwgcm9sZXMgYXMgcGFydCBvZiB0aGUgd29ybGQgb2JqZWN0IGFsbG93cyB5b3UgdG8gYXV0b2Fzc2lnbiB1c2VycyB0byB3b3JsZHMgYW5kIGVuc3VyZSB0aGF0IGFsbCByb2xlcyBhcmUgZmlsbGVkIGluIGVhY2ggd29ybGQuXG4gICAgICAgICogQHBhcmFtIHtpbnRlZ2VyfSBwYXJhbXMubWluVXNlcnMgKE9wdGlvbmFsKSBUaGUgbWluaW11bSBudW1iZXIgb2YgdXNlcnMgZm9yIHRoZSB3b3JsZC4gSW5jbHVkaW5nIHRoaXMgbnVtYmVyIGFsbG93cyB5b3UgdG8gYXV0b2Fzc2lnbiBlbmQgdXNlcnMgdG8gd29ybGRzIGFuZCBlbnN1cmUgdGhhdCB0aGUgY29ycmVjdCBudW1iZXIgb2YgdXNlcnMgYXJlIGluIGVhY2ggd29ybGQuXG4gICAgICAgICogQHBhcmFtIHtvYmplY3R9IG9wdGlvbnMgKE9wdGlvbmFsKSBPcHRpb25zIG9iamVjdCB0byBvdmVycmlkZSBnbG9iYWwgb3B0aW9ucy5cbiAgICAgICAgKiBAcmV0dXJuIHtQcm9taXNlfVxuICAgICAgICAqL1xuICAgICAgICB1cGRhdGU6IGZ1bmN0aW9uIChwYXJhbXMsIG9wdGlvbnMpIHtcbiAgICAgICAgICAgIHZhciB3aGl0ZWxpc3QgPSBbJ3JvbGVzJywgJ29wdGlvbmFsUm9sZXMnLCAnbWluVXNlcnMnXTtcbiAgICAgICAgICAgIG9wdGlvbnMgPSBvcHRpb25zIHx8IHt9O1xuICAgICAgICAgICAgc2V0SWRGaWx0ZXJPclRocm93RXJyb3Iob3B0aW9ucyk7XG5cbiAgICAgICAgICAgIHZhciB1cGRhdGVPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sXG4gICAgICAgICAgICAgICAgc2VydmljZU9wdGlvbnMsXG4gICAgICAgICAgICAgICAgb3B0aW9ucyxcbiAgICAgICAgICAgICAgICB7IHVybDogdXJsQ29uZmlnLmdldEFQSVBhdGgoYXBpRW5kcG9pbnQpICsgc2VydmljZU9wdGlvbnMuZmlsdGVyIH1cbiAgICAgICAgICAgICk7XG5cbiAgICAgICAgICAgIHBhcmFtcyA9IF9waWNrKHBhcmFtcyB8fCB7fSwgd2hpdGVsaXN0KTtcblxuICAgICAgICAgICAgcmV0dXJuIGh0dHAucGF0Y2gocGFyYW1zLCB1cGRhdGVPcHRpb25zKTtcbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgKiBEZWxldGVzIGFuIGV4aXN0aW5nIHdvcmxkLlxuICAgICAgICAqXG4gICAgICAgICogVGhpcyBmdW5jdGlvbiBvcHRpb25hbGx5IHRha2VzIG9uZSBhcmd1bWVudC4gSWYgdGhlIGFyZ3VtZW50IGlzIGEgc3RyaW5nLCBpdCBpcyB0aGUgaWQgb2YgdGhlIHdvcmxkIHRvIGRlbGV0ZS4gSWYgdGhlIGFyZ3VtZW50IGlzIGFuIG9iamVjdCwgaXQgaXMgdGhlIG92ZXJyaWRlIGZvciBnbG9iYWwgb3B0aW9ucy5cbiAgICAgICAgKlxuICAgICAgICAqICAqKkV4YW1wbGUqKlxuICAgICAgICAqXG4gICAgICAgICogICAgICB2YXIgd2EgPSBuZXcgRi5zZXJ2aWNlLldvcmxkKHtcbiAgICAgICAgKiAgICAgICAgICAgYWNjb3VudDogJ2FjbWUtc2ltdWxhdGlvbnMnLFxuICAgICAgICAqICAgICAgICAgICBwcm9qZWN0OiAnc3VwcGx5LWNoYWluLWdhbWUnLFxuICAgICAgICAqICAgICAgICAgICBncm91cDogJ3RlYW0xJyB9KTtcbiAgICAgICAgKiAgICAgIHdhLmNyZWF0ZSgpXG4gICAgICAgICogICAgICAgICAgIC50aGVuKGZ1bmN0aW9uKHdvcmxkKSB7XG4gICAgICAgICogICAgICAgICAgICAgICB3YS5kZWxldGUoKTtcbiAgICAgICAgKiAgICAgICAgICAgfSk7XG4gICAgICAgICpcbiAgICAgICAgKiAgKipQYXJhbWV0ZXJzKipcbiAgICAgICAgKiBAcGFyYW0ge1N0cmluZ3xPYmplY3R9IG9wdGlvbnMgKE9wdGlvbmFsKSBUaGUgaWQgb2YgdGhlIHdvcmxkIHRvIGRlbGV0ZSwgb3Igb3B0aW9ucyBvYmplY3QgdG8gb3ZlcnJpZGUgZ2xvYmFsIG9wdGlvbnMuXG4gICAgICAgICogQHJldHVybiB7UHJvbWlzZX1cbiAgICAgICAgKi9cbiAgICAgICAgZGVsZXRlOiBmdW5jdGlvbiAob3B0aW9ucykge1xuICAgICAgICAgICAgb3B0aW9ucyA9IChvcHRpb25zICYmICh0eXBlb2Ygb3B0aW9ucyA9PT0gJ3N0cmluZycpKSA/IHsgZmlsdGVyOiBvcHRpb25zIH0gOiB7fTtcbiAgICAgICAgICAgIHNldElkRmlsdGVyT3JUaHJvd0Vycm9yKG9wdGlvbnMpO1xuXG4gICAgICAgICAgICB2YXIgZGVsZXRlT3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LFxuICAgICAgICAgICAgICAgIHNlcnZpY2VPcHRpb25zLFxuICAgICAgICAgICAgICAgIG9wdGlvbnMsXG4gICAgICAgICAgICAgICAgeyB1cmw6IHVybENvbmZpZy5nZXRBUElQYXRoKGFwaUVuZHBvaW50KSArIHNlcnZpY2VPcHRpb25zLmZpbHRlciB9XG4gICAgICAgICAgICApO1xuXG4gICAgICAgICAgICByZXR1cm4gaHR0cC5kZWxldGUobnVsbCwgZGVsZXRlT3B0aW9ucyk7XG4gICAgICAgIH0sXG5cbiAgICAgICAgLyoqXG4gICAgICAgICogVXBkYXRlcyB0aGUgY29uZmlndXJhdGlvbiBmb3IgdGhlIGN1cnJlbnQgaW5zdGFuY2Ugb2YgdGhlIFdvcmxkIEFQSSBBZGFwdGVyIChpbmNsdWRpbmcgYWxsIHN1YnNlcXVlbnQgZnVuY3Rpb24gY2FsbHMsIHVudGlsIHRoZSBjb25maWd1cmF0aW9uIGlzIHVwZGF0ZWQgYWdhaW4pLlxuICAgICAgICAqXG4gICAgICAgICogKipFeGFtcGxlKipcbiAgICAgICAgKlxuICAgICAgICAqICAgICAgdmFyIHdhID0gbmV3IEYuc2VydmljZS5Xb3JsZCh7Li4ufSkudXBkYXRlQ29uZmlnKHsgZmlsdGVyOiAnMTIzJyB9KS5hZGRVc2VyKHsgdXNlcklkOiAnMTIzJyB9KTtcbiAgICAgICAgKlxuICAgICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICAgICogQHBhcmFtIHtvYmplY3R9IGNvbmZpZyBUaGUgY29uZmlndXJhdGlvbiBvYmplY3QgdG8gdXNlIGluIHVwZGF0aW5nIGV4aXN0aW5nIGNvbmZpZ3VyYXRpb24uXG4gICAgICAgICogQHJldHVybiB7T2JqZWN0fSByZWZlcmVuY2UgdG8gY3VycmVudCBpbnN0YW5jZVxuICAgICAgICAqL1xuICAgICAgICB1cGRhdGVDb25maWc6IGZ1bmN0aW9uIChjb25maWcpIHtcbiAgICAgICAgICAgICQuZXh0ZW5kKHNlcnZpY2VPcHRpb25zLCBjb25maWcpO1xuXG4gICAgICAgICAgICByZXR1cm4gdGhpcztcbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgKiBMaXN0cyBhbGwgd29ybGRzIGZvciBhIGdpdmVuIGFjY291bnQsIHByb2plY3QsIGFuZCBncm91cC4gQWxsIHRocmVlIGFyZSByZXF1aXJlZCwgYW5kIGlmIG5vdCBzcGVjaWZpZWQgYXMgcGFyYW1ldGVycywgYXJlIHJlYWQgZnJvbSB0aGUgc2VydmljZS5cbiAgICAgICAgKlxuICAgICAgICAqICAqKkV4YW1wbGUqKlxuICAgICAgICAqXG4gICAgICAgICogICAgICB2YXIgd2EgPSBuZXcgRi5zZXJ2aWNlLldvcmxkKHtcbiAgICAgICAgKiAgICAgICAgICAgYWNjb3VudDogJ2FjbWUtc2ltdWxhdGlvbnMnLFxuICAgICAgICAqICAgICAgICAgICBwcm9qZWN0OiAnc3VwcGx5LWNoYWluLWdhbWUnLFxuICAgICAgICAqICAgICAgICAgICBncm91cDogJ3RlYW0xJyB9KTtcbiAgICAgICAgKiAgICAgIHdhLmNyZWF0ZSgpXG4gICAgICAgICogICAgICAgICAgIC50aGVuKGZ1bmN0aW9uKHdvcmxkKSB7XG4gICAgICAgICogICAgICAgICAgICAgICAvLyBsaXN0cyBhbGwgd29ybGRzIGluIGdyb3VwIFwidGVhbTFcIlxuICAgICAgICAqICAgICAgICAgICAgICAgd2EubGlzdCgpO1xuICAgICAgICAqXG4gICAgICAgICogICAgICAgICAgICAgICAvLyBsaXN0cyBhbGwgd29ybGRzIGluIGdyb3VwIFwib3RoZXItZ3JvdXAtbmFtZVwiXG4gICAgICAgICogICAgICAgICAgICAgICB3YS5saXN0KHsgZ3JvdXA6ICdvdGhlci1ncm91cC1uYW1lJyB9KTtcbiAgICAgICAgKiAgICAgICAgICAgfSk7XG4gICAgICAgICpcbiAgICAgICAgKiAgKipQYXJhbWV0ZXJzKipcbiAgICAgICAgKiBAcGFyYW0ge29iamVjdH0gb3B0aW9ucyAoT3B0aW9uYWwpIE9wdGlvbnMgb2JqZWN0IHRvIG92ZXJyaWRlIGdsb2JhbCBvcHRpb25zLlxuICAgICAgICAqIEByZXR1cm4ge1Byb21pc2V9XG4gICAgICAgICovXG4gICAgICAgIGxpc3Q6IGZ1bmN0aW9uIChvcHRpb25zKSB7XG4gICAgICAgICAgICBvcHRpb25zID0gb3B0aW9ucyB8fCB7fTtcblxuICAgICAgICAgICAgdmFyIGdldE9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSxcbiAgICAgICAgICAgICAgICBzZXJ2aWNlT3B0aW9ucyxcbiAgICAgICAgICAgICAgICBvcHRpb25zLFxuICAgICAgICAgICAgICAgIHsgdXJsOiB1cmxDb25maWcuZ2V0QVBJUGF0aChhcGlFbmRwb2ludCkgfVxuICAgICAgICAgICAgKTtcblxuICAgICAgICAgICAgdmFyIGZpbHRlcnMgPSBfcGljayhnZXRPcHRpb25zLCBbJ2FjY291bnQnLCAncHJvamVjdCcsICdncm91cCddKTtcblxuICAgICAgICAgICAgcmV0dXJuIGh0dHAuZ2V0KGZpbHRlcnMsIGdldE9wdGlvbnMpO1xuICAgICAgICB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAqIEdldHMgYWxsIHdvcmxkcyB0aGF0IGFuIGVuZCB1c2VyIGJlbG9uZ3MgdG8gZm9yIGEgZ2l2ZW4gYWNjb3VudCAodGVhbSksIHByb2plY3QsIGFuZCBncm91cC5cbiAgICAgICAgKlxuICAgICAgICAqICAqKkV4YW1wbGUqKlxuICAgICAgICAqXG4gICAgICAgICogICAgICB2YXIgd2EgPSBuZXcgRi5zZXJ2aWNlLldvcmxkKHtcbiAgICAgICAgKiAgICAgICAgICAgYWNjb3VudDogJ2FjbWUtc2ltdWxhdGlvbnMnLFxuICAgICAgICAqICAgICAgICAgICBwcm9qZWN0OiAnc3VwcGx5LWNoYWluLWdhbWUnLFxuICAgICAgICAqICAgICAgICAgICBncm91cDogJ3RlYW0xJyB9KTtcbiAgICAgICAgKiAgICAgIHdhLmNyZWF0ZSgpXG4gICAgICAgICogICAgICAgICAgIC50aGVuKGZ1bmN0aW9uKHdvcmxkKSB7XG4gICAgICAgICogICAgICAgICAgICAgICB3YS5nZXRXb3JsZHNGb3JVc2VyKCdiMWMxOWRkYS0yZDJlLTQ3NzctYWQ1ZC0zOTI5ZjE3ZTg2ZDMnKVxuICAgICAgICAqICAgICAgICAgICB9KTtcbiAgICAgICAgKlxuICAgICAgICAqICoqIFBhcmFtZXRlcnMgKipcbiAgICAgICAgKiBAcGFyYW0ge3N0cmluZ30gdXNlcklkIFRoZSBgdXNlcklkYCBvZiB0aGUgdXNlciB3aG9zZSB3b3JsZHMgYXJlIGJlaW5nIHJldHJpZXZlZC5cbiAgICAgICAgKiBAcGFyYW0ge29iamVjdH0gb3B0aW9ucyAoT3B0aW9uYWwpIE9wdGlvbnMgb2JqZWN0IHRvIG92ZXJyaWRlIGdsb2JhbCBvcHRpb25zLlxuICAgICAgICAqIEByZXR1cm4ge1Byb21pc2V9XG4gICAgICAgICovXG4gICAgICAgIGdldFdvcmxkc0ZvclVzZXI6IGZ1bmN0aW9uICh1c2VySWQsIG9wdGlvbnMpIHtcbiAgICAgICAgICAgIG9wdGlvbnMgPSBvcHRpb25zIHx8IHt9O1xuXG4gICAgICAgICAgICB2YXIgZ2V0T3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LFxuICAgICAgICAgICAgICAgIHNlcnZpY2VPcHRpb25zLFxuICAgICAgICAgICAgICAgIG9wdGlvbnMsXG4gICAgICAgICAgICAgICAgeyB1cmw6IHVybENvbmZpZy5nZXRBUElQYXRoKGFwaUVuZHBvaW50KSB9XG4gICAgICAgICAgICApO1xuXG4gICAgICAgICAgICB2YXIgZmlsdGVycyA9ICQuZXh0ZW5kKFxuICAgICAgICAgICAgICAgIF9waWNrKGdldE9wdGlvbnMsIFsnYWNjb3VudCcsICdwcm9qZWN0JywgJ2dyb3VwJ10pLFxuICAgICAgICAgICAgICAgIHsgdXNlcklkOiB1c2VySWQgfVxuICAgICAgICAgICAgKTtcblxuICAgICAgICAgICAgcmV0dXJuIGh0dHAuZ2V0KGZpbHRlcnMsIGdldE9wdGlvbnMpO1xuICAgICAgICB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBMb2FkIGluZm9ybWF0aW9uIGZvciBhIHNwZWNpZmljIHdvcmxkLiBBbGwgZnVydGhlciBjYWxscyB0byB0aGUgd29ybGQgc2VydmljZSB3aWxsIHVzZSB0aGUgaWQgcHJvdmlkZWQuXG4gICAgICAgICAqXG4gICAgICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICAgICAqIEBwYXJhbSB7U3RyaW5nfSB3b3JsZElkIFRoZSBpZCBvZiB0aGUgd29ybGQgdG8gbG9hZC5cbiAgICAgICAgICogQHBhcmFtIHtPYmplY3R9IG9wdGlvbnMgKE9wdGlvbmFsKSBPcHRpb25zIG9iamVjdCB0byBvdmVycmlkZSBnbG9iYWwgb3B0aW9ucy5cbiAgICAgICAgICogQHJldHVybiB7UHJvbWlzZX1cbiAgICAgICAgICovXG4gICAgICAgIGxvYWQ6IGZ1bmN0aW9uICh3b3JsZElkLCBvcHRpb25zKSB7XG4gICAgICAgICAgICBpZiAod29ybGRJZCkge1xuICAgICAgICAgICAgICAgIHNlcnZpY2VPcHRpb25zLmZpbHRlciA9IHdvcmxkSWQ7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBpZiAoIXNlcnZpY2VPcHRpb25zLmZpbHRlcikge1xuICAgICAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcignUGxlYXNlIHByb3ZpZGUgYSB3b3JsZGlkIHRvIGxvYWQnKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHZhciBodHRwT3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LCBzZXJ2aWNlT3B0aW9ucywgb3B0aW9ucywgeyB1cmw6IHVybENvbmZpZy5nZXRBUElQYXRoKGFwaUVuZHBvaW50KSArIHNlcnZpY2VPcHRpb25zLmZpbHRlciArICcvJyB9KTtcbiAgICAgICAgICAgIHJldHVybiBodHRwLmdldCgnJywgaHR0cE9wdGlvbnMpO1xuICAgICAgICB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAqIEFkZHMgYW4gZW5kIHVzZXIgb3IgbGlzdCBvZiBlbmQgdXNlcnMgdG8gYSBnaXZlbiB3b3JsZC4gVGhlIGVuZCB1c2VyIG11c3QgYmUgYSBtZW1iZXIgb2YgdGhlIGBncm91cGAgdGhhdCBpcyBhc3NvY2lhdGVkIHdpdGggdGhpcyB3b3JsZC5cbiAgICAgICAgKlxuICAgICAgICAqICAqKkV4YW1wbGUqKlxuICAgICAgICAqXG4gICAgICAgICogICAgICB2YXIgd2EgPSBuZXcgRi5zZXJ2aWNlLldvcmxkKHtcbiAgICAgICAgKiAgICAgICAgICAgYWNjb3VudDogJ2FjbWUtc2ltdWxhdGlvbnMnLFxuICAgICAgICAqICAgICAgICAgICBwcm9qZWN0OiAnc3VwcGx5LWNoYWluLWdhbWUnLFxuICAgICAgICAqICAgICAgICAgICBncm91cDogJ3RlYW0xJyB9KTtcbiAgICAgICAgKiAgICAgIHdhLmNyZWF0ZSgpXG4gICAgICAgICogICAgICAgICAgIC50aGVuKGZ1bmN0aW9uKHdvcmxkKSB7XG4gICAgICAgICogICAgICAgICAgICAgICAvLyBhZGQgb25lIHVzZXJcbiAgICAgICAgKiAgICAgICAgICAgICAgIHdhLmFkZFVzZXJzKCdiMWMxOWRkYS0yZDJlLTQ3NzctYWQ1ZC0zOTI5ZjE3ZTg2ZDMnKTtcbiAgICAgICAgKiAgICAgICAgICAgICAgIHdhLmFkZFVzZXJzKFsnYjFjMTlkZGEtMmQyZS00Nzc3LWFkNWQtMzkyOWYxN2U4NmQzJ10pO1xuICAgICAgICAqICAgICAgICAgICAgICAgd2EuYWRkVXNlcnMoeyB1c2VySWQ6ICdiMWMxOWRkYS0yZDJlLTQ3NzctYWQ1ZC0zOTI5ZjE3ZTg2ZDMnLCByb2xlOiAnVlAgU2FsZXMnIH0pO1xuICAgICAgICAqXG4gICAgICAgICogICAgICAgICAgICAgICAvLyBhZGQgc2V2ZXJhbCB1c2Vyc1xuICAgICAgICAqICAgICAgICAgICAgICAgd2EuYWRkVXNlcnMoW1xuICAgICAgICAqICAgICAgICAgICAgICAgICAgIHsgdXNlcklkOiAnYTZmZTBjMWUtZjRiOC00ZjAxLTlmNWYtMDFjY2Y0YzJlZDQ0JyxcbiAgICAgICAgKiAgICAgICAgICAgICAgICAgICAgIHJvbGU6ICdWUCBNYXJrZXRpbmcnIH0sXG4gICAgICAgICogICAgICAgICAgICAgICAgICAgeyB1c2VySWQ6ICc4ZjI2MDRjZi05NmNkLTQ0OWYtODJmYS1lMzMxNTMwNzM0ZWUnLFxuICAgICAgICAqICAgICAgICAgICAgICAgICAgICAgcm9sZTogJ1ZQIEVuZ2luZWVyaW5nJyB9XG4gICAgICAgICogICAgICAgICAgICAgICBdKTtcbiAgICAgICAgKlxuICAgICAgICAqICAgICAgICAgICAgICAgLy8gYWRkIG9uZSB1c2VyIHRvIGEgc3BlY2lmaWMgd29ybGRcbiAgICAgICAgKiAgICAgICAgICAgICAgIHdhLmFkZFVzZXJzKCdiMWMxOWRkYS0yZDJlLTQ3NzctYWQ1ZC0zOTI5ZjE3ZTg2ZDMnLCB3b3JsZC5pZCk7XG4gICAgICAgICogICAgICAgICAgICAgICB3YS5hZGRVc2VycygnYjFjMTlkZGEtMmQyZS00Nzc3LWFkNWQtMzkyOWYxN2U4NmQzJywgeyBmaWx0ZXI6IHdvcmxkLmlkIH0pO1xuICAgICAgICAqICAgICAgICAgICB9KTtcbiAgICAgICAgKlxuICAgICAgICAqICoqIFBhcmFtZXRlcnMgKipcbiAgICAgICAgKiBAcGFyYW0ge3N0cmluZ3xvYmplY3R8YXJyYXl9IHVzZXJzIFVzZXIgaWQsIGFycmF5IG9mIHVzZXIgaWRzLCBvYmplY3QsIG9yIGFycmF5IG9mIG9iamVjdHMgb2YgdGhlIHVzZXJzIHRvIGFkZCB0byB0aGlzIHdvcmxkLlxuICAgICAgICAqIEBwYXJhbSB7c3RyaW5nfSB1c2Vycy5yb2xlIFRoZSBgcm9sZWAgdGhlIHVzZXIgc2hvdWxkIGhhdmUgaW4gdGhlIHdvcmxkLiBJdCBpcyB1cCB0byB0aGUgY2FsbGVyIHRvIGVuc3VyZSwgaWYgbmVlZGVkLCB0aGF0IHRoZSBgcm9sZWAgcGFzc2VkIGluIGlzIG9uZSBvZiB0aGUgYHJvbGVzYCBvciBgb3B0aW9uYWxSb2xlc2Agb2YgdGhpcyB3b3JsZC5cbiAgICAgICAgKiBAcGFyYW0ge3N0cmluZ30gd29ybGRJZCBUaGUgd29ybGQgdG8gd2hpY2ggdGhlIHVzZXJzIHNob3VsZCBiZSBhZGRlZC4gSWYgbm90IHNwZWNpZmllZCwgdGhlIGZpbHRlciBwYXJhbWV0ZXIgb2YgdGhlIGBvcHRpb25zYCBvYmplY3QgaXMgdXNlZC5cbiAgICAgICAgKiBAcGFyYW0ge29iamVjdH0gb3B0aW9ucyAoT3B0aW9uYWwpIE9wdGlvbnMgb2JqZWN0IHRvIG92ZXJyaWRlIGdsb2JhbCBvcHRpb25zLlxuICAgICAgICAqIEByZXR1cm4ge1Byb21pc2V9XG4gICAgICAgICovXG4gICAgICAgIGFkZFVzZXJzOiBmdW5jdGlvbiAodXNlcnMsIHdvcmxkSWQsIG9wdGlvbnMpIHtcblxuICAgICAgICAgICAgaWYgKCF1c2Vycykge1xuICAgICAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcignUGxlYXNlIHByb3ZpZGUgYSBsaXN0IG9mIHVzZXJzIHRvIGFkZCB0byB0aGUgd29ybGQnKTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgLy8gbm9ybWFsaXplIHRoZSBsaXN0IG9mIHVzZXJzIHRvIGFuIGFycmF5IG9mIHVzZXIgb2JqZWN0c1xuICAgICAgICAgICAgdXNlcnMgPSAkLm1hcChbXS5jb25jYXQodXNlcnMpLCBmdW5jdGlvbiAodSkge1xuICAgICAgICAgICAgICAgIHZhciBpc09iamVjdCA9ICQuaXNQbGFpbk9iamVjdCh1KTtcblxuICAgICAgICAgICAgICAgIGlmICh0eXBlb2YgdSAhPT0gJ3N0cmluZycgJiYgIWlzT2JqZWN0KSB7XG4gICAgICAgICAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcignU29tZSBvZiB0aGUgdXNlcnMgaW4gdGhlIGxpc3QgYXJlIG5vdCBpbiB0aGUgdmFsaWQgZm9ybWF0OiAnICsgdSk7XG4gICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgcmV0dXJuIGlzT2JqZWN0ID8gdSA6IHsgdXNlcklkOiB1IH07XG4gICAgICAgICAgICB9KTtcblxuICAgICAgICAgICAgLy8gY2hlY2sgaWYgb3B0aW9ucyB3ZXJlIHBhc3NlZCBhcyB0aGUgc2Vjb25kIHBhcmFtZXRlclxuICAgICAgICAgICAgaWYgKCQuaXNQbGFpbk9iamVjdCh3b3JsZElkKSAmJiAhb3B0aW9ucykge1xuICAgICAgICAgICAgICAgIG9wdGlvbnMgPSB3b3JsZElkO1xuICAgICAgICAgICAgICAgIHdvcmxkSWQgPSBudWxsO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICBvcHRpb25zID0gb3B0aW9ucyB8fCB7fTtcblxuICAgICAgICAgICAgLy8gd2UgbXVzdCBoYXZlIG9wdGlvbnMgYnkgbm93XG4gICAgICAgICAgICBpZiAodHlwZW9mIHdvcmxkSWQgPT09ICdzdHJpbmcnKSB7XG4gICAgICAgICAgICAgICAgb3B0aW9ucy5maWx0ZXIgPSB3b3JsZElkO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICBzZXRJZEZpbHRlck9yVGhyb3dFcnJvcihvcHRpb25zKTtcblxuICAgICAgICAgICAgdmFyIHVwZGF0ZU9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSxcbiAgICAgICAgICAgICAgICBzZXJ2aWNlT3B0aW9ucyxcbiAgICAgICAgICAgICAgICBvcHRpb25zLFxuICAgICAgICAgICAgICAgIHsgdXJsOiB1cmxDb25maWcuZ2V0QVBJUGF0aChhcGlFbmRwb2ludCkgKyBzZXJ2aWNlT3B0aW9ucy5maWx0ZXIgKyAnL3VzZXJzJyB9XG4gICAgICAgICAgICApO1xuXG4gICAgICAgICAgICByZXR1cm4gaHR0cC5wb3N0KHVzZXJzLCB1cGRhdGVPcHRpb25zKTtcbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgKiBVcGRhdGVzIHRoZSByb2xlIG9mIGFuIGVuZCB1c2VyIGluIGEgZ2l2ZW4gd29ybGQuIChZb3UgY2FuIG9ubHkgdXBkYXRlIG9uZSBlbmQgdXNlciBhdCBhIHRpbWUuKVxuICAgICAgICAqXG4gICAgICAgICogKipFeGFtcGxlKipcbiAgICAgICAgKlxuICAgICAgICAqICAgICAgdmFyIHdhID0gbmV3IEYuc2VydmljZS5Xb3JsZCh7XG4gICAgICAgICogICAgICAgICAgIGFjY291bnQ6ICdhY21lLXNpbXVsYXRpb25zJyxcbiAgICAgICAgKiAgICAgICAgICAgcHJvamVjdDogJ3N1cHBseS1jaGFpbi1nYW1lJyxcbiAgICAgICAgKiAgICAgICAgICAgZ3JvdXA6ICd0ZWFtMScgfSk7XG4gICAgICAgICpcbiAgICAgICAgKiAgICAgIHdhLmNyZWF0ZSgpLnRoZW4oZnVuY3Rpb24od29ybGQpIHtcbiAgICAgICAgKiAgICAgICAgICAgd2EuYWRkVXNlcnMoJ2IxYzE5ZGRhLTJkMmUtNDc3Ny1hZDVkLTM5MjlmMTdlODZkMycpO1xuICAgICAgICAqICAgICAgICAgICB3YS51cGRhdGVVc2VyKHsgdXNlcklkOiAnYjFjMTlkZGEtMmQyZS00Nzc3LWFkNWQtMzkyOWYxN2U4NmQzJywgcm9sZTogJ2xlYWRlcicgfSk7XG4gICAgICAgICogICAgICB9KTtcbiAgICAgICAgKlxuICAgICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICAgICogQHBhcmFtIHtvYmplY3R9IHVzZXIgVXNlciBvYmplY3Qgd2l0aCBgdXNlcklkYCBhbmQgdGhlIG5ldyBgcm9sZWAuXG4gICAgICAgICogQHBhcmFtIHtvYmplY3R9IG9wdGlvbnMgKE9wdGlvbmFsKSBPcHRpb25zIG9iamVjdCB0byBvdmVycmlkZSBnbG9iYWwgb3B0aW9ucy5cbiAgICAgICAgKiBAcmV0dXJuIHtQcm9taXNlfVxuICAgICAgICAqL1xuICAgICAgICB1cGRhdGVVc2VyOiBmdW5jdGlvbiAodXNlciwgb3B0aW9ucykge1xuICAgICAgICAgICAgb3B0aW9ucyA9IG9wdGlvbnMgfHwge307XG5cbiAgICAgICAgICAgIGlmICghdXNlciB8fCAhdXNlci51c2VySWQpIHtcbiAgICAgICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ1lvdSBuZWVkIHRvIHBhc3MgYSB1c2VySWQgdG8gdXBkYXRlIGZyb20gdGhlIHdvcmxkJyk7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIHNldElkRmlsdGVyT3JUaHJvd0Vycm9yKG9wdGlvbnMpO1xuXG4gICAgICAgICAgICB2YXIgcGF0Y2hPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sXG4gICAgICAgICAgICAgICAgc2VydmljZU9wdGlvbnMsXG4gICAgICAgICAgICAgICAgb3B0aW9ucyxcbiAgICAgICAgICAgICAgICB7IHVybDogdXJsQ29uZmlnLmdldEFQSVBhdGgoYXBpRW5kcG9pbnQpICsgc2VydmljZU9wdGlvbnMuZmlsdGVyICsgJy91c2Vycy8nICsgdXNlci51c2VySWQgfVxuICAgICAgICAgICAgKTtcblxuICAgICAgICAgICAgcmV0dXJuIGh0dHAucGF0Y2goX3BpY2sodXNlciwgJ3JvbGUnKSwgcGF0Y2hPcHRpb25zKTtcbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgKiBSZW1vdmVzIGFuIGVuZCB1c2VyIGZyb20gYSBnaXZlbiB3b3JsZC5cbiAgICAgICAgKlxuICAgICAgICAqICAqKkV4YW1wbGUqKlxuICAgICAgICAqXG4gICAgICAgICogICAgICB2YXIgd2EgPSBuZXcgRi5zZXJ2aWNlLldvcmxkKHtcbiAgICAgICAgKiAgICAgICAgICAgYWNjb3VudDogJ2FjbWUtc2ltdWxhdGlvbnMnLFxuICAgICAgICAqICAgICAgICAgICBwcm9qZWN0OiAnc3VwcGx5LWNoYWluLWdhbWUnLFxuICAgICAgICAqICAgICAgICAgICBncm91cDogJ3RlYW0xJyB9KTtcbiAgICAgICAgKiAgICAgIHdhLmNyZWF0ZSgpXG4gICAgICAgICogICAgICAgICAgIC50aGVuKGZ1bmN0aW9uKHdvcmxkKSB7XG4gICAgICAgICogICAgICAgICAgICAgICB3YS5hZGRVc2VycyhbJ2E2ZmUwYzFlLWY0YjgtNGYwMS05ZjVmLTAxY2NmNGMyZWQ0NCcsICc4ZjI2MDRjZi05NmNkLTQ0OWYtODJmYS1lMzMxNTMwNzM0ZWUnXSk7XG4gICAgICAgICogICAgICAgICAgICAgICB3YS5yZW1vdmVVc2VyKCdhNmZlMGMxZS1mNGI4LTRmMDEtOWY1Zi0wMWNjZjRjMmVkNDQnKTtcbiAgICAgICAgKiAgICAgICAgICAgICAgIHdhLnJlbW92ZVVzZXIoeyB1c2VySWQ6ICc4ZjI2MDRjZi05NmNkLTQ0OWYtODJmYS1lMzMxNTMwNzM0ZWUnIH0pO1xuICAgICAgICAqICAgICAgICAgICB9KTtcbiAgICAgICAgKlxuICAgICAgICAqICoqIFBhcmFtZXRlcnMgKipcbiAgICAgICAgKiBAcGFyYW0ge29iamVjdHxzdHJpbmd9IHVzZXIgVGhlIGB1c2VySWRgIG9mIHRoZSB1c2VyIHRvIHJlbW92ZSBmcm9tIHRoZSB3b3JsZCwgb3IgYW4gb2JqZWN0IGNvbnRhaW5pbmcgdGhlIGB1c2VySWRgIGZpZWxkLlxuICAgICAgICAqIEBwYXJhbSB7b2JqZWN0fSBvcHRpb25zIChPcHRpb25hbCkgT3B0aW9ucyBvYmplY3QgdG8gb3ZlcnJpZGUgZ2xvYmFsIG9wdGlvbnMuXG4gICAgICAgICogQHJldHVybiB7UHJvbWlzZX1cbiAgICAgICAgKi9cbiAgICAgICAgcmVtb3ZlVXNlcjogZnVuY3Rpb24gKHVzZXIsIG9wdGlvbnMpIHtcbiAgICAgICAgICAgIG9wdGlvbnMgPSBvcHRpb25zIHx8IHt9O1xuXG4gICAgICAgICAgICBpZiAodHlwZW9mIHVzZXIgPT09ICdzdHJpbmcnKSB7XG4gICAgICAgICAgICAgICAgdXNlciA9IHsgdXNlcklkOiB1c2VyIH07XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIGlmICghdXNlci51c2VySWQpIHtcbiAgICAgICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ1lvdSBuZWVkIHRvIHBhc3MgYSB1c2VySWQgdG8gcmVtb3ZlIGZyb20gdGhlIHdvcmxkJyk7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIHNldElkRmlsdGVyT3JUaHJvd0Vycm9yKG9wdGlvbnMpO1xuXG4gICAgICAgICAgICB2YXIgZ2V0T3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LFxuICAgICAgICAgICAgICAgIHNlcnZpY2VPcHRpb25zLFxuICAgICAgICAgICAgICAgIG9wdGlvbnMsXG4gICAgICAgICAgICAgICAgeyB1cmw6IHVybENvbmZpZy5nZXRBUElQYXRoKGFwaUVuZHBvaW50KSArIHNlcnZpY2VPcHRpb25zLmZpbHRlciArICcvdXNlcnMvJyArIHVzZXIudXNlcklkIH1cbiAgICAgICAgICAgICk7XG5cbiAgICAgICAgICAgIHJldHVybiBodHRwLmRlbGV0ZShudWxsLCBnZXRPcHRpb25zKTtcbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgKiBHZXRzIHRoZSBydW4gaWQgb2YgY3VycmVudCBydW4gZm9yIHRoZSBnaXZlbiB3b3JsZC4gSWYgdGhlIHdvcmxkIGRvZXMgbm90IGhhdmUgYSBydW4sIGNyZWF0ZXMgYSBuZXcgb25lIGFuZCByZXR1cm5zIHRoZSBydW4gaWQuXG4gICAgICAgICpcbiAgICAgICAgKiBSZW1lbWJlciB0aGF0IGEgW3J1bl0oLi4vLi4vZ2xvc3NhcnkvI3J1bikgaXMgYSBjb2xsZWN0aW9uIG9mIGludGVyYWN0aW9ucyB3aXRoIGEgcHJvamVjdCBhbmQgaXRzIG1vZGVsLiBJbiB0aGUgY2FzZSBvZiBtdWx0aXBsYXllciBwcm9qZWN0cywgdGhlIHJ1biBpcyBzaGFyZWQgYnkgYWxsIGVuZCB1c2VycyBpbiB0aGUgd29ybGQuXG4gICAgICAgICpcbiAgICAgICAgKiAgKipFeGFtcGxlKipcbiAgICAgICAgKlxuICAgICAgICAqICAgICAgdmFyIHdhID0gbmV3IEYuc2VydmljZS5Xb3JsZCh7XG4gICAgICAgICogICAgICAgICAgIGFjY291bnQ6ICdhY21lLXNpbXVsYXRpb25zJyxcbiAgICAgICAgKiAgICAgICAgICAgcHJvamVjdDogJ3N1cHBseS1jaGFpbi1nYW1lJyxcbiAgICAgICAgKiAgICAgICAgICAgZ3JvdXA6ICd0ZWFtMScgfSk7XG4gICAgICAgICogICAgICB3YS5jcmVhdGUoKVxuICAgICAgICAqICAgICAgICAgICAudGhlbihmdW5jdGlvbih3b3JsZCkge1xuICAgICAgICAqICAgICAgICAgICAgICAgd2EuZ2V0Q3VycmVudFJ1bklkKHsgbW9kZWw6ICdtb2RlbC5weScgfSk7XG4gICAgICAgICogICAgICAgICAgIH0pO1xuICAgICAgICAqXG4gICAgICAgICogKiogUGFyYW1ldGVycyAqKlxuICAgICAgICAqIEBwYXJhbSB7b2JqZWN0fSBvcHRpb25zIChPcHRpb25hbCkgT3B0aW9ucyBvYmplY3QgdG8gb3ZlcnJpZGUgZ2xvYmFsIG9wdGlvbnMuXG4gICAgICAgICogQHBhcmFtIHtvYmplY3R9IG9wdGlvbnMubW9kZWwgVGhlIG1vZGVsIGZpbGUgdG8gdXNlIHRvIGNyZWF0ZSBhIHJ1biBpZiBuZWVkZWQuXG4gICAgICAgICogQHJldHVybiB7UHJvbWlzZX1cbiAgICAgICAgKi9cbiAgICAgICAgZ2V0Q3VycmVudFJ1bklkOiBmdW5jdGlvbiAob3B0aW9ucykge1xuICAgICAgICAgICAgb3B0aW9ucyA9IG9wdGlvbnMgfHwge307XG5cbiAgICAgICAgICAgIHNldElkRmlsdGVyT3JUaHJvd0Vycm9yKG9wdGlvbnMpO1xuXG4gICAgICAgICAgICB2YXIgZ2V0T3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LFxuICAgICAgICAgICAgICAgIHNlcnZpY2VPcHRpb25zLFxuICAgICAgICAgICAgICAgIG9wdGlvbnMsXG4gICAgICAgICAgICAgICAgeyB1cmw6IHVybENvbmZpZy5nZXRBUElQYXRoKGFwaUVuZHBvaW50KSArIHNlcnZpY2VPcHRpb25zLmZpbHRlciArICcvcnVuJyB9XG4gICAgICAgICAgICApO1xuXG4gICAgICAgICAgICB2YWxpZGF0ZU1vZGVsT3JUaHJvd0Vycm9yKGdldE9wdGlvbnMpO1xuICAgICAgICAgICAgcmV0dXJuIGh0dHAucG9zdChfcGljayhnZXRPcHRpb25zLCAnbW9kZWwnKSwgZ2V0T3B0aW9ucyk7XG4gICAgICAgIH0sXG5cbiAgICAgICAgLyoqXG4gICAgICAgICogR2V0cyB0aGUgY3VycmVudCAobW9zdCByZWNlbnQpIHdvcmxkIGZvciB0aGUgZ2l2ZW4gZW5kIHVzZXIgaW4gdGhlIGdpdmVuIGdyb3VwLiBCcmluZ3MgdGhpcyBtb3N0IHJlY2VudCB3b3JsZCBpbnRvIG1lbW9yeSBpZiBuZWVkZWQuXG4gICAgICAgICpcbiAgICAgICAgKiAgKipFeGFtcGxlKipcbiAgICAgICAgKlxuICAgICAgICAqICAgICAgdmFyIHdhID0gbmV3IEYuc2VydmljZS5Xb3JsZCh7XG4gICAgICAgICogICAgICAgICAgIGFjY291bnQ6ICdhY21lLXNpbXVsYXRpb25zJyxcbiAgICAgICAgKiAgICAgICAgICAgcHJvamVjdDogJ3N1cHBseS1jaGFpbi1nYW1lJyxcbiAgICAgICAgKiAgICAgICAgICAgZ3JvdXA6ICd0ZWFtMScgfSk7XG4gICAgICAgICogICAgICB3YS5nZXRDdXJyZW50V29ybGRGb3JVc2VyKCc4ZjI2MDRjZi05NmNkLTQ0OWYtODJmYS1lMzMxNTMwNzM0ZWUnKVxuICAgICAgICAqICAgICAgICAgICAudGhlbihmdW5jdGlvbih3b3JsZCkge1xuICAgICAgICAqICAgICAgICAgICAgICAgLy8gdXNlIGRhdGEgZnJvbSB3b3JsZFxuICAgICAgICAqICAgICAgICAgICB9KTtcbiAgICAgICAgKlxuICAgICAgICAqICoqIFBhcmFtZXRlcnMgKipcbiAgICAgICAgKiBAcGFyYW0ge3N0cmluZ30gdXNlcklkIFRoZSBgdXNlcklkYCBvZiB0aGUgdXNlciB3aG9zZSBjdXJyZW50IChtb3N0IHJlY2VudCkgd29ybGQgaXMgYmVpbmcgcmV0cmlldmVkLlxuICAgICAgICAqIEBwYXJhbSB7c3RyaW5nfSBncm91cE5hbWUgKE9wdGlvbmFsKSBUaGUgbmFtZSBvZiB0aGUgZ3JvdXAuIElmIG5vdCBwcm92aWRlZCwgZGVmYXVsdHMgdG8gdGhlIGdyb3VwIHVzZWQgdG8gY3JlYXRlIHRoZSBzZXJ2aWNlLlxuICAgICAgICAqIEByZXR1cm4ge1Byb21pc2V9XG4gICAgICAgICovXG4gICAgICAgIGdldEN1cnJlbnRXb3JsZEZvclVzZXI6IGZ1bmN0aW9uICh1c2VySWQsIGdyb3VwTmFtZSkge1xuICAgICAgICAgICAgdmFyIGR0ZCA9ICQuRGVmZXJyZWQoKTtcbiAgICAgICAgICAgIHZhciBtZSA9IHRoaXM7XG4gICAgICAgICAgICB0aGlzLmdldFdvcmxkc0ZvclVzZXIodXNlcklkLCB7IGdyb3VwOiBncm91cE5hbWUgfSlcbiAgICAgICAgICAgICAgICAudGhlbihmdW5jdGlvbiAod29ybGRzKSB7XG4gICAgICAgICAgICAgICAgICAgIC8vIGFzc3VtZSB0aGUgbW9zdCByZWNlbnQgd29ybGQgYXMgdGhlICdhY3RpdmUnIHdvcmxkXG4gICAgICAgICAgICAgICAgICAgIHdvcmxkcy5zb3J0KGZ1bmN0aW9uIChhLCBiKSB7IHJldHVybiBuZXcgRGF0ZShiLmxhc3RNb2RpZmllZCkgLSBuZXcgRGF0ZShhLmxhc3RNb2RpZmllZCk7IH0pO1xuICAgICAgICAgICAgICAgICAgICB2YXIgY3VycmVudFdvcmxkID0gd29ybGRzWzBdO1xuXG4gICAgICAgICAgICAgICAgICAgIGlmIChjdXJyZW50V29ybGQpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHNlcnZpY2VPcHRpb25zLmZpbHRlciA9IGN1cnJlbnRXb3JsZC5pZDtcbiAgICAgICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgICAgIGR0ZC5yZXNvbHZlV2l0aChtZSwgW2N1cnJlbnRXb3JsZF0pO1xuICAgICAgICAgICAgICAgIH0pXG4gICAgICAgICAgICAgICAgLmZhaWwoZHRkLnJlamVjdCk7XG5cbiAgICAgICAgICAgIHJldHVybiBkdGQucHJvbWlzZSgpO1xuICAgICAgICB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAqIERlbGV0ZXMgdGhlIGN1cnJlbnQgcnVuIGZyb20gdGhlIHdvcmxkLlxuICAgICAgICAqXG4gICAgICAgICogKE5vdGUgdGhhdCB0aGUgd29ybGQgaWQgcmVtYWlucyBwYXJ0IG9mIHRoZSBydW4gcmVjb3JkLCBpbmRpY2F0aW5nIHRoYXQgdGhlIHJ1biB3YXMgZm9ybWVybHkgYW4gYWN0aXZlIHJ1biBmb3IgdGhlIHdvcmxkLilcbiAgICAgICAgKlxuICAgICAgICAqICAqKkV4YW1wbGUqKlxuICAgICAgICAqXG4gICAgICAgICogICAgICB2YXIgd2EgPSBuZXcgRi5zZXJ2aWNlLldvcmxkKHtcbiAgICAgICAgKiAgICAgICAgICAgYWNjb3VudDogJ2FjbWUtc2ltdWxhdGlvbnMnLFxuICAgICAgICAqICAgICAgICAgICBwcm9qZWN0OiAnc3VwcGx5LWNoYWluLWdhbWUnLFxuICAgICAgICAqICAgICAgICAgICBncm91cDogJ3RlYW0xJyB9KTtcbiAgICAgICAgKlxuICAgICAgICAqICAgICAgd2EuZGVsZXRlUnVuKCdzYW1wbGUtd29ybGQtaWQnKTtcbiAgICAgICAgKlxuICAgICAgICAqICAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAqIEBwYXJhbSB7c3RyaW5nfSB3b3JsZElkIFRoZSBgd29ybGRJZGAgb2YgdGhlIHdvcmxkIGZyb20gd2hpY2ggdGhlIGN1cnJlbnQgcnVuIGlzIGJlaW5nIGRlbGV0ZWQuXG4gICAgICAgICogQHBhcmFtIHtvYmplY3R9IG9wdGlvbnMgKE9wdGlvbmFsKSBPcHRpb25zIG9iamVjdCB0byBvdmVycmlkZSBnbG9iYWwgb3B0aW9ucy5cbiAgICAgICAgKiBAcmV0dXJuIHtQcm9taXNlfVxuICAgICAgICAqL1xuICAgICAgICBkZWxldGVSdW46IGZ1bmN0aW9uICh3b3JsZElkLCBvcHRpb25zKSB7XG4gICAgICAgICAgICBvcHRpb25zID0gb3B0aW9ucyB8fCB7fTtcblxuICAgICAgICAgICAgaWYgKHdvcmxkSWQpIHtcbiAgICAgICAgICAgICAgICBvcHRpb25zLmZpbHRlciA9IHdvcmxkSWQ7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIHNldElkRmlsdGVyT3JUaHJvd0Vycm9yKG9wdGlvbnMpO1xuXG4gICAgICAgICAgICB2YXIgZGVsZXRlT3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LFxuICAgICAgICAgICAgICAgIHNlcnZpY2VPcHRpb25zLFxuICAgICAgICAgICAgICAgIG9wdGlvbnMsXG4gICAgICAgICAgICAgICAgeyB1cmw6IHVybENvbmZpZy5nZXRBUElQYXRoKGFwaUVuZHBvaW50KSArIHNlcnZpY2VPcHRpb25zLmZpbHRlciArICcvcnVuJyB9XG4gICAgICAgICAgICApO1xuXG4gICAgICAgICAgICByZXR1cm4gaHR0cC5kZWxldGUobnVsbCwgZGVsZXRlT3B0aW9ucyk7XG4gICAgICAgIH0sXG5cbiAgICAgICAgLyoqXG4gICAgICAgICogQ3JlYXRlcyBhIG5ldyBydW4gZm9yIHRoZSB3b3JsZC5cbiAgICAgICAgKlxuICAgICAgICAqICAqKkV4YW1wbGUqKlxuICAgICAgICAqXG4gICAgICAgICogICAgICB2YXIgd2EgPSBuZXcgRi5zZXJ2aWNlLldvcmxkKHtcbiAgICAgICAgKiAgICAgICAgICAgYWNjb3VudDogJ2FjbWUtc2ltdWxhdGlvbnMnLFxuICAgICAgICAqICAgICAgICAgICBwcm9qZWN0OiAnc3VwcGx5LWNoYWluLWdhbWUnLFxuICAgICAgICAqICAgICAgICAgICBncm91cDogJ3RlYW0xJyB9KTtcbiAgICAgICAgKlxuICAgICAgICAqICAgICAgd2EuZ2V0Q3VycmVudFdvcmxkRm9yVXNlcignOGYyNjA0Y2YtOTZjZC00NDlmLTgyZmEtZTMzMTUzMDczNGVlJylcbiAgICAgICAgKiAgICAgICAgICAgLnRoZW4oZnVuY3Rpb24gKHdvcmxkKSB7XG4gICAgICAgICogICAgICAgICAgICAgICAgICAgd2EubmV3UnVuRm9yV29ybGQod29ybGQuaWQpO1xuICAgICAgICAqICAgICAgICAgICB9KTtcbiAgICAgICAgKlxuICAgICAgICAqICAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAqIEBwYXJhbSB7c3RyaW5nfSB3b3JsZElkIHdvcmxkSWQgaW4gd2hpY2ggd2UgY3JlYXRlIHRoZSBuZXcgcnVuLlxuICAgICAgICAqIEBwYXJhbSB7b2JqZWN0fSBvcHRpb25zIChPcHRpb25hbCkgT3B0aW9ucyBvYmplY3QgdG8gb3ZlcnJpZGUgZ2xvYmFsIG9wdGlvbnMuXG4gICAgICAgICogQHBhcmFtIHtvYmplY3R9IG9wdGlvbnMubW9kZWwgVGhlIG1vZGVsIGZpbGUgdG8gdXNlIHRvIGNyZWF0ZSBhIHJ1biBpZiBuZWVkZWQuXG4gICAgICAgICogQHJldHVybiB7UHJvbWlzZX1cbiAgICAgICAgKi9cbiAgICAgICAgbmV3UnVuRm9yV29ybGQ6IGZ1bmN0aW9uICh3b3JsZElkLCBvcHRpb25zKSB7XG4gICAgICAgICAgICB2YXIgY3VycmVudFJ1bk9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSxcbiAgICAgICAgICAgICAgICBzZXJ2aWNlT3B0aW9ucyxcbiAgICAgICAgICAgICAgICBvcHRpb25zLFxuICAgICAgICAgICAgICAgIHsgZmlsdGVyOiB3b3JsZElkIHx8IHNlcnZpY2VPcHRpb25zLmZpbHRlciB9XG4gICAgICAgICAgICApO1xuICAgICAgICAgICAgdmFyIG1lID0gdGhpcztcblxuICAgICAgICAgICAgdmFsaWRhdGVNb2RlbE9yVGhyb3dFcnJvcihjdXJyZW50UnVuT3B0aW9ucyk7XG5cbiAgICAgICAgICAgIHJldHVybiB0aGlzLmRlbGV0ZVJ1bih3b3JsZElkLCBvcHRpb25zKVxuICAgICAgICAgICAgICAgIC50aGVuKGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIG1lLmdldEN1cnJlbnRSdW5JZChjdXJyZW50UnVuT3B0aW9ucyk7XG4gICAgICAgICAgICAgICAgfSk7XG4gICAgICAgIH0sXG5cbiAgICAgICAgLyoqXG4gICAgICAgICogQXNzaWducyBlbmQgdXNlcnMgdG8gd29ybGRzLCBjcmVhdGluZyBuZXcgd29ybGRzIGFzIGFwcHJvcHJpYXRlLCBhdXRvbWF0aWNhbGx5LiBBc3NpZ25zIGFsbCBlbmQgdXNlcnMgaW4gdGhlIGdyb3VwLCBhbmQgY3JlYXRlcyBuZXcgd29ybGRzIGFzIG5lZWRlZCBiYXNlZCBvbiB0aGUgcHJvamVjdC1sZXZlbCB3b3JsZCBjb25maWd1cmF0aW9uIChyb2xlcywgb3B0aW9uYWwgcm9sZXMsIGFuZCBtaW5pbXVtIGVuZCB1c2VycyBwZXIgd29ybGQpLlxuICAgICAgICAqXG4gICAgICAgICogKipFeGFtcGxlKipcbiAgICAgICAgKlxuICAgICAgICAqICAgICAgdmFyIHdhID0gbmV3IEYuc2VydmljZS5Xb3JsZCh7XG4gICAgICAgICogICAgICAgICAgIGFjY291bnQ6ICdhY21lLXNpbXVsYXRpb25zJyxcbiAgICAgICAgKiAgICAgICAgICAgcHJvamVjdDogJ3N1cHBseS1jaGFpbi1nYW1lJyxcbiAgICAgICAgKiAgICAgICAgICAgZ3JvdXA6ICd0ZWFtMScgfSk7XG4gICAgICAgICpcbiAgICAgICAgKiAgICAgIHdhLmF1dG9Bc3NpZ24oKTtcbiAgICAgICAgKlxuICAgICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICAgICogQHBhcmFtIHtvYmplY3R9IG9wdGlvbnMgKE9wdGlvbmFsKSBPcHRpb25zIG9iamVjdCB0byBvdmVycmlkZSBnbG9iYWwgb3B0aW9ucy5cbiAgICAgICAgKiBAcGFyYW0ge251bWJlcn0gb3B0aW9ucy5tYXhVc2VycyBTZXRzIHRoZSBtYXhpbXVtIG51bWJlciBvZiB1c2VycyBpbiBhIHdvcmxkLlxuICAgICAgICAqIEBwYXJhbSB7c3RyaW5nW119IG9wdGlvbnMudXNlcklkcyBBIGxpc3Qgb2YgdXNlcnMgdG8gYmUgYXNzaWduZWQgYmUgYXNzaWduZWQgaW5zdGVhZCBvZiBhbGwgZW5kIHVzZXJzIGluIHRoZSBncm91cC5cbiAgICAgICAgKiBAcmV0dXJuIHtQcm9taXNlfVxuICAgICAgICAqXG4gICAgICAgICovXG4gICAgICAgIGF1dG9Bc3NpZ246IGZ1bmN0aW9uIChvcHRpb25zKSB7XG4gICAgICAgICAgICBvcHRpb25zID0gb3B0aW9ucyB8fCB7fTtcblxuICAgICAgICAgICAgdmFyIG9wdCA9ICQuZXh0ZW5kKHRydWUsIHt9LFxuICAgICAgICAgICAgICAgIHNlcnZpY2VPcHRpb25zLFxuICAgICAgICAgICAgICAgIG9wdGlvbnMsXG4gICAgICAgICAgICAgICAgeyB1cmw6IHVybENvbmZpZy5nZXRBUElQYXRoKGFzc2lnbm1lbnRFbmRwb2ludCkgfVxuICAgICAgICAgICAgKTtcblxuICAgICAgICAgICAgdmFyIHBhcmFtcyA9IHtcbiAgICAgICAgICAgICAgICBhY2NvdW50OiBvcHQuYWNjb3VudCxcbiAgICAgICAgICAgICAgICBwcm9qZWN0OiBvcHQucHJvamVjdCxcbiAgICAgICAgICAgICAgICBncm91cDogb3B0Lmdyb3VwXG4gICAgICAgICAgICB9O1xuXG4gICAgICAgICAgICBpZiAob3B0Lm1heFVzZXJzKSB7XG4gICAgICAgICAgICAgICAgcGFyYW1zLm1heFVzZXJzID0gb3B0Lm1heFVzZXJzO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICBpZiAob3B0LnVzZXJJZHMpIHtcbiAgICAgICAgICAgICAgICBwYXJhbXMudXNlcklkcyA9IG9wdC51c2VySWRzO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICByZXR1cm4gaHR0cC5wb3N0KHBhcmFtcywgb3B0KTtcbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgKiBHZXRzIHRoZSBwcm9qZWN0J3Mgd29ybGQgY29uZmlndXJhdGlvbi5cbiAgICAgICAgKlxuICAgICAgICAqIFR5cGljYWxseSwgZXZlcnkgaW50ZXJhY3Rpb24gd2l0aCB5b3VyIHByb2plY3QgdXNlcyB0aGUgc2FtZSBjb25maWd1cmF0aW9uIG9mIGVhY2ggd29ybGQuIEZvciBleGFtcGxlLCBlYWNoIHdvcmxkIGluIHlvdXIgcHJvamVjdCBwcm9iYWJseSBoYXMgdGhlIHNhbWUgcm9sZXMgZm9yIGVuZCB1c2Vycy4gQW5kIHlvdXIgcHJvamVjdCBpcyBwcm9iYWJseSBlaXRoZXIgY29uZmlndXJlZCBzbyB0aGF0IGFsbCBlbmQgdXNlcnMgc2hhcmUgdGhlIHNhbWUgd29ybGQgKGFuZCBydW4pLCBvciBzbWFsbGVyIHNldHMgb2YgZW5kIHVzZXJzIHNoYXJlIHdvcmxkcyDigJQgYnV0IG5vdCBib3RoLlxuICAgICAgICAqXG4gICAgICAgICogKFRoZSBbTXVsdGlwbGF5ZXIgUHJvamVjdCBSRVNUIEFQSV0oLi4vLi4vLi4vcmVzdF9hcGlzL211bHRpcGxheWVyL211bHRpcGxheWVyX3Byb2plY3QvKSBhbGxvd3MgeW91IHRvIHNldCB0aGVzZSBwcm9qZWN0LWxldmVsIHdvcmxkIGNvbmZpZ3VyYXRpb25zLiBUaGUgV29ybGQgQWRhcHRlciBzaW1wbHkgcmV0cmlldmVzIHRoZW0sIGZvciBleGFtcGxlIHNvIHRoZXkgY2FuIGJlIHVzZWQgaW4gYXV0by1hc3NpZ25tZW50IG9mIGVuZCB1c2VycyB0byB3b3JsZHMuKVxuICAgICAgICAqXG4gICAgICAgICogKipFeGFtcGxlKipcbiAgICAgICAgKlxuICAgICAgICAqICAgICAgdmFyIHdhID0gbmV3IEYuc2VydmljZS5Xb3JsZCh7XG4gICAgICAgICogICAgICAgICAgIGFjY291bnQ6ICdhY21lLXNpbXVsYXRpb25zJyxcbiAgICAgICAgKiAgICAgICAgICAgcHJvamVjdDogJ3N1cHBseS1jaGFpbi1nYW1lJyxcbiAgICAgICAgKiAgICAgICAgICAgZ3JvdXA6ICd0ZWFtMScgfSk7XG4gICAgICAgICpcbiAgICAgICAgKiAgICAgIHdhLmdldFByb2plY3RTZXR0aW5ncygpXG4gICAgICAgICogICAgICAgICAgIC50aGVuKGZ1bmN0aW9uKHNldHRpbmdzKSB7XG4gICAgICAgICogICAgICAgICAgICAgICBjb25zb2xlLmxvZyhzZXR0aW5ncy5yb2xlcyk7XG4gICAgICAgICogICAgICAgICAgICAgICBjb25zb2xlLmxvZyhzZXR0aW5ncy5vcHRpb25hbFJvbGVzKTtcbiAgICAgICAgKiAgICAgICAgICAgfSk7XG4gICAgICAgICpcbiAgICAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAqIEBwYXJhbSB7b2JqZWN0fSBvcHRpb25zIChPcHRpb25hbCkgT3B0aW9ucyBvYmplY3QgdG8gb3ZlcnJpZGUgZ2xvYmFsIG9wdGlvbnMuXG4gICAgICAgICogQHJldHVybiB7UHJvbWlzZX1cbiAgICAgICAgKi9cbiAgICAgICAgZ2V0UHJvamVjdFNldHRpbmdzOiBmdW5jdGlvbiAob3B0aW9ucykge1xuICAgICAgICAgICAgb3B0aW9ucyA9IG9wdGlvbnMgfHwge307XG5cbiAgICAgICAgICAgIHZhciBvcHQgPSAkLmV4dGVuZCh0cnVlLCB7fSxcbiAgICAgICAgICAgICAgICBzZXJ2aWNlT3B0aW9ucyxcbiAgICAgICAgICAgICAgICBvcHRpb25zLFxuICAgICAgICAgICAgICAgIHsgdXJsOiB1cmxDb25maWcuZ2V0QVBJUGF0aChwcm9qZWN0RW5kcG9pbnQpIH1cbiAgICAgICAgICAgICk7XG5cbiAgICAgICAgICAgIG9wdC51cmwgKz0gW29wdC5hY2NvdW50LCBvcHQucHJvamVjdF0uam9pbignLycpO1xuICAgICAgICAgICAgcmV0dXJuIGh0dHAuZ2V0KG51bGwsIG9wdCk7XG4gICAgICAgIH1cblxuICAgIH07XG5cbiAgICAkLmV4dGVuZCh0aGlzLCBwdWJsaWNBUEkpO1xufTtcbiIsIi8qKlxuICogQGNsYXNzIENvb2tpZSBTdG9yYWdlIFNlcnZpY2VcbiAqXG4gKiBAZXhhbXBsZVxuICogICAgICB2YXIgcGVvcGxlID0gcmVxdWlyZSgnY29va2llLXN0b3JlJykoeyByb290OiAncGVvcGxlJyB9KTtcbiAgICAgICAgcGVvcGxlXG4gICAgICAgICAgICAuc2F2ZSh7bGFzdE5hbWU6ICdzbWl0aCcgfSlcblxuICovXG5cblxuJ3VzZSBzdHJpY3QnO1xuXG4vLyBUaGluIGRvY3VtZW50LmNvb2tpZSB3cmFwcGVyIHRvIGFsbG93IHVuaXQgdGVzdGluZ1xudmFyIENvb2tpZSA9IGZ1bmN0aW9uICgpIHtcbiAgICB0aGlzLmdldCA9IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgcmV0dXJuIGRvY3VtZW50LmNvb2tpZTtcbiAgICB9O1xuXG4gICAgdGhpcy5zZXQgPSBmdW5jdGlvbiAobmV3Q29va2llKSB7XG4gICAgICAgIGRvY3VtZW50LmNvb2tpZSA9IG5ld0Nvb2tpZTtcbiAgICB9O1xufTtcblxubW9kdWxlLmV4cG9ydHMgPSBmdW5jdGlvbiAoY29uZmlnKSB7XG4gICAgdmFyIGhvc3QgPSB3aW5kb3cubG9jYXRpb24uaG9zdG5hbWU7XG4gICAgdmFyIHZhbGlkSG9zdCA9IGhvc3Quc3BsaXQoJy4nKS5sZW5ndGggPiAxO1xuICAgIHZhciBkb21haW4gPSB2YWxpZEhvc3QgPyAnLicgKyBob3N0IDogbnVsbDtcblxuICAgIHZhciBkZWZhdWx0cyA9IHtcbiAgICAgICAgLyoqXG4gICAgICAgICAqIE5hbWUgb2YgY29sbGVjdGlvblxuICAgICAgICAgKiBAdHlwZSB7IHN0cmluZ31cbiAgICAgICAgICovXG4gICAgICAgIHJvb3Q6ICcvJyxcblxuICAgICAgICBkb21haW46IGRvbWFpbixcbiAgICAgICAgY29va2llOiBuZXcgQ29va2llKClcbiAgICB9O1xuICAgIHRoaXMuc2VydmljZU9wdGlvbnMgPSAkLmV4dGVuZCh7fSwgZGVmYXVsdHMsIGNvbmZpZyk7XG5cbiAgICB2YXIgcHVibGljQVBJID0ge1xuICAgICAgICAvLyAqIFRCRFxuICAgICAgICAvLyAgKiBRdWVyeSBjb2xsZWN0aW9uOyB1c2VzIE1vbmdvREIgc3ludGF4XG4gICAgICAgIC8vICAqIEBzZWUgIDxUQkQ6IERhdGEgQVBJIFVSTD5cbiAgICAgICAgLy8gICpcbiAgICAgICAgLy8gICogQHBhcmFtIHsgc3RyaW5nfSBxcyBRdWVyeSBGaWx0ZXJcbiAgICAgICAgLy8gICogQHBhcmFtIHsgc3RyaW5nfSBsaW1pdGVycyBAc2VlIDxUQkQ6IHVybCBmb3IgbGltaXRzLCBwYWdpbmcgZXRjPlxuICAgICAgICAvLyAgKlxuICAgICAgICAvLyAgKiBAZXhhbXBsZVxuICAgICAgICAvLyAgKiAgICAgY3MucXVlcnkoXG4gICAgICAgIC8vICAqICAgICAgeyBuYW1lOiAnSm9obicsIGNsYXNzTmFtZTogJ0NTQzEwMScgfSxcbiAgICAgICAgLy8gICogICAgICB7bGltaXQ6IDEwfVxuICAgICAgICAvLyAgKiAgICAgKVxuXG4gICAgICAgIC8vIHF1ZXJ5OiBmdW5jdGlvbiAocXMsIGxpbWl0ZXJzKSB7XG5cbiAgICAgICAgLy8gfSxcblxuICAgICAgICAvKipcbiAgICAgICAgICogU2F2ZSBjb29raWUgdmFsdWVcbiAgICAgICAgICogQHBhcmFtICB7IHN0cmluZ3xPYmplY3R9IGtleSAgIElmIGdpdmVuIGEga2V5IHNhdmUgdmFsdWVzIHVuZGVyIGl0LCBpZiBnaXZlbiBhbiBvYmplY3QgZGlyZWN0bHksIHNhdmUgdG8gdG9wLWxldmVsIGFwaVxuICAgICAgICAgKiBAcGFyYW0gIHtPYmplY3R9IHZhbHVlIChPcHRpb25hbClcbiAgICAgICAgICogQHBhcmFtIHtPYmplY3R9IG9wdGlvbnMgT3ZlcnJpZGVzIGZvciBzZXJ2aWNlIG9wdGlvbnNcbiAgICAgICAgICpcbiAgICAgICAgICogQHJldHVybiB7Kn0gVGhlIHNhdmVkIHZhbHVlXG4gICAgICAgICAqXG4gICAgICAgICAqIEBleGFtcGxlXG4gICAgICAgICAqICAgICBjcy5zZXQoJ3BlcnNvbicsIHsgZmlyc3ROYW1lOiAnam9obicsIGxhc3ROYW1lOiAnc21pdGgnIH0pO1xuICAgICAgICAgKiAgICAgY3Muc2V0KHsgbmFtZTonc21pdGgnLCBhZ2U6JzMyJyB9KTtcbiAgICAgICAgICovXG4gICAgICAgIHNldDogZnVuY3Rpb24gKGtleSwgdmFsdWUsIG9wdGlvbnMpIHtcbiAgICAgICAgICAgIHZhciBzZXRPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sIHRoaXMuc2VydmljZU9wdGlvbnMsIG9wdGlvbnMpO1xuXG4gICAgICAgICAgICB2YXIgZG9tYWluID0gc2V0T3B0aW9ucy5kb21haW47XG4gICAgICAgICAgICB2YXIgcGF0aCA9IHNldE9wdGlvbnMucm9vdDtcbiAgICAgICAgICAgIHZhciBjb29raWUgPSBzZXRPcHRpb25zLmNvb2tpZTtcblxuICAgICAgICAgICAgY29va2llLnNldChlbmNvZGVVUklDb21wb25lbnQoa2V5KSArICc9JyArXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGVuY29kZVVSSUNvbXBvbmVudCh2YWx1ZSkgK1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAoZG9tYWluID8gJzsgZG9tYWluPScgKyBkb21haW4gOiAnJykgK1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAocGF0aCA/ICc7IHBhdGg9JyArIHBhdGggOiAnJylcbiAgICAgICAgICAgICk7XG5cbiAgICAgICAgICAgIHJldHVybiB2YWx1ZTtcbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgICogTG9hZCBjb29raWUgdmFsdWVcbiAgICAgICAgICogQHBhcmFtICB7IHN0cmluZ3xPYmplY3R9IGtleSAgIElmIGdpdmVuIGEga2V5IHNhdmUgdmFsdWVzIHVuZGVyIGl0LCBpZiBnaXZlbiBhbiBvYmplY3QgZGlyZWN0bHksIHNhdmUgdG8gdG9wLWxldmVsIGFwaVxuICAgICAgICAgKiBAcmV0dXJuIHsqfSBUaGUgdmFsdWUgc3RvcmVkXG4gICAgICAgICAqXG4gICAgICAgICAqIEBleGFtcGxlXG4gICAgICAgICAqICAgICBjcy5nZXQoJ3BlcnNvbicpO1xuICAgICAgICAgKi9cbiAgICAgICAgZ2V0OiBmdW5jdGlvbiAoa2V5KSB7XG4gICAgICAgICAgICB2YXIgY29va2llID0gdGhpcy5zZXJ2aWNlT3B0aW9ucy5jb29raWU7XG4gICAgICAgICAgICB2YXIgY29va2llUmVnID0gbmV3IFJlZ0V4cCgnKD86Xnw7KVxcXFxzKicgKyBlbmNvZGVVUklDb21wb25lbnQoa2V5KS5yZXBsYWNlKC9bXFwtXFwuXFwrXFwqXS9nLCAnXFxcXCQmJykgKyAnXFxcXHMqXFxcXD1cXFxccyooW147XSopLiokJyk7XG4gICAgICAgICAgICB2YXIgcmVzID0gY29va2llUmVnLmV4ZWMoY29va2llLmdldCgpKTtcbiAgICAgICAgICAgIHZhciB2YWwgPSByZXMgPyBkZWNvZGVVUklDb21wb25lbnQocmVzWzFdKSA6IG51bGw7XG4gICAgICAgICAgICByZXR1cm4gdmFsO1xuICAgICAgICB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBSZW1vdmVzIGtleSBmcm9tIGNvbGxlY3Rpb25cbiAgICAgICAgICogQHBhcmFtIHsgc3RyaW5nfSBrZXkga2V5IHRvIHJlbW92ZVxuICAgICAgICAgKiBAcGFyYW0ge29iamVjdH0gb3B0aW9ucyAob3B0aW9uYWwpIG92ZXJyaWRlcyBmb3Igc2VydmljZSBvcHRpb25zXG4gICAgICAgICAqIEByZXR1cm4geyBzdHJpbmd9IGtleSBUaGUga2V5IHJlbW92ZWRcbiAgICAgICAgICpcbiAgICAgICAgICogQGV4YW1wbGVcbiAgICAgICAgICogICAgIGNzLnJlbW92ZSgncGVyc29uJyk7XG4gICAgICAgICAqL1xuICAgICAgICByZW1vdmU6IGZ1bmN0aW9uIChrZXksIG9wdGlvbnMpIHtcbiAgICAgICAgICAgIHZhciByZW1PcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sIHRoaXMuc2VydmljZU9wdGlvbnMsIG9wdGlvbnMpO1xuXG4gICAgICAgICAgICB2YXIgZG9tYWluID0gcmVtT3B0aW9ucy5kb21haW47XG4gICAgICAgICAgICB2YXIgcGF0aCA9IHJlbU9wdGlvbnMucm9vdDtcbiAgICAgICAgICAgIHZhciBjb29raWUgPSByZW1PcHRpb25zLmNvb2tpZTtcblxuICAgICAgICAgICAgY29va2llLnNldChlbmNvZGVVUklDb21wb25lbnQoa2V5KSArXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgJz07IGV4cGlyZXM9VGh1LCAwMSBKYW4gMTk3MCAwMDowMDowMCBHTVQnICtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAoZG9tYWluID8gJzsgZG9tYWluPScgKyBkb21haW4gOiAnJykgK1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIChwYXRoID8gJzsgcGF0aD0nICsgcGF0aCA6ICcnKVxuICAgICAgICAgICAgKTtcbiAgICAgICAgICAgIHJldHVybiBrZXk7XG4gICAgICAgIH0sXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIFJlbW92ZXMgY29sbGVjdGlvbiBiZWluZyByZWZlcmVuY2VkXG4gICAgICAgICAqIEByZXR1cm4geyBhcnJheX0ga2V5cyBBbGwgdGhlIGtleXMgcmVtb3ZlZFxuICAgICAgICAgKi9cbiAgICAgICAgZGVzdHJveTogZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgdmFyIGNvb2tpZSA9IHRoaXMuc2VydmljZU9wdGlvbnMuY29va2llO1xuICAgICAgICAgICAgdmFyIGFLZXlzID0gY29va2llLmdldCgpLnJlcGxhY2UoLygoPzpefFxccyo7KVteXFw9XSspKD89O3wkKXxeXFxzKnxcXHMqKD86XFw9W147XSopPyg/OlxcMXwkKS9nLCAnJykuc3BsaXQoL1xccyooPzpcXD1bXjtdKik/O1xccyovKTtcbiAgICAgICAgICAgIGZvciAodmFyIG5JZHggPSAwOyBuSWR4IDwgYUtleXMubGVuZ3RoOyBuSWR4KyspIHtcbiAgICAgICAgICAgICAgICB2YXIgY29va2llS2V5ID0gZGVjb2RlVVJJQ29tcG9uZW50KGFLZXlzW25JZHhdKTtcbiAgICAgICAgICAgICAgICB0aGlzLnJlbW92ZShjb29raWVLZXkpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgcmV0dXJuIGFLZXlzO1xuICAgICAgICB9XG4gICAgfTtcblxuICAgICQuZXh0ZW5kKHRoaXMsIHB1YmxpY0FQSSk7XG59O1xuIiwiJ3VzZSBzdHJpY3QnO1xuXG52YXIga2V5TmFtZXMgPSByZXF1aXJlKCcuLi9tYW5hZ2Vycy9rZXktbmFtZXMnKTtcbnZhciBTdG9yYWdlRmFjdG9yeSA9IHJlcXVpcmUoJy4vc3RvcmUtZmFjdG9yeScpO1xudmFyIG9wdGlvblV0aWxzID0gcmVxdWlyZSgnLi4vdXRpbC9vcHRpb24tdXRpbHMnKTtcblxudmFyIEVQSV9TRVNTSU9OX0tFWSA9IGtleU5hbWVzLkVQSV9TRVNTSU9OX0tFWTtcbnZhciBFUElfTUFOQUdFUl9LRVkgPSAnZXBpY2VudGVyLnRva2VuJzsgLy9jYW4ndCBiZSB1bmRlciBrZXktbmFtZXMsIG9yIGxvZ291dCB3aWxsIGNsZWFyIHRoaXMgdG9vXG5cbnZhciBkZWZhdWx0cyA9IHtcbiAgICAvKipcbiAgICAgKiBXaGVyZSB0byBzdG9yZSB1c2VyIGFjY2VzcyB0b2tlbnMgZm9yIHRlbXBvcmFyeSBhY2Nlc3MuIERlZmF1bHRzIHRvIHN0b3JpbmcgaW4gYSBjb29raWUgaW4gdGhlIGJyb3dzZXIuXG4gICAgICogQHR5cGUge3N0cmluZ31cbiAgICAgKi9cbiAgICBzdG9yZTogeyBzeW5jaHJvbm91czogdHJ1ZSB9XG59O1xuXG52YXIgU2Vzc2lvbk1hbmFnZXIgPSBmdW5jdGlvbiAobWFuYWdlck9wdGlvbnMpIHtcbiAgICBtYW5hZ2VyT3B0aW9ucyA9IG1hbmFnZXJPcHRpb25zIHx8IHt9O1xuICAgIGZ1bmN0aW9uIGdldEJhc2VPcHRpb25zKG92ZXJyaWRlcykge1xuICAgICAgICBvdmVycmlkZXMgPSBvdmVycmlkZXMgfHwge307XG4gICAgICAgIHZhciBsaWJPcHRpb25zID0gb3B0aW9uVXRpbHMuZ2V0T3B0aW9ucygpO1xuICAgICAgICB2YXIgZmluYWxPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sIGRlZmF1bHRzLCBsaWJPcHRpb25zLCBtYW5hZ2VyT3B0aW9ucywgb3ZlcnJpZGVzKTtcbiAgICAgICAgcmV0dXJuIGZpbmFsT3B0aW9ucztcbiAgICB9XG5cbiAgICBmdW5jdGlvbiBnZXRTdG9yZShvdmVycmlkZXMpIHtcbiAgICAgICAgdmFyIGJhc2VPcHRpb25zID0gZ2V0QmFzZU9wdGlvbnMob3ZlcnJpZGVzKTtcbiAgICAgICAgdmFyIHN0b3JlT3B0cyA9IGJhc2VPcHRpb25zLnN0b3JlIHx8IHt9O1xuICAgICAgICB2YXIgaXNFcGljZW50ZXJEb21haW4gPSAhYmFzZU9wdGlvbnMuaXNMb2NhbCAmJiAhYmFzZU9wdGlvbnMuaXNDdXN0b21Eb21haW47XG4gICAgICAgIGlmIChzdG9yZU9wdHMucm9vdCA9PT0gdW5kZWZpbmVkICYmIGJhc2VPcHRpb25zLmFjY291bnQgJiYgYmFzZU9wdGlvbnMucHJvamVjdCAmJiBpc0VwaWNlbnRlckRvbWFpbikge1xuICAgICAgICAgICAgc3RvcmVPcHRzLnJvb3QgPSAnL2FwcC8nICsgYmFzZU9wdGlvbnMuYWNjb3VudCArICcvJyArIGJhc2VPcHRpb25zLnByb2plY3Q7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIG5ldyBTdG9yYWdlRmFjdG9yeShzdG9yZU9wdHMpO1xuICAgIH1cblxuICAgIHZhciBwdWJsaWNBUEkgPSB7XG4gICAgICAgIHNhdmVTZXNzaW9uOiBmdW5jdGlvbiAodXNlckluZm8sIG9wdGlvbnMpIHtcbiAgICAgICAgICAgIHZhciBzZXJpYWxpemVkID0gSlNPTi5zdHJpbmdpZnkodXNlckluZm8pO1xuICAgICAgICAgICAgZ2V0U3RvcmUob3B0aW9ucykuc2V0KEVQSV9TRVNTSU9OX0tFWSwgc2VyaWFsaXplZCk7XG4gICAgICAgIH0sXG4gICAgICAgIGdldFNlc3Npb246IGZ1bmN0aW9uIChvcHRpb25zKSB7XG4gICAgICAgICAgICB2YXIgc3RvcmUgPSBnZXRTdG9yZShvcHRpb25zKTtcbiAgICAgICAgICAgIHZhciBmaW5hbE9wdHMgPSBzdG9yZS5zZXJ2aWNlT3B0aW9ucztcbiAgICAgICAgICAgIHZhciBzZXJpYWxpemVkID0gc3RvcmUuZ2V0KEVQSV9TRVNTSU9OX0tFWSkgfHwgJ3t9JztcbiAgICAgICAgICAgIHZhciBzZXNzaW9uID0gSlNPTi5wYXJzZShzZXJpYWxpemVkKTtcbiAgICAgICAgICAgIC8vIElmIHRoZSB1cmwgY29udGFpbnMgdGhlIHByb2plY3QgYW5kIGFjY291bnRcbiAgICAgICAgICAgIC8vIHZhbGlkYXRlIHRoZSBhY2NvdW50IGFuZCBwcm9qZWN0IGluIHRoZSBzZXNzaW9uXG4gICAgICAgICAgICAvLyBhbmQgb3ZlcnJpZGUgcHJvamVjdCwgZ3JvdXBOYW1lLCBncm91cElkIGFuZCBpc0ZhY1xuICAgICAgICAgICAgLy8gT3RoZXJ3aXNlIChpLmUuIGxvY2FsaG9zdCkgdXNlIHRoZSBzYXZlZCBzZXNzaW9uIHZhbHVlc1xuICAgICAgICAgICAgdmFyIGFjY291bnQgPSBmaW5hbE9wdHMuYWNjb3VudDtcbiAgICAgICAgICAgIHZhciBwcm9qZWN0ID0gZmluYWxPcHRzLnByb2plY3Q7XG4gICAgICAgICAgICBpZiAoYWNjb3VudCAmJiBzZXNzaW9uLmFjY291bnQgIT09IGFjY291bnQpIHtcbiAgICAgICAgICAgICAgICAvLyBUaGlzIG1lYW5zIHRoYXQgdGhlIHRva2VuIHdhcyBub3QgdXNlZCB0byBsb2dpbiB0byB0aGUgc2FtZSBhY2NvdW50XG4gICAgICAgICAgICAgICAgcmV0dXJuIHt9O1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgaWYgKHNlc3Npb24uZ3JvdXBzICYmIGFjY291bnQgJiYgcHJvamVjdCkge1xuICAgICAgICAgICAgICAgIHZhciBncm91cCA9IHNlc3Npb24uZ3JvdXBzW3Byb2plY3RdIHx8IHsgZ3JvdXBJZDogJycsIGdyb3VwTmFtZTogJycsIGlzRmFjOiBmYWxzZSB9O1xuICAgICAgICAgICAgICAgICQuZXh0ZW5kKHNlc3Npb24sIHsgcHJvamVjdDogcHJvamVjdCB9LCBncm91cCk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICByZXR1cm4gc2Vzc2lvbjtcbiAgICAgICAgfSxcbiAgICAgICAgcmVtb3ZlU2Vzc2lvbjogZnVuY3Rpb24gKG9wdGlvbnMpIHtcbiAgICAgICAgICAgIHZhciBzdG9yZSA9IGdldFN0b3JlKG9wdGlvbnMpO1xuICAgICAgICAgICAgT2JqZWN0LmtleXMoa2V5TmFtZXMpLmZvckVhY2goZnVuY3Rpb24gKGNvb2tpZUtleSkge1xuICAgICAgICAgICAgICAgIHZhciBjb29raWVOYW1lID0ga2V5TmFtZXNbY29va2llS2V5XTtcbiAgICAgICAgICAgICAgICBzdG9yZS5yZW1vdmUoY29va2llTmFtZSk7XG4gICAgICAgICAgICB9KTtcbiAgICAgICAgICAgIHJldHVybiB0cnVlO1xuICAgICAgICB9LFxuICAgICAgICBnZXRTdG9yZTogZnVuY3Rpb24gKG9wdGlvbnMpIHtcbiAgICAgICAgICAgIHJldHVybiBnZXRTdG9yZShvcHRpb25zKTtcbiAgICAgICAgfSxcblxuICAgICAgICBnZXRNZXJnZWRPcHRpb25zOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICB2YXIgYXJncyA9IEFycmF5LnByb3RvdHlwZS5zbGljZS5jYWxsKGFyZ3VtZW50cyk7XG4gICAgICAgICAgICB2YXIgb3ZlcnJpZGVzID0gJC5leHRlbmQuYXBwbHkoJCwgW3RydWUsIHt9XS5jb25jYXQoYXJncykpO1xuICAgICAgICAgICAgdmFyIGJhc2VPcHRpb25zID0gZ2V0QmFzZU9wdGlvbnMob3ZlcnJpZGVzKTtcbiAgICAgICAgICAgIHZhciBzZXNzaW9uID0gdGhpcy5nZXRTZXNzaW9uKG92ZXJyaWRlcyk7XG5cbiAgICAgICAgICAgIHZhciB0b2tlbiA9IHNlc3Npb24uYXV0aF90b2tlbjtcbiAgICAgICAgICAgIGlmICghdG9rZW4pIHtcbiAgICAgICAgICAgICAgICB2YXIgZmFjdG9yeSA9IG5ldyBTdG9yYWdlRmFjdG9yeSgpO1xuICAgICAgICAgICAgICAgIHRva2VuID0gZmFjdG9yeS5nZXQoRVBJX01BTkFHRVJfS0VZKTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgdmFyIHNlc3Npb25EZWZhdWx0cyA9IHtcbiAgICAgICAgICAgICAgICAvKipcbiAgICAgICAgICAgICAgICAgKiBGb3IgcHJvamVjdHMgdGhhdCByZXF1aXJlIGF1dGhlbnRpY2F0aW9uLCBwYXNzIGluIHRoZSB1c2VyIGFjY2VzcyB0b2tlbiAoZGVmYXVsdHMgdG8gZW1wdHkgc3RyaW5nKS4gSWYgdGhlIHVzZXIgaXMgYWxyZWFkeSBsb2dnZWQgaW4gdG8gRXBpY2VudGVyLCB0aGUgdXNlciBhY2Nlc3MgdG9rZW4gaXMgYWxyZWFkeSBzZXQgaW4gYSBjb29raWUgYW5kIGF1dG9tYXRpY2FsbHkgbG9hZGVkIGZyb20gdGhlcmUuIChTZWUgW21vcmUgYmFja2dyb3VuZCBvbiBhY2Nlc3MgdG9rZW5zXSguLi8uLi8uLi9wcm9qZWN0X2FjY2Vzcy8pKS5cbiAgICAgICAgICAgICAgICAgKiBAc2VlIFtBdXRoZW50aWNhdGlvbiBBUEkgU2VydmljZV0oLi4vYXV0aC1hcGktc2VydmljZS8pIGZvciBnZXR0aW5nIHRva2Vucy5cbiAgICAgICAgICAgICAgICAgKiBAdHlwZSB7U3RyaW5nfVxuICAgICAgICAgICAgICAgICAqL1xuICAgICAgICAgICAgICAgIHRva2VuOiB0b2tlbixcblxuICAgICAgICAgICAgICAgIC8qKlxuICAgICAgICAgICAgICAgICAqIFRoZSBhY2NvdW50LiBJZiBsZWZ0IHVuZGVmaW5lZCwgdGFrZW4gZnJvbSB0aGUgY29va2llIHNlc3Npb24uXG4gICAgICAgICAgICAgICAgICogQHR5cGUge1N0cmluZ31cbiAgICAgICAgICAgICAgICAgKi9cbiAgICAgICAgICAgICAgICBhY2NvdW50OiBzZXNzaW9uLmFjY291bnQsXG5cbiAgICAgICAgICAgICAgICAvKipcbiAgICAgICAgICAgICAgICAgKiBUaGUgcHJvamVjdC4gSWYgbGVmdCB1bmRlZmluZWQsIHRha2VuIGZyb20gdGhlIGNvb2tpZSBzZXNzaW9uLlxuICAgICAgICAgICAgICAgICAqIEB0eXBlIHtTdHJpbmd9XG4gICAgICAgICAgICAgICAgICovXG4gICAgICAgICAgICAgICAgcHJvamVjdDogc2Vzc2lvbi5wcm9qZWN0LFxuXG5cbiAgICAgICAgICAgICAgICAvKipcbiAgICAgICAgICAgICAgICAgKiBUaGUgZ3JvdXAgbmFtZS4gSWYgbGVmdCB1bmRlZmluZWQsIHRha2VuIGZyb20gdGhlIGNvb2tpZSBzZXNzaW9uLlxuICAgICAgICAgICAgICAgICAqIEB0eXBlIHtTdHJpbmd9XG4gICAgICAgICAgICAgICAgICovXG4gICAgICAgICAgICAgICAgZ3JvdXA6IHNlc3Npb24uZ3JvdXBOYW1lLFxuICAgICAgICAgICAgICAgIC8qKlxuICAgICAgICAgICAgICAgICAqIEFsaWFzIGZvciBncm91cC4gXG4gICAgICAgICAgICAgICAgICogQHR5cGUge1N0cmluZ31cbiAgICAgICAgICAgICAgICAgKi9cbiAgICAgICAgICAgICAgICBncm91cE5hbWU6IHNlc3Npb24uZ3JvdXBOYW1lLCAvL0l0J3MgYSBsaXR0bGUgd2VpcmQgdGhhdCBpdCdzIGNhbGxlZCBncm91cE5hbWUgaW4gdGhlIGNvb2tpZSwgYnV0ICdncm91cCcgaW4gYWxsIHRoZSBzZXJ2aWNlIG9wdGlvbnMsIHNvIG5vcm1hbGl6ZSBmb3IgYm90aFxuICAgICAgICAgICAgICAgIC8qKlxuICAgICAgICAgICAgICAgICAqIFRoZSBncm91cCBpZC4gSWYgbGVmdCB1bmRlZmluZWQsIHRha2VuIGZyb20gdGhlIGNvb2tpZSBzZXNzaW9uLlxuICAgICAgICAgICAgICAgICAqIEB0eXBlIHtTdHJpbmd9XG4gICAgICAgICAgICAgICAgICovXG4gICAgICAgICAgICAgICAgZ3JvdXBJZDogc2Vzc2lvbi5ncm91cElkLFxuICAgICAgICAgICAgICAgIHVzZXJJZDogc2Vzc2lvbi51c2VySWQsXG4gICAgICAgICAgICAgICAgdXNlck5hbWU6IHNlc3Npb24udXNlck5hbWUsXG4gICAgICAgICAgICB9O1xuICAgICAgICAgICAgcmV0dXJuICQuZXh0ZW5kKHRydWUsIHNlc3Npb25EZWZhdWx0cywgYmFzZU9wdGlvbnMpO1xuICAgICAgICB9XG4gICAgfTtcbiAgICAkLmV4dGVuZCh0aGlzLCBwdWJsaWNBUEkpO1xufTtcblxubW9kdWxlLmV4cG9ydHMgPSBTZXNzaW9uTWFuYWdlcjsiLCIvKipcbiAgICBEZWNpZGVzIHR5cGUgb2Ygc3RvcmUgdG8gcHJvdmlkZVxuKi9cblxuJ3VzZSBzdHJpY3QnO1xuLy8gdmFyIGlzTm9kZSA9IGZhbHNlOyBGSVhNRTogQnJvd3NlcmlmeS9taW5pZnlpZnkgaGFzIGlzc3VlcyB3aXRoIHRoZSBuZXh0IGxpbmtcbi8vIHZhciBzdG9yZSA9IChpc05vZGUpID8gcmVxdWlyZSgnLi9zZXNzaW9uLXN0b3JlJykgOiByZXF1aXJlKCcuL2Nvb2tpZS1zdG9yZScpO1xudmFyIHN0b3JlID0gcmVxdWlyZSgnLi9jb29raWUtc3RvcmUnKTtcblxubW9kdWxlLmV4cG9ydHMgPSBzdG9yZTtcbiIsIid1c2Ugc3RyaWN0JztcblxudmFyIHF1dGlscyA9IHJlcXVpcmUoJy4uL3V0aWwvcXVlcnktdXRpbCcpO1xuXG5tb2R1bGUuZXhwb3J0cyA9IGZ1bmN0aW9uIChjb25maWcpIHtcblxuICAgIHZhciBkZWZhdWx0cyA9IHtcbiAgICAgICAgdXJsOiAnJyxcblxuICAgICAgICBjb250ZW50VHlwZTogJ2FwcGxpY2F0aW9uL2pzb24nLFxuICAgICAgICBoZWFkZXJzOiB7fSxcbiAgICAgICAgc3RhdHVzQ29kZToge1xuICAgICAgICAgICAgNDA0OiAkLm5vb3BcbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgICogT05MWSBmb3Igc3RyaW5ncyBpbiB0aGUgdXJsLiBBbGwgR0VUICYgREVMRVRFIHBhcmFtcyBhcmUgcnVuIHRocm91Z2ggdGhpc1xuICAgICAgICAgKiBAdHlwZSB7W3R5cGVdIH1cbiAgICAgICAgICovXG4gICAgICAgIHBhcmFtZXRlclBhcnNlcjogcXV0aWxzLnRvUXVlcnlGb3JtYXQsXG5cbiAgICAgICAgLy8gVG8gYWxsb3cgZXBpY2VudGVyLnRva2VuIGFuZCBvdGhlciBzZXNzaW9uIGNvb2tpZXMgdG8gYmUgcGFzc2VkXG4gICAgICAgIC8vIHdpdGggdGhlIHJlcXVlc3RzXG4gICAgICAgIHhockZpZWxkczoge1xuICAgICAgICAgICAgd2l0aENyZWRlbnRpYWxzOiB0cnVlXG4gICAgICAgIH1cbiAgICB9O1xuXG4gICAgdmFyIHRyYW5zcG9ydE9wdGlvbnMgPSAkLmV4dGVuZCh7fSwgZGVmYXVsdHMsIGNvbmZpZyk7XG5cbiAgICB2YXIgcmVzdWx0ID0gZnVuY3Rpb24gKGQpIHtcbiAgICAgICAgcmV0dXJuICgkLmlzRnVuY3Rpb24oZCkpID8gZCgpIDogZDtcbiAgICB9O1xuXG4gICAgdmFyIGNvbm5lY3QgPSBmdW5jdGlvbiAobWV0aG9kLCBwYXJhbXMsIGNvbm5lY3RPcHRpb25zKSB7XG4gICAgICAgIHBhcmFtcyA9IHJlc3VsdChwYXJhbXMpO1xuICAgICAgICBwYXJhbXMgPSAoJC5pc1BsYWluT2JqZWN0KHBhcmFtcykgfHwgJC5pc0FycmF5KHBhcmFtcykpID8gSlNPTi5zdHJpbmdpZnkocGFyYW1zKSA6IHBhcmFtcztcblxuICAgICAgICB2YXIgb3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LCB0cmFuc3BvcnRPcHRpb25zLCBjb25uZWN0T3B0aW9ucywge1xuICAgICAgICAgICAgdHlwZTogbWV0aG9kLFxuICAgICAgICAgICAgZGF0YTogcGFyYW1zXG4gICAgICAgIH0pO1xuICAgICAgICB2YXIgQUxMT1dFRF9UT19CRV9GVU5DVElPTlMgPSBbJ2RhdGEnLCAndXJsJ107XG4gICAgICAgICQuZWFjaChvcHRpb25zLCBmdW5jdGlvbiAoa2V5LCB2YWx1ZSkge1xuICAgICAgICAgICAgaWYgKCQuaXNGdW5jdGlvbih2YWx1ZSkgJiYgJC5pbkFycmF5KGtleSwgQUxMT1dFRF9UT19CRV9GVU5DVElPTlMpICE9PSAtMSkge1xuICAgICAgICAgICAgICAgIG9wdGlvbnNba2V5XSA9IHZhbHVlKCk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH0pO1xuXG4gICAgICAgIGlmIChvcHRpb25zLmxvZ0xldmVsICYmIG9wdGlvbnMubG9nTGV2ZWwgPT09ICdERUJVRycpIHtcbiAgICAgICAgICAgIGNvbnNvbGUubG9nKG9wdGlvbnMudXJsKTtcbiAgICAgICAgICAgIHZhciBvbGRTdWNjZXNzRm4gPSBvcHRpb25zLnN1Y2Nlc3MgfHwgJC5ub29wO1xuICAgICAgICAgICAgb3B0aW9ucy5zdWNjZXNzID0gZnVuY3Rpb24gKHJlc3BvbnNlLCBhamF4U3RhdHVzLCBhamF4UmVxKSB7XG4gICAgICAgICAgICAgICAgY29uc29sZS5sb2cocmVzcG9uc2UpO1xuICAgICAgICAgICAgICAgIG9sZFN1Y2Nlc3NGbi5hcHBseSh0aGlzLCBhcmd1bWVudHMpO1xuICAgICAgICAgICAgfTtcbiAgICAgICAgfVxuXG4gICAgICAgIHZhciBiZWZvcmVTZW5kID0gb3B0aW9ucy5iZWZvcmVTZW5kO1xuICAgICAgICBvcHRpb25zLmJlZm9yZVNlbmQgPSBmdW5jdGlvbiAoeGhyLCBzZXR0aW5ncykge1xuICAgICAgICAgICAgeGhyLnJlcXVlc3RVcmwgPSAoY29ubmVjdE9wdGlvbnMgfHwge30pLnVybDtcbiAgICAgICAgICAgIGlmIChiZWZvcmVTZW5kKSB7XG4gICAgICAgICAgICAgICAgYmVmb3JlU2VuZC5hcHBseSh0aGlzLCBhcmd1bWVudHMpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9O1xuXG4gICAgICAgIHJldHVybiAkLmFqYXgob3B0aW9ucyk7XG4gICAgfTtcblxuICAgIHZhciBwdWJsaWNBUEkgPSB7XG4gICAgICAgIGdldDogZnVuY3Rpb24gKHBhcmFtcywgYWpheE9wdGlvbnMpIHtcbiAgICAgICAgICAgIHZhciBvcHRpb25zID0gJC5leHRlbmQoe30sIHRyYW5zcG9ydE9wdGlvbnMsIGFqYXhPcHRpb25zKTtcbiAgICAgICAgICAgIHBhcmFtcyA9IG9wdGlvbnMucGFyYW1ldGVyUGFyc2VyKHJlc3VsdChwYXJhbXMpKTtcbiAgICAgICAgICAgIHJldHVybiBjb25uZWN0LmNhbGwodGhpcywgJ0dFVCcsIHBhcmFtcywgb3B0aW9ucyk7XG4gICAgICAgIH0sXG4gICAgICAgIHNwbGl0R2V0OiBmdW5jdGlvbiAoKSB7XG5cbiAgICAgICAgfSxcbiAgICAgICAgcG9zdDogZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgcmV0dXJuIGNvbm5lY3QuYXBwbHkodGhpcywgWydwb3N0J10uY29uY2F0KFtdLnNsaWNlLmNhbGwoYXJndW1lbnRzKSkpO1xuICAgICAgICB9LFxuICAgICAgICBwYXRjaDogZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgcmV0dXJuIGNvbm5lY3QuYXBwbHkodGhpcywgWydwYXRjaCddLmNvbmNhdChbXS5zbGljZS5jYWxsKGFyZ3VtZW50cykpKTtcbiAgICAgICAgfSxcbiAgICAgICAgcHV0OiBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICByZXR1cm4gY29ubmVjdC5hcHBseSh0aGlzLCBbJ3B1dCddLmNvbmNhdChbXS5zbGljZS5jYWxsKGFyZ3VtZW50cykpKTtcbiAgICAgICAgfSxcbiAgICAgICAgZGVsZXRlOiBmdW5jdGlvbiAocGFyYW1zLCBhamF4T3B0aW9ucykge1xuICAgICAgICAgICAgLy9ERUxFVEUgZG9lc24ndCBzdXBwb3J0IGJvZHkgcGFyYW1zLCBidXQgalF1ZXJ5IHRoaW5rcyBpdCBkb2VzLlxuICAgICAgICAgICAgdmFyIG9wdGlvbnMgPSAkLmV4dGVuZCh7fSwgdHJhbnNwb3J0T3B0aW9ucywgYWpheE9wdGlvbnMpO1xuICAgICAgICAgICAgcGFyYW1zID0gb3B0aW9ucy5wYXJhbWV0ZXJQYXJzZXIocmVzdWx0KHBhcmFtcykpO1xuICAgICAgICAgICAgaWYgKCQudHJpbShwYXJhbXMpKSB7XG4gICAgICAgICAgICAgICAgdmFyIGRlbGltaXRlciA9IChyZXN1bHQob3B0aW9ucy51cmwpLmluZGV4T2YoJz8nKSA9PT0gLTEpID8gJz8nIDogJyYnO1xuICAgICAgICAgICAgICAgIG9wdGlvbnMudXJsID0gcmVzdWx0KG9wdGlvbnMudXJsKSArIGRlbGltaXRlciArIHBhcmFtcztcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHJldHVybiBjb25uZWN0LmNhbGwodGhpcywgJ0RFTEVURScsIG51bGwsIG9wdGlvbnMpO1xuICAgICAgICB9LFxuICAgICAgICBoZWFkOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICByZXR1cm4gY29ubmVjdC5hcHBseSh0aGlzLCBbJ2hlYWQnXS5jb25jYXQoW10uc2xpY2UuY2FsbChhcmd1bWVudHMpKSk7XG4gICAgICAgIH0sXG4gICAgICAgIG9wdGlvbnM6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIHJldHVybiBjb25uZWN0LmFwcGx5KHRoaXMsIFsnb3B0aW9ucyddLmNvbmNhdChbXS5zbGljZS5jYWxsKGFyZ3VtZW50cykpKTtcbiAgICAgICAgfVxuICAgIH07XG5cbiAgICByZXR1cm4gJC5leHRlbmQodGhpcywgcHVibGljQVBJKTtcbn07XG4iLCIndXNlIHN0cmljdCc7XG5cbi8vIHZhciBpc05vZGUgPSBmYWxzZTsgRklYTUU6IEJyb3dzZXJpZnkvbWluaWZ5aWZ5IGhhcyBpc3N1ZXMgd2l0aCB0aGUgbmV4dCBsaW5rXG4vLyB2YXIgdHJhbnNwb3J0ID0gKGlzTm9kZSkgPyByZXF1aXJlKCcuL25vZGUtaHR0cC10cmFuc3BvcnQnKSA6IHJlcXVpcmUoJy4vYWpheC1odHRwLXRyYW5zcG9ydCcpO1xudmFyIHRyYW5zcG9ydCA9IHJlcXVpcmUoJy4vYWpheC1odHRwLXRyYW5zcG9ydCcpO1xubW9kdWxlLmV4cG9ydHMgPSB0cmFuc3BvcnQ7XG4iLCIvKipcbi8qIEluaGVyaXQgZnJvbSBhIGNsYXNzICh1c2luZyBwcm90b3R5cGUgYm9ycm93aW5nKVxuKi9cbid1c2Ugc3RyaWN0JztcblxuZnVuY3Rpb24gaW5oZXJpdChDLCBQKSB7XG4gICAgdmFyIEYgPSBmdW5jdGlvbiAoKSB7fTtcbiAgICBGLnByb3RvdHlwZSA9IFAucHJvdG90eXBlO1xuICAgIEMucHJvdG90eXBlID0gbmV3IEYoKTtcbiAgICBDLl9fc3VwZXIgPSBQLnByb3RvdHlwZTtcbiAgICBDLnByb3RvdHlwZS5jb25zdHJ1Y3RvciA9IEM7XG59XG5cbi8qKlxuKiBTaGFsbG93IGNvcHkgb2YgYW4gb2JqZWN0XG4qIEBwYXJhbSB7T2JqZWN0fSBkZXN0IG9iamVjdCB0byBleHRlbmRcbiogQHJldHVybiB7T2JqZWN0fSBleHRlbmRlZCBvYmplY3RcbiovXG52YXIgZXh0ZW5kID0gZnVuY3Rpb24gKGRlc3QgLyosIHZhcl9hcmdzKi8pIHtcbiAgICB2YXIgb2JqID0gQXJyYXkucHJvdG90eXBlLnNsaWNlLmNhbGwoYXJndW1lbnRzLCAxKTtcbiAgICB2YXIgY3VycmVudDtcbiAgICBmb3IgKHZhciBqID0gMDsgaiA8IG9iai5sZW5ndGg7IGorKykge1xuICAgICAgICBpZiAoIShjdXJyZW50ID0gb2JqW2pdKSkgeyAvL2VzbGludC1kaXNhYmxlLWxpbmVcbiAgICAgICAgICAgIGNvbnRpbnVlO1xuICAgICAgICB9XG5cbiAgICAgICAgLy8gZG8gbm90IHdyYXAgaW5uZXIgaW4gZGVzdC5oYXNPd25Qcm9wZXJ0eSBvciBiYWQgdGhpbmdzIHdpbGwgaGFwcGVuXG4gICAgICAgIGZvciAodmFyIGtleSBpbiBjdXJyZW50KSB7IC8vZXNsaW50LWRpc2FibGUtbGluZVxuICAgICAgICAgICAgZGVzdFtrZXldID0gY3VycmVudFtrZXldO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgcmV0dXJuIGRlc3Q7XG59O1xuXG5tb2R1bGUuZXhwb3J0cyA9IGZ1bmN0aW9uIChiYXNlLCBwcm9wcywgc3RhdGljUHJvcHMpIHtcbiAgICB2YXIgcGFyZW50ID0gYmFzZTtcbiAgICB2YXIgY2hpbGQ7XG5cbiAgICBjaGlsZCA9IHByb3BzICYmIHByb3BzLmhhc093blByb3BlcnR5KCdjb25zdHJ1Y3RvcicpID8gcHJvcHMuY29uc3RydWN0b3IgOiBmdW5jdGlvbiAoKSB7IHJldHVybiBwYXJlbnQuYXBwbHkodGhpcywgYXJndW1lbnRzKTsgfTtcblxuICAgIC8vIGFkZCBzdGF0aWMgcHJvcGVydGllcyB0byB0aGUgY2hpbGQgY29uc3RydWN0b3IgZnVuY3Rpb25cbiAgICBleHRlbmQoY2hpbGQsIHBhcmVudCwgc3RhdGljUHJvcHMpO1xuXG4gICAgLy8gYXNzb2NpYXRlIHByb3RvdHlwZSBjaGFpblxuICAgIGluaGVyaXQoY2hpbGQsIHBhcmVudCk7XG5cbiAgICAvLyBhZGQgaW5zdGFuY2UgcHJvcGVydGllc1xuICAgIGlmIChwcm9wcykge1xuICAgICAgICBleHRlbmQoY2hpbGQucHJvdG90eXBlLCBwcm9wcyk7XG4gICAgfVxuXG4gICAgLy8gZG9uZVxuICAgIHJldHVybiBjaGlsZDtcbn07XG4iLCIndXNlIHN0cmljdCc7XG5cbm1vZHVsZS5leHBvcnRzID0ge1xuICAgIF9waWNrOiBmdW5jdGlvbiAob2JqLCBwcm9wcykge1xuICAgICAgICB2YXIgcmVzID0ge307XG4gICAgICAgIGZvciAodmFyIHAgaW4gb2JqKSB7XG4gICAgICAgICAgICBpZiAocHJvcHMuaW5kZXhPZihwKSAhPT0gLTEpIHtcbiAgICAgICAgICAgICAgICByZXNbcF0gPSBvYmpbcF07XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICByZXR1cm4gcmVzO1xuICAgIH0sXG4gICAgaXNFbXB0eTogZnVuY3Rpb24gaXNFbXB0eSh2YWx1ZSkge1xuICAgICAgICByZXR1cm4gKCF2YWx1ZSB8fCAoJC5pc1BsYWluT2JqZWN0KHZhbHVlKSAmJiBPYmplY3Qua2V5cyh2YWx1ZSkubGVuZ3RoID09PSAwKSk7XG4gICAgfVxufTtcbiIsIid1c2Ugc3RyaWN0JztcblxudmFyIENvbmZpZ1NlcnZpY2UgPSByZXF1aXJlKCcuLi9zZXJ2aWNlL2NvbmZpZ3VyYXRpb24tc2VydmljZScpO1xuXG52YXIgdXJsQ29uZmlnID0gbmV3IENvbmZpZ1NlcnZpY2UoKS5nZXQoJ3NlcnZlcicpO1xudmFyIGN1c3RvbURlZmF1bHRzID0ge307XG52YXIgbGliRGVmYXVsdHMgPSB7XG4gICAgLyoqXG4gICAgICogVGhlIGFjY291bnQgaWQuIEluIHRoZSBFcGljZW50ZXIgVUksIHRoaXMgaXMgdGhlICoqVGVhbSBJRCoqIChmb3IgdGVhbSBwcm9qZWN0cykgb3IgKipVc2VyIElEKiogKGZvciBwZXJzb25hbCBwcm9qZWN0cykuIERlZmF1bHRzIHRvIGVtcHR5IHN0cmluZy4gSWYgbGVmdCB1bmRlZmluZWQsIHRha2VuIGZyb20gdGhlIFVSTC5cbiAgICAgKiBAdHlwZSB7U3RyaW5nfVxuICAgICAqL1xuICAgIGFjY291bnQ6IHVybENvbmZpZy5hY2NvdW50UGF0aCB8fCB1bmRlZmluZWQsXG4gICAgLyoqXG4gICAgICogVGhlIGFjY291bnQgaWQuIEluIHRoZSBFcGljZW50ZXIgVUksIHRoaXMgaXMgdGhlICoqVGVhbSBJRCoqIChmb3IgdGVhbSBwcm9qZWN0cykgb3IgKipVc2VyIElEKiogKGZvciBwZXJzb25hbCBwcm9qZWN0cykuIERlZmF1bHRzIHRvIGVtcHR5IHN0cmluZy4gSWYgbGVmdCB1bmRlZmluZWQsIHRha2VuIGZyb20gdGhlIFVSTC5cbiAgICAgKiBAdHlwZSB7U3RyaW5nfVxuICAgICAqL1xuICAgIHByb2plY3Q6IHVybENvbmZpZy5wcm9qZWN0UGF0aCB8fCB1bmRlZmluZWQsXG4gICAgaXNMb2NhbDogdXJsQ29uZmlnLmlzTG9jYWxob3N0KCksXG4gICAgaXNDdXN0b21Eb21haW46IHVybENvbmZpZy5pc0N1c3RvbURvbWFpbixcbiAgICBzdG9yZToge31cbn07XG5cbnZhciBvcHRpb25VdGlscyA9IHtcbiAgICAvKipcbiAgICAgKiBHZXRzIHRoZSBmaW5hbCBvcHRpb25zIGJ5IG92ZXJyaWRpbmcgdGhlIGdsb2JhbCBvcHRpb25zIHNldCB3aXRoXG4gICAgICogb3B0aW9uVXRpbHMjc2V0RGVmYXVsdHMoKSBhbmQgdGhlIGxpYiBkZWZhdWx0cy5cbiAgICAgKiBAcGFyYW0ge29iamVjdH0gb3B0aW9ucyBUaGUgZmluYWwgb3B0aW9ucyBvYmplY3QuXG4gICAgICogQHJldHVybiB7b2JqZWN0fSBFeHRlbmRlZCBvYmplY3RcbiAgICAgKi9cbiAgICBnZXRPcHRpb25zOiBmdW5jdGlvbiAob3B0aW9ucykge1xuICAgICAgICByZXR1cm4gJC5leHRlbmQodHJ1ZSwge30sIGxpYkRlZmF1bHRzLCBjdXN0b21EZWZhdWx0cywgb3B0aW9ucyk7XG4gICAgfSxcbiAgICAvKipcbiAgICAgKiBTZXRzIHRoZSBnbG9iYWwgZGVmYXVsdHMgZm9yIHRoZSBvcHRpb25VdGlscyNnZXRPcHRpb25zKCkgbWV0aG9kLlxuICAgICAqIEBwYXJhbSB7b2JqZWN0fSBkZWZhdWx0cyBUaGUgZGVmYXVsdHMgb2JqZWN0LlxuICAgICAqL1xuICAgIHNldERlZmF1bHRzOiBmdW5jdGlvbiAoZGVmYXVsdHMpIHtcbiAgICAgICAgY3VzdG9tRGVmYXVsdHMgPSBkZWZhdWx0cztcbiAgICB9XG59O1xubW9kdWxlLmV4cG9ydHMgPSBvcHRpb25VdGlscztcbiIsIi8qKlxuICogVXRpbGl0aWVzIGZvciB3b3JraW5nIHdpdGggcXVlcnkgc3RyaW5nc1xuKi9cbid1c2Ugc3RyaWN0JztcblxubW9kdWxlLmV4cG9ydHMgPSAoZnVuY3Rpb24gKCkge1xuXG4gICAgcmV0dXJuIHtcbiAgICAgICAgLyoqXG4gICAgICAgICAqIENvbnZlcnRzIHRvIG1hdHJpeCBmb3JtYXRcbiAgICAgICAgICogQHBhcmFtICB7T2JqZWN0fSBxcyBPYmplY3QgdG8gY29udmVydCB0byBxdWVyeSBzdHJpbmdcbiAgICAgICAgICogQHJldHVybiB7IHN0cmluZ30gICAgTWF0cml4LWZvcm1hdCBxdWVyeSBwYXJhbWV0ZXJzXG4gICAgICAgICAqL1xuICAgICAgICB0b01hdHJpeEZvcm1hdDogZnVuY3Rpb24gKHFzKSB7XG4gICAgICAgICAgICBpZiAocXMgPT09IG51bGwgfHwgcXMgPT09IHVuZGVmaW5lZCB8fCBxcyA9PT0gJycpIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gJzsnO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgaWYgKHR5cGVvZiBxcyA9PT0gJ3N0cmluZycgfHwgcXMgaW5zdGFuY2VvZiBTdHJpbmcpIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gcXM7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIHZhciByZXR1cm5BcnJheSA9IFtdO1xuICAgICAgICAgICAgdmFyIE9QRVJBVE9SUyA9IFsnPCcsICc+JywgJyEnXTtcbiAgICAgICAgICAgICQuZWFjaChxcywgZnVuY3Rpb24gKGtleSwgdmFsdWUpIHtcbiAgICAgICAgICAgICAgICBpZiAodHlwZW9mIHZhbHVlICE9PSAnc3RyaW5nJyB8fCAkLmluQXJyYXkoJC50cmltKHZhbHVlKS5jaGFyQXQoMCksIE9QRVJBVE9SUykgPT09IC0xKSB7XG4gICAgICAgICAgICAgICAgICAgIHZhbHVlID0gJz0nICsgdmFsdWU7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIHJldHVybkFycmF5LnB1c2goa2V5ICsgdmFsdWUpO1xuICAgICAgICAgICAgfSk7XG5cbiAgICAgICAgICAgIHZhciBtdHJ4ID0gJzsnICsgcmV0dXJuQXJyYXkuam9pbignOycpO1xuICAgICAgICAgICAgcmV0dXJuIG10cng7XG4gICAgICAgIH0sXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIENvbnZlcnRzIHN0cmluZ3MvYXJyYXlzL29iamVjdHMgdG8gdHlwZSAnYT1iJmI9YydcbiAgICAgICAgICogQHBhcmFtICB7IHN0cmluZ3xBcnJheXxPYmplY3R9IHFzXG4gICAgICAgICAqIEByZXR1cm4geyBzdHJpbmd9XG4gICAgICAgICAqL1xuICAgICAgICB0b1F1ZXJ5Rm9ybWF0OiBmdW5jdGlvbiAocXMpIHtcbiAgICAgICAgICAgIGlmIChxcyA9PT0gbnVsbCB8fCBxcyA9PT0gdW5kZWZpbmVkKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuICcnO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgaWYgKHR5cGVvZiBxcyA9PT0gJ3N0cmluZycgfHwgcXMgaW5zdGFuY2VvZiBTdHJpbmcpIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gcXM7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIHZhciByZXR1cm5BcnJheSA9IFtdO1xuICAgICAgICAgICAgJC5lYWNoKHFzLCBmdW5jdGlvbiAoa2V5LCB2YWx1ZSkge1xuICAgICAgICAgICAgICAgIGlmICgkLmlzQXJyYXkodmFsdWUpKSB7XG4gICAgICAgICAgICAgICAgICAgIHZhbHVlID0gdmFsdWUuam9pbignLCcpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICBpZiAoJC5pc1BsYWluT2JqZWN0KHZhbHVlKSkge1xuICAgICAgICAgICAgICAgICAgICAvL01vc3RseSBmb3IgZGF0YSBhcGlcbiAgICAgICAgICAgICAgICAgICAgdmFsdWUgPSBKU09OLnN0cmluZ2lmeSh2YWx1ZSk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIHJldHVybkFycmF5LnB1c2goa2V5ICsgJz0nICsgdmFsdWUpO1xuICAgICAgICAgICAgfSk7XG5cbiAgICAgICAgICAgIHZhciByZXN1bHQgPSByZXR1cm5BcnJheS5qb2luKCcmJyk7XG4gICAgICAgICAgICByZXR1cm4gcmVzdWx0O1xuICAgICAgICB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBDb252ZXJ0cyBzdHJpbmdzIG9mIHR5cGUgJ2E9YiZiPWMnIHRvIHsgYTpiLCBiOmN9XG4gICAgICAgICAqIEBwYXJhbSAgeyBzdHJpbmd9IHFzXG4gICAgICAgICAqIEByZXR1cm4ge29iamVjdH1cbiAgICAgICAgICovXG4gICAgICAgIHFzVG9PYmplY3Q6IGZ1bmN0aW9uIChxcykge1xuICAgICAgICAgICAgaWYgKHFzID09PSBudWxsIHx8IHFzID09PSB1bmRlZmluZWQgfHwgcXMgPT09ICcnKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIHt9O1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICB2YXIgcXNBcnJheSA9IHFzLnNwbGl0KCcmJyk7XG4gICAgICAgICAgICB2YXIgcmV0dXJuT2JqID0ge307XG4gICAgICAgICAgICAkLmVhY2gocXNBcnJheSwgZnVuY3Rpb24gKGluZGV4LCB2YWx1ZSkge1xuICAgICAgICAgICAgICAgIHZhciBxS2V5ID0gdmFsdWUuc3BsaXQoJz0nKVswXTtcbiAgICAgICAgICAgICAgICB2YXIgcVZhbCA9IHZhbHVlLnNwbGl0KCc9JylbMV07XG5cbiAgICAgICAgICAgICAgICBpZiAocVZhbC5pbmRleE9mKCcsJykgIT09IC0xKSB7XG4gICAgICAgICAgICAgICAgICAgIHFWYWwgPSBxVmFsLnNwbGl0KCcsJyk7XG4gICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgcmV0dXJuT2JqW3FLZXldID0gcVZhbDtcbiAgICAgICAgICAgIH0pO1xuXG4gICAgICAgICAgICByZXR1cm4gcmV0dXJuT2JqO1xuICAgICAgICB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBOb3JtYWxpemVzIGFuZCBtZXJnZXMgc3RyaW5ncyBvZiB0eXBlICdhPWInLCB7IGI6Y30gdG8geyBhOmIsIGI6Y31cbiAgICAgICAgICogQHBhcmFtICB7IHN0cmluZ3xBcnJheXxPYmplY3R9IHFzMVxuICAgICAgICAgKiBAcGFyYW0gIHsgc3RyaW5nfEFycmF5fE9iamVjdH0gcXMyXG4gICAgICAgICAqIEByZXR1cm4ge09iamVjdH1cbiAgICAgICAgICovXG4gICAgICAgIG1lcmdlUVM6IGZ1bmN0aW9uIChxczEsIHFzMikge1xuICAgICAgICAgICAgdmFyIG9iajEgPSB0aGlzLnFzVG9PYmplY3QodGhpcy50b1F1ZXJ5Rm9ybWF0KHFzMSkpO1xuICAgICAgICAgICAgdmFyIG9iajIgPSB0aGlzLnFzVG9PYmplY3QodGhpcy50b1F1ZXJ5Rm9ybWF0KHFzMikpO1xuICAgICAgICAgICAgcmV0dXJuICQuZXh0ZW5kKHRydWUsIHt9LCBvYmoxLCBvYmoyKTtcbiAgICAgICAgfSxcblxuICAgICAgICBhZGRUcmFpbGluZ1NsYXNoOiBmdW5jdGlvbiAodXJsKSB7XG4gICAgICAgICAgICBpZiAoIXVybCkge1xuICAgICAgICAgICAgICAgIHJldHVybiAnJztcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHJldHVybiAodXJsLmNoYXJBdCh1cmwubGVuZ3RoIC0gMSkgPT09ICcvJykgPyB1cmwgOiAodXJsICsgJy8nKTtcbiAgICAgICAgfVxuICAgIH07XG59KCkpO1xuXG5cbiIsIi8qKlxuICogVXRpbGl0aWVzIGZvciB3b3JraW5nIHdpdGggdGhlIHJ1biBzZXJ2aWNlXG4qL1xuJ3VzZSBzdHJpY3QnO1xudmFyIHF1dGlsID0gcmVxdWlyZSgnLi9xdWVyeS11dGlsJyk7XG52YXIgTUFYX1VSTF9MRU5HVEggPSAyMDQ4O1xuXG5tb2R1bGUuZXhwb3J0cyA9IChmdW5jdGlvbiAoKSB7XG4gICAgcmV0dXJuIHtcbiAgICAgICAgLyoqXG4gICAgICAgICAqIG5vcm1hbGl6ZXMgZGlmZmVyZW50IHR5cGVzIG9mIG9wZXJhdGlvbiBpbnB1dHNcbiAgICAgICAgICogQHBhcmFtICB7T2JqZWN0fEFycmF5fFN0cmluZ30gb3BlcmF0aW9ucyBvcGVyYXRpb25zIHRvIHBlcmZvcm1cbiAgICAgICAgICogQHBhcmFtICB7QXJyYXl9IGFyZ3MgYXJndW1lbnRzIGZvciBvcGVyYXRpb25cbiAgICAgICAgICogQHJldHVybiB7U3RyaW5nfSBvcGVyYXRpb25zIG9mIHRoZSBmb3JtIGB7IG9wczogW10sIGFyZ3M6IFtdIH1gXG4gICAgICAgICAqL1xuICAgICAgICBub3JtYWxpemVPcGVyYXRpb25zOiBmdW5jdGlvbiAob3BlcmF0aW9ucywgYXJncykge1xuICAgICAgICAgICAgaWYgKCFhcmdzKSB7XG4gICAgICAgICAgICAgICAgYXJncyA9IFtdO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgdmFyIHJldHVybkxpc3QgPSB7XG4gICAgICAgICAgICAgICAgb3BzOiBbXSxcbiAgICAgICAgICAgICAgICBhcmdzOiBbXVxuICAgICAgICAgICAgfTtcblxuICAgICAgICAgICAgdmFyIF9jb25jYXQgPSBmdW5jdGlvbiAoYXJyKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIChhcnIgIT09IG51bGwgJiYgYXJyICE9PSB1bmRlZmluZWQpID8gW10uY29uY2F0KGFycikgOiBbXTtcbiAgICAgICAgICAgIH07XG5cbiAgICAgICAgICAgIC8veyBhZGQ6IFsxLDJdLCBzdWJ0cmFjdDogWzIsNF0gfVxuICAgICAgICAgICAgdmFyIF9ub3JtYWxpemVQbGFpbk9iamVjdHMgPSBmdW5jdGlvbiAob3BlcmF0aW9ucywgcmV0dXJuTGlzdCkge1xuICAgICAgICAgICAgICAgIGlmICghcmV0dXJuTGlzdCkge1xuICAgICAgICAgICAgICAgICAgICByZXR1cm5MaXN0ID0geyBvcHM6IFtdLCBhcmdzOiBbXSB9O1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAkLmVhY2gob3BlcmF0aW9ucywgZnVuY3Rpb24gKG9wbiwgYXJnKSB7XG4gICAgICAgICAgICAgICAgICAgIHJldHVybkxpc3Qub3BzLnB1c2gob3BuKTtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuTGlzdC5hcmdzLnB1c2goX2NvbmNhdChhcmcpKTtcbiAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgICByZXR1cm4gcmV0dXJuTGlzdDtcbiAgICAgICAgICAgIH07XG4gICAgICAgICAgICAvL3sgbmFtZTogJ2FkZCcsIHBhcmFtczogWzFdIH1cbiAgICAgICAgICAgIHZhciBfbm9ybWFsaXplU3RydWN0dXJlZE9iamVjdHMgPSBmdW5jdGlvbiAob3BlcmF0aW9uLCByZXR1cm5MaXN0KSB7XG4gICAgICAgICAgICAgICAgaWYgKCFyZXR1cm5MaXN0KSB7XG4gICAgICAgICAgICAgICAgICAgIHJldHVybkxpc3QgPSB7IG9wczogW10sIGFyZ3M6IFtdIH07XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIHJldHVybkxpc3Qub3BzLnB1c2gob3BlcmF0aW9uLm5hbWUpO1xuICAgICAgICAgICAgICAgIHJldHVybkxpc3QuYXJncy5wdXNoKF9jb25jYXQob3BlcmF0aW9uLnBhcmFtcykpO1xuICAgICAgICAgICAgICAgIHJldHVybiByZXR1cm5MaXN0O1xuICAgICAgICAgICAgfTtcblxuICAgICAgICAgICAgdmFyIF9ub3JtYWxpemVPYmplY3QgPSBmdW5jdGlvbiAob3BlcmF0aW9uLCByZXR1cm5MaXN0KSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuICgob3BlcmF0aW9uLm5hbWUpID8gX25vcm1hbGl6ZVN0cnVjdHVyZWRPYmplY3RzIDogX25vcm1hbGl6ZVBsYWluT2JqZWN0cykob3BlcmF0aW9uLCByZXR1cm5MaXN0KTtcbiAgICAgICAgICAgIH07XG5cbiAgICAgICAgICAgIHZhciBfbm9ybWFsaXplTGl0ZXJhbHMgPSBmdW5jdGlvbiAob3BlcmF0aW9uLCBhcmdzLCByZXR1cm5MaXN0KSB7XG4gICAgICAgICAgICAgICAgaWYgKCFyZXR1cm5MaXN0KSB7XG4gICAgICAgICAgICAgICAgICAgIHJldHVybkxpc3QgPSB7IG9wczogW10sIGFyZ3M6IFtdIH07XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIHJldHVybkxpc3Qub3BzLnB1c2gob3BlcmF0aW9uKTtcbiAgICAgICAgICAgICAgICByZXR1cm5MaXN0LmFyZ3MucHVzaChfY29uY2F0KGFyZ3MpKTtcbiAgICAgICAgICAgICAgICByZXR1cm4gcmV0dXJuTGlzdDtcbiAgICAgICAgICAgIH07XG5cblxuICAgICAgICAgICAgdmFyIF9ub3JtYWxpemVBcnJheXMgPSBmdW5jdGlvbiAob3BlcmF0aW9ucywgYXJnLCByZXR1cm5MaXN0KSB7XG4gICAgICAgICAgICAgICAgaWYgKCFyZXR1cm5MaXN0KSB7XG4gICAgICAgICAgICAgICAgICAgIHJldHVybkxpc3QgPSB7IG9wczogW10sIGFyZ3M6IFtdIH07XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICQuZWFjaChvcGVyYXRpb25zLCBmdW5jdGlvbiAoaW5kZXgsIG9wbikge1xuICAgICAgICAgICAgICAgICAgICBpZiAoJC5pc1BsYWluT2JqZWN0KG9wbikpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIF9ub3JtYWxpemVPYmplY3Qob3BuLCByZXR1cm5MaXN0KTtcbiAgICAgICAgICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIF9ub3JtYWxpemVMaXRlcmFscyhvcG4sIGFyZ3NbaW5kZXhdLCByZXR1cm5MaXN0KTtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICAgIHJldHVybiByZXR1cm5MaXN0O1xuICAgICAgICAgICAgfTtcblxuICAgICAgICAgICAgaWYgKCQuaXNQbGFpbk9iamVjdChvcGVyYXRpb25zKSkge1xuICAgICAgICAgICAgICAgIF9ub3JtYWxpemVPYmplY3Qob3BlcmF0aW9ucywgcmV0dXJuTGlzdCk7XG4gICAgICAgICAgICB9IGVsc2UgaWYgKCQuaXNBcnJheShvcGVyYXRpb25zKSkge1xuICAgICAgICAgICAgICAgIF9ub3JtYWxpemVBcnJheXMob3BlcmF0aW9ucywgYXJncywgcmV0dXJuTGlzdCk7XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgIF9ub3JtYWxpemVMaXRlcmFscyhvcGVyYXRpb25zLCBhcmdzLCByZXR1cm5MaXN0KTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgcmV0dXJuIHJldHVybkxpc3Q7XG4gICAgICAgIH0sXG5cbiAgICAgICAgc3BsaXRHZXRGYWN0b3J5OiBmdW5jdGlvbiAoaHR0cE9wdGlvbnMpIHtcbiAgICAgICAgICAgIHJldHVybiBmdW5jdGlvbiAocGFyYW1zLCBvcHRpb25zKSB7XG4gICAgICAgICAgICAgICAgdmFyIGh0dHAgPSB0aGlzOyAvL2VzbGludC1kaXNhYmxlLWxpbmVcbiAgICAgICAgICAgICAgICB2YXIgZ2V0VmFsdWUgPSBmdW5jdGlvbiAobmFtZSkge1xuICAgICAgICAgICAgICAgICAgICB2YXIgdmFsdWUgPSBvcHRpb25zW25hbWVdIHx8IGh0dHBPcHRpb25zW25hbWVdO1xuICAgICAgICAgICAgICAgICAgICBpZiAodHlwZW9mIHZhbHVlID09PSAnZnVuY3Rpb24nKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICB2YWx1ZSA9IHZhbHVlKCk7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIHZhbHVlO1xuICAgICAgICAgICAgICAgIH07XG4gICAgICAgICAgICAgICAgdmFyIGdldEZpbmFsVXJsID0gZnVuY3Rpb24gKHBhcmFtcykge1xuICAgICAgICAgICAgICAgICAgICB2YXIgdXJsID0gZ2V0VmFsdWUoJ3VybCcsIG9wdGlvbnMpO1xuICAgICAgICAgICAgICAgICAgICB2YXIgZGF0YSA9IHBhcmFtcztcbiAgICAgICAgICAgICAgICAgICAgLy8gVGhlcmUgaXMgZWFzeSAob3Iga25vd24pIHdheSB0byBnZXQgdGhlIGZpbmFsIFVSTCBqcXVlcnkgaXMgZ29pbmcgdG8gc2VuZCBzb1xuICAgICAgICAgICAgICAgICAgICAvLyB3ZSdyZSByZXBsaWNhdGluZyBpdC4gVGhlIHByb2Nlc3MgbWlnaHQgY2hhbmdlIGF0IHNvbWUgcG9pbnQgYnV0IGl0IHByb2JhYmx5IHdpbGwgbm90LlxuICAgICAgICAgICAgICAgICAgICAvLyAxLiBSZW1vdmUgaGFzaFxuICAgICAgICAgICAgICAgICAgICB1cmwgPSB1cmwucmVwbGFjZSgvIy4qJC8sICcnKTtcbiAgICAgICAgICAgICAgICAgICAgLy8gMS4gQXBwZW5kIHF1ZXJ5IHN0cmluZ1xuICAgICAgICAgICAgICAgICAgICB2YXIgcXVlcnlQYXJhbXMgPSBxdXRpbC50b1F1ZXJ5Rm9ybWF0KGRhdGEpO1xuICAgICAgICAgICAgICAgICAgICB2YXIgcXVlc3Rpb25JZHggPSB1cmwuaW5kZXhPZignPycpO1xuICAgICAgICAgICAgICAgICAgICBpZiAocXVlcnlQYXJhbXMgJiYgcXVlc3Rpb25JZHggPiAtMSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIHVybCArICcmJyArIHF1ZXJ5UGFyYW1zO1xuICAgICAgICAgICAgICAgICAgICB9IGVsc2UgaWYgKHF1ZXJ5UGFyYW1zKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICByZXR1cm4gdXJsICsgJz8nICsgcXVlcnlQYXJhbXM7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIHVybDtcbiAgICAgICAgICAgICAgICB9O1xuICAgICAgICAgICAgICAgIHZhciB1cmwgPSBnZXRGaW5hbFVybChwYXJhbXMpO1xuICAgICAgICAgICAgICAgIC8vIFdlIG11c3Qgc3BsaXQgdGhlIEdFVCBpbiBtdWx0aXBsZSBzaG9ydCBVUkwnc1xuICAgICAgICAgICAgICAgIC8vIFRoZSBvbmx5IHByb3BlcnR5IGFsbG93ZWQgdG8gYmUgc3BsaXQgaXMgXCJpbmNsdWRlXCJcbiAgICAgICAgICAgICAgICBpZiAocGFyYW1zICYmIHBhcmFtcy5pbmNsdWRlICYmIGVuY29kZVVSSSh1cmwpLmxlbmd0aCA+IE1BWF9VUkxfTEVOR1RIKSB7XG4gICAgICAgICAgICAgICAgICAgIHZhciBkdGQgPSAkLkRlZmVycmVkKCk7XG4gICAgICAgICAgICAgICAgICAgIHZhciBwYXJhbXNDb3B5ID0gJC5leHRlbmQodHJ1ZSwge30sIHBhcmFtcyk7XG4gICAgICAgICAgICAgICAgICAgIGRlbGV0ZSBwYXJhbXNDb3B5LmluY2x1ZGU7XG4gICAgICAgICAgICAgICAgICAgIHZhciB1cmxOb0luY2x1ZGVzID0gZ2V0RmluYWxVcmwocGFyYW1zQ29weSk7XG4gICAgICAgICAgICAgICAgICAgIHZhciBkaWZmID0gTUFYX1VSTF9MRU5HVEggLSB1cmxOb0luY2x1ZGVzLmxlbmd0aDtcbiAgICAgICAgICAgICAgICAgICAgdmFyIG9sZFN1Y2Nlc3MgPSBvcHRpb25zLnN1Y2Nlc3MgfHwgaHR0cE9wdGlvbnMuc3VjY2VzcyB8fCAkLm5vb3A7XG4gICAgICAgICAgICAgICAgICAgIHZhciBvbGRFcnJvciA9IG9wdGlvbnMuZXJyb3IgfHwgaHR0cE9wdGlvbnMuZXJyb3IgfHwgJC5ub29wO1xuICAgICAgICAgICAgICAgICAgICAvLyByZW1vdmUgdGhlIG9yaWdpbmFsIHN1Y2Nlc3MgYW5kIGVycm9yIGNhbGxiYWNrc1xuICAgICAgICAgICAgICAgICAgICBvcHRpb25zLnN1Y2Nlc3MgPSAkLm5vb3A7XG4gICAgICAgICAgICAgICAgICAgIG9wdGlvbnMuZXJyb3IgPSAkLm5vb3A7XG5cbiAgICAgICAgICAgICAgICAgICAgdmFyIGluY2x1ZGUgPSBwYXJhbXMuaW5jbHVkZTtcbiAgICAgICAgICAgICAgICAgICAgdmFyIGN1cnJJbmNsdWRlcyA9IFtdO1xuICAgICAgICAgICAgICAgICAgICB2YXIgaW5jbHVkZU9wdHMgPSBbY3VyckluY2x1ZGVzXTtcbiAgICAgICAgICAgICAgICAgICAgdmFyIGN1cnJMZW5ndGggPSBlbmNvZGVVUklDb21wb25lbnQoJz9pbmNsdWRlPScpLmxlbmd0aDtcbiAgICAgICAgICAgICAgICAgICAgdmFyIHZhcmlhYmxlID0gaW5jbHVkZS5wb3AoKTtcbiAgICAgICAgICAgICAgICAgICAgd2hpbGUgKHZhcmlhYmxlKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICB2YXIgdmFyTGVuZ2h0ID0gZW5jb2RlVVJJQ29tcG9uZW50KHZhcmlhYmxlKS5sZW5ndGg7XG4gICAgICAgICAgICAgICAgICAgICAgICAvLyBVc2UgYSBncmVlZHkgYXBwcm9hY2ggZm9yIG5vdywgY2FuIGJlIG9wdGltaXplZCB0byBiZSBzb2x2ZWQgaW4gYSBtb3JlXG4gICAgICAgICAgICAgICAgICAgICAgICAvLyBlZmZpY2llbnQgd2F5XG4gICAgICAgICAgICAgICAgICAgICAgICAvLyArIDEgaXMgdGhlIGNvbW1hXG4gICAgICAgICAgICAgICAgICAgICAgICBpZiAoY3Vyckxlbmd0aCArIHZhckxlbmdodCArIDEgPCBkaWZmKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgY3VyckluY2x1ZGVzLnB1c2godmFyaWFibGUpO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGN1cnJMZW5ndGggKz0gdmFyTGVuZ2h0ICsgMTtcbiAgICAgICAgICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgY3VyckluY2x1ZGVzID0gW3ZhcmlhYmxlXTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBpbmNsdWRlT3B0cy5wdXNoKGN1cnJJbmNsdWRlcyk7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgY3Vyckxlbmd0aCA9ICc/aW5jbHVkZT0nLmxlbmd0aCArIHZhckxlbmdodDtcbiAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgICAgIHZhcmlhYmxlID0gaW5jbHVkZS5wb3AoKTtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICB2YXIgcmVxcyA9ICQubWFwKGluY2x1ZGVPcHRzLCBmdW5jdGlvbiAoaW5jbHVkZSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgdmFyIHJlcVBhcmFtcyA9ICQuZXh0ZW5kKHt9LCBwYXJhbXMsIHsgaW5jbHVkZTogaW5jbHVkZSB9KTtcbiAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybiBodHRwLmdldChyZXFQYXJhbXMsIG9wdGlvbnMpO1xuICAgICAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgICAgICAgJC53aGVuLmFwcGx5KCQsIHJlcXMpLnRoZW4oZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgICAgICAgICAgICAgLy8gRWFjaCBhcmd1bWVudCBhcmUgYXJyYXlzIG9mIHRoZSBhcmd1bWVudHMgb2YgZWFjaCBkb25lIHJlcXVlc3RcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIFNvIHRoZSBmaXJzdCBhcmd1bWVudCBvZiB0aGUgZmlyc3QgYXJyYXkgb2YgYXJndW1lbnRzIGlzIHRoZSBkYXRhXG4gICAgICAgICAgICAgICAgICAgICAgICB2YXIgaXNWYWxpZCA9IGFyZ3VtZW50c1swXSAmJiBhcmd1bWVudHNbMF1bMF07XG4gICAgICAgICAgICAgICAgICAgICAgICBpZiAoIWlzVmFsaWQpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBTaG91bGQgbmV2ZXIgaGFwcGVuLi4uXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgb2xkRXJyb3IoKTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICByZXR1cm4gZHRkLnJlamVjdCgpO1xuICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICAgICAgdmFyIGZpcnN0UmVzcG9uc2UgPSBhcmd1bWVudHNbMF1bMF07XG4gICAgICAgICAgICAgICAgICAgICAgICB2YXIgaXNPYmplY3QgPSAkLmlzUGxhaW5PYmplY3QoZmlyc3RSZXNwb25zZSk7XG4gICAgICAgICAgICAgICAgICAgICAgICB2YXIgaXNSdW5BUEkgPSAoaXNPYmplY3QgJiYgJC5pc1BsYWluT2JqZWN0KGZpcnN0UmVzcG9uc2UudmFyaWFibGVzKSkgfHwgIWlzT2JqZWN0O1xuICAgICAgICAgICAgICAgICAgICAgICAgaWYgKGlzUnVuQVBJKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgaWYgKGlzT2JqZWN0KSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIGFnZ3JlZ2F0ZSB0aGUgdmFyaWFibGVzIHByb3BlcnR5IG9ubHlcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdmFyIGFnZ3JlZ2F0ZVJ1biA9IGFyZ3VtZW50c1swXVswXTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJC5lYWNoKGFyZ3VtZW50cywgZnVuY3Rpb24gKGlkeCwgYXJncykge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdmFyIHJ1biA9IGFyZ3NbMF07XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAkLmV4dGVuZCh0cnVlLCBhZ2dyZWdhdGVSdW4udmFyaWFibGVzLCBydW4udmFyaWFibGVzKTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG9sZFN1Y2Nlc3MoYWdncmVnYXRlUnVuLCBhcmd1bWVudHNbMF1bMV0sIGFyZ3VtZW50c1swXVsyXSk7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGR0ZC5yZXNvbHZlKGFnZ3JlZ2F0ZVJ1biwgYXJndW1lbnRzWzBdWzFdLCBhcmd1bWVudHNbMF1bMl0pO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIGFycmF5IG9mIHJ1bnNcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gQWdyZWdhdGUgdmFyaWFibGVzIGluIGVhY2ggcnVuXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHZhciBhZ2dyZWdhdGVkUnVucyA9IHt9O1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAkLmVhY2goYXJndW1lbnRzLCBmdW5jdGlvbiAoaWR4LCBhcmdzKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB2YXIgcnVucyA9IGFyZ3NbMF07XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZiAoISQuaXNBcnJheShydW5zKSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICQuZWFjaChydW5zLCBmdW5jdGlvbiAoaWR4UnVuLCBydW4pIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZiAocnVuLmlkICYmICFhZ2dyZWdhdGVkUnVuc1tydW4uaWRdKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJ1bi52YXJpYWJsZXMgPSBydW4udmFyaWFibGVzIHx8IHt9O1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhZ2dyZWdhdGVkUnVuc1tydW4uaWRdID0gcnVuO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0gZWxzZSBpZiAocnVuLmlkKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICQuZXh0ZW5kKHRydWUsIGFnZ3JlZ2F0ZWRSdW5zW3J1bi5pZF0udmFyaWFibGVzLCBydW4udmFyaWFibGVzKTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIHR1cm4gaXQgaW50byBhbiBhcnJheVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhZ2dyZWdhdGVkUnVucyA9ICQubWFwKGFnZ3JlZ2F0ZWRSdW5zLCBmdW5jdGlvbiAocnVuKSB7IHJldHVybiBydW47IH0pO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBvbGRTdWNjZXNzKGFnZ3JlZ2F0ZWRSdW5zLCBhcmd1bWVudHNbMF1bMV0sIGFyZ3VtZW50c1swXVsyXSk7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGR0ZC5yZXNvbHZlKGFnZ3JlZ2F0ZWRSdW5zLCBhcmd1bWVudHNbMF1bMV0sIGFyZ3VtZW50c1swXVsyXSk7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBpcyB2YXJpYWJsZXMgQVBJXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gYWdncmVnYXRlIHRoZSByZXNwb25zZVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHZhciBhZ2dyZWdhdGVkVmFyaWFibGVzID0ge307XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgJC5lYWNoKGFyZ3VtZW50cywgZnVuY3Rpb24gKGlkeCwgYXJncykge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB2YXIgdmFycyA9IGFyZ3NbMF07XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICQuZXh0ZW5kKHRydWUsIGFnZ3JlZ2F0ZWRWYXJpYWJsZXMsIHZhcnMpO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIG9sZFN1Y2Nlc3MoYWdncmVnYXRlZFZhcmlhYmxlcywgYXJndW1lbnRzWzBdWzFdLCBhcmd1bWVudHNbMF1bMl0pO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGR0ZC5yZXNvbHZlKGFnZ3JlZ2F0ZWRWYXJpYWJsZXMsIGFyZ3VtZW50c1swXVsxXSwgYXJndW1lbnRzWzBdWzJdKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgfSwgZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgICAgICAgICAgICAgb2xkRXJyb3IuYXBwbHkoaHR0cCwgYXJndW1lbnRzKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIGR0ZC5yZWplY3QuYXBwbHkoZHRkLCBhcmd1bWVudHMpO1xuICAgICAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIGR0ZC5wcm9taXNlKCk7XG4gICAgICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIGh0dHAuZ2V0KHBhcmFtcywgb3B0aW9ucyk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfTtcbiAgICAgICAgfVxuICAgIH07XG59KCkpO1xuIl19 +//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIm5vZGVfbW9kdWxlcy9icm93c2VyLXBhY2svX3ByZWx1ZGUuanMiLCJub2RlX21vZHVsZXMvQmFzZTY0L2Jhc2U2NC5qcyIsIm5vZGVfbW9kdWxlcy9vYmplY3QtYXNzaWduL2luZGV4LmpzIiwic3JjL2FwaS12ZXJzaW9uLmpzb24iLCJzcmMvYXBwLmpzIiwic3JjL2Vudi1sb2FkLmpzIiwic3JjL21hbmFnZXJzL2F1dGgtbWFuYWdlci5qcyIsInNyYy9tYW5hZ2Vycy9jaGFubmVsLW1hbmFnZXIuanMiLCJzcmMvbWFuYWdlcnMvZXBpY2VudGVyLWNoYW5uZWwtbWFuYWdlci5qcyIsInNyYy9tYW5hZ2Vycy9rZXktbmFtZXMuanMiLCJzcmMvbWFuYWdlcnMvcnVuLW1hbmFnZXIuanMiLCJzcmMvbWFuYWdlcnMvcnVuLXN0cmF0ZWdpZXMvY29uZGl0aW9uYWwtY3JlYXRpb24tc3RyYXRlZ3kuanMiLCJzcmMvbWFuYWdlcnMvcnVuLXN0cmF0ZWdpZXMvZGVwcmVjYXRlZC9uZXctaWYtaW5pdGlhbGl6ZWQtc3RyYXRlZ3kuanMiLCJzcmMvbWFuYWdlcnMvcnVuLXN0cmF0ZWdpZXMvZGVwcmVjYXRlZC9uZXctaWYtcGVyc2lzdGVkLXN0cmF0ZWd5LmpzIiwic3JjL21hbmFnZXJzL3J1bi1zdHJhdGVnaWVzL2luZGV4LmpzIiwic3JjL21hbmFnZXJzL3J1bi1zdHJhdGVnaWVzL211bHRpcGxheWVyLXN0cmF0ZWd5LmpzIiwic3JjL21hbmFnZXJzL3J1bi1zdHJhdGVnaWVzL25vbmUtc3RyYXRlZ3kuanMiLCJzcmMvbWFuYWdlcnMvcnVuLXN0cmF0ZWdpZXMvcmV1c2UtYWNyb3NzLXNlc3Npb25zLmpzIiwic3JjL21hbmFnZXJzL3J1bi1zdHJhdGVnaWVzL3JldXNlLWxhc3QtaW5pdGlhbGl6ZWQuanMiLCJzcmMvbWFuYWdlcnMvcnVuLXN0cmF0ZWdpZXMvcmV1c2UtbmV2ZXIuanMiLCJzcmMvbWFuYWdlcnMvcnVuLXN0cmF0ZWdpZXMvcmV1c2UtcGVyLXNlc3Npb24uanMiLCJzcmMvbWFuYWdlcnMvc2F2ZWQtcnVucy1tYW5hZ2VyLmpzIiwic3JjL21hbmFnZXJzL3NjZW5hcmlvLW1hbmFnZXIuanMiLCJzcmMvbWFuYWdlcnMvc2NlbmFyaW8tc3RyYXRlZ2llcy9iYXNlbGluZS1zdHJhdGVneS5qcyIsInNyYy9tYW5hZ2Vycy9zY2VuYXJpby1zdHJhdGVnaWVzL3JldXNlLWxhc3QtdW5zYXZlZC5qcyIsInNyYy9tYW5hZ2Vycy9zcGVjaWFsLW9wZXJhdGlvbnMuanMiLCJzcmMvbWFuYWdlcnMvc3RyYXRlZ3ktdXRpbHMuanMiLCJzcmMvbWFuYWdlcnMvd29ybGQtbWFuYWdlci5qcyIsInNyYy9zZXJ2aWNlL2FkbWluLWZpbGUtc2VydmljZS5qcyIsInNyYy9zZXJ2aWNlL2Fzc2V0LWFwaS1hZGFwdGVyLmpzIiwic3JjL3NlcnZpY2UvYXV0aC1hcGktc2VydmljZS5qcyIsInNyYy9zZXJ2aWNlL2NoYW5uZWwtc2VydmljZS5qcyIsInNyYy9zZXJ2aWNlL2NvbmZpZ3VyYXRpb24tc2VydmljZS5qcyIsInNyYy9zZXJ2aWNlL2RhdGEtYXBpLXNlcnZpY2UuanMiLCJzcmMvc2VydmljZS9ncm91cC1hcGktc2VydmljZS5qcyIsInNyYy9zZXJ2aWNlL2ludHJvc3BlY3Rpb24tYXBpLXNlcnZpY2UuanMiLCJzcmMvc2VydmljZS9tZW1iZXItYXBpLWFkYXB0ZXIuanMiLCJzcmMvc2VydmljZS9wcmVzZW5jZS1hcGktc2VydmljZS5qcyIsInNyYy9zZXJ2aWNlL3J1bi1hcGktc2VydmljZS5qcyIsInNyYy9zZXJ2aWNlL3NlcnZpY2UtdXRpbHMuanMiLCJzcmMvc2VydmljZS9zdGF0ZS1hcGktYWRhcHRlci5qcyIsInNyYy9zZXJ2aWNlL3VybC1jb25maWctc2VydmljZS5qcyIsInNyYy9zZXJ2aWNlL3VzZXItYXBpLWFkYXB0ZXIuanMiLCJzcmMvc2VydmljZS92YXJpYWJsZXMtYXBpLXNlcnZpY2UuanMiLCJzcmMvc2VydmljZS93b3JsZC1hcGktYWRhcHRlci5qcyIsInNyYy9zdG9yZS9jb29raWUtc3RvcmUuanMiLCJzcmMvc3RvcmUvc2Vzc2lvbi1tYW5hZ2VyLmpzIiwic3JjL3N0b3JlL3N0b3JlLWZhY3RvcnkuanMiLCJzcmMvdHJhbnNwb3J0L2FqYXgtaHR0cC10cmFuc3BvcnQuanMiLCJzcmMvdHJhbnNwb3J0L2h0dHAtdHJhbnNwb3J0LWZhY3RvcnkuanMiLCJzcmMvdXRpbC9pbmhlcml0LmpzIiwic3JjL3V0aWwvb2JqZWN0LXV0aWwuanMiLCJzcmMvdXRpbC9vcHRpb24tdXRpbHMuanMiLCJzcmMvdXRpbC9xdWVyeS11dGlsLmpzIiwic3JjL3V0aWwvcnVuLXV0aWwuanMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7QUNBQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzdEQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDbkZBO0FBQ0E7QUFDQTtBQUNBOzs7QUNIQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7Ozs7QUN2RUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNoQkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUM1WkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNoUUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNyYUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ0xBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzFPQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDaEZBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3BDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUN2Q0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNuSEE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDM0VBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzNCQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUMvREE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUN4RkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzdCQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3hDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzFKQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUMxT0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNyQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzlEQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDUkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUN4Q0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNoS0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzlNQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUMxWEE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDeEhBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDalBBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3hFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNoU0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDeEVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3BJQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDNUxBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDNU5BO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNobUJBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3ZDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3ZKQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNwSUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzNKQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3RLQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDNXZCQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNoSkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ25JQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ1ZBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUMzR0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDTkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUN2REE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ2pCQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDekNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQy9HQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSIsImZpbGUiOiJnZW5lcmF0ZWQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlc0NvbnRlbnQiOlsiKGZ1bmN0aW9uIGUodCxuLHIpe2Z1bmN0aW9uIHMobyx1KXtpZighbltvXSl7aWYoIXRbb10pe3ZhciBhPXR5cGVvZiByZXF1aXJlPT1cImZ1bmN0aW9uXCImJnJlcXVpcmU7aWYoIXUmJmEpcmV0dXJuIGEobywhMCk7aWYoaSlyZXR1cm4gaShvLCEwKTt2YXIgZj1uZXcgRXJyb3IoXCJDYW5ub3QgZmluZCBtb2R1bGUgJ1wiK28rXCInXCIpO3Rocm93IGYuY29kZT1cIk1PRFVMRV9OT1RfRk9VTkRcIixmfXZhciBsPW5bb109e2V4cG9ydHM6e319O3Rbb11bMF0uY2FsbChsLmV4cG9ydHMsZnVuY3Rpb24oZSl7dmFyIG49dFtvXVsxXVtlXTtyZXR1cm4gcyhuP246ZSl9LGwsbC5leHBvcnRzLGUsdCxuLHIpfXJldHVybiBuW29dLmV4cG9ydHN9dmFyIGk9dHlwZW9mIHJlcXVpcmU9PVwiZnVuY3Rpb25cIiYmcmVxdWlyZTtmb3IodmFyIG89MDtvPHIubGVuZ3RoO28rKylzKHJbb10pO3JldHVybiBzfSkiLCI7KGZ1bmN0aW9uICgpIHtcblxuICB2YXIgb2JqZWN0ID0gdHlwZW9mIGV4cG9ydHMgIT0gJ3VuZGVmaW5lZCcgPyBleHBvcnRzIDogc2VsZjsgLy8gIzg6IHdlYiB3b3JrZXJzXG4gIHZhciBjaGFycyA9ICdBQkNERUZHSElKS0xNTk9QUVJTVFVWV1hZWmFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6MDEyMzQ1Njc4OSsvPSc7XG5cbiAgZnVuY3Rpb24gSW52YWxpZENoYXJhY3RlckVycm9yKG1lc3NhZ2UpIHtcbiAgICB0aGlzLm1lc3NhZ2UgPSBtZXNzYWdlO1xuICB9XG4gIEludmFsaWRDaGFyYWN0ZXJFcnJvci5wcm90b3R5cGUgPSBuZXcgRXJyb3I7XG4gIEludmFsaWRDaGFyYWN0ZXJFcnJvci5wcm90b3R5cGUubmFtZSA9ICdJbnZhbGlkQ2hhcmFjdGVyRXJyb3InO1xuXG4gIC8vIGVuY29kZXJcbiAgLy8gW2h0dHBzOi8vZ2lzdC5naXRodWIuY29tLzk5OTE2Nl0gYnkgW2h0dHBzOi8vZ2l0aHViLmNvbS9uaWduYWddXG4gIG9iamVjdC5idG9hIHx8IChcbiAgb2JqZWN0LmJ0b2EgPSBmdW5jdGlvbiAoaW5wdXQpIHtcbiAgICB2YXIgc3RyID0gU3RyaW5nKGlucHV0KTtcbiAgICBmb3IgKFxuICAgICAgLy8gaW5pdGlhbGl6ZSByZXN1bHQgYW5kIGNvdW50ZXJcbiAgICAgIHZhciBibG9jaywgY2hhckNvZGUsIGlkeCA9IDAsIG1hcCA9IGNoYXJzLCBvdXRwdXQgPSAnJztcbiAgICAgIC8vIGlmIHRoZSBuZXh0IHN0ciBpbmRleCBkb2VzIG5vdCBleGlzdDpcbiAgICAgIC8vICAgY2hhbmdlIHRoZSBtYXBwaW5nIHRhYmxlIHRvIFwiPVwiXG4gICAgICAvLyAgIGNoZWNrIGlmIGQgaGFzIG5vIGZyYWN0aW9uYWwgZGlnaXRzXG4gICAgICBzdHIuY2hhckF0KGlkeCB8IDApIHx8IChtYXAgPSAnPScsIGlkeCAlIDEpO1xuICAgICAgLy8gXCI4IC0gaWR4ICUgMSAqIDhcIiBnZW5lcmF0ZXMgdGhlIHNlcXVlbmNlIDIsIDQsIDYsIDhcbiAgICAgIG91dHB1dCArPSBtYXAuY2hhckF0KDYzICYgYmxvY2sgPj4gOCAtIGlkeCAlIDEgKiA4KVxuICAgICkge1xuICAgICAgY2hhckNvZGUgPSBzdHIuY2hhckNvZGVBdChpZHggKz0gMy80KTtcbiAgICAgIGlmIChjaGFyQ29kZSA+IDB4RkYpIHtcbiAgICAgICAgdGhyb3cgbmV3IEludmFsaWRDaGFyYWN0ZXJFcnJvcihcIididG9hJyBmYWlsZWQ6IFRoZSBzdHJpbmcgdG8gYmUgZW5jb2RlZCBjb250YWlucyBjaGFyYWN0ZXJzIG91dHNpZGUgb2YgdGhlIExhdGluMSByYW5nZS5cIik7XG4gICAgICB9XG4gICAgICBibG9jayA9IGJsb2NrIDw8IDggfCBjaGFyQ29kZTtcbiAgICB9XG4gICAgcmV0dXJuIG91dHB1dDtcbiAgfSk7XG5cbiAgLy8gZGVjb2RlclxuICAvLyBbaHR0cHM6Ly9naXN0LmdpdGh1Yi5jb20vMTAyMDM5Nl0gYnkgW2h0dHBzOi8vZ2l0aHViLmNvbS9hdGtdXG4gIG9iamVjdC5hdG9iIHx8IChcbiAgb2JqZWN0LmF0b2IgPSBmdW5jdGlvbiAoaW5wdXQpIHtcbiAgICB2YXIgc3RyID0gU3RyaW5nKGlucHV0KS5yZXBsYWNlKC89KyQvLCAnJyk7XG4gICAgaWYgKHN0ci5sZW5ndGggJSA0ID09IDEpIHtcbiAgICAgIHRocm93IG5ldyBJbnZhbGlkQ2hhcmFjdGVyRXJyb3IoXCInYXRvYicgZmFpbGVkOiBUaGUgc3RyaW5nIHRvIGJlIGRlY29kZWQgaXMgbm90IGNvcnJlY3RseSBlbmNvZGVkLlwiKTtcbiAgICB9XG4gICAgZm9yIChcbiAgICAgIC8vIGluaXRpYWxpemUgcmVzdWx0IGFuZCBjb3VudGVyc1xuICAgICAgdmFyIGJjID0gMCwgYnMsIGJ1ZmZlciwgaWR4ID0gMCwgb3V0cHV0ID0gJyc7XG4gICAgICAvLyBnZXQgbmV4dCBjaGFyYWN0ZXJcbiAgICAgIGJ1ZmZlciA9IHN0ci5jaGFyQXQoaWR4KyspO1xuICAgICAgLy8gY2hhcmFjdGVyIGZvdW5kIGluIHRhYmxlPyBpbml0aWFsaXplIGJpdCBzdG9yYWdlIGFuZCBhZGQgaXRzIGFzY2lpIHZhbHVlO1xuICAgICAgfmJ1ZmZlciAmJiAoYnMgPSBiYyAlIDQgPyBicyAqIDY0ICsgYnVmZmVyIDogYnVmZmVyLFxuICAgICAgICAvLyBhbmQgaWYgbm90IGZpcnN0IG9mIGVhY2ggNCBjaGFyYWN0ZXJzLFxuICAgICAgICAvLyBjb252ZXJ0IHRoZSBmaXJzdCA4IGJpdHMgdG8gb25lIGFzY2lpIGNoYXJhY3RlclxuICAgICAgICBiYysrICUgNCkgPyBvdXRwdXQgKz0gU3RyaW5nLmZyb21DaGFyQ29kZSgyNTUgJiBicyA+PiAoLTIgKiBiYyAmIDYpKSA6IDBcbiAgICApIHtcbiAgICAgIC8vIHRyeSB0byBmaW5kIGNoYXJhY3RlciBpbiB0YWJsZSAoMC02Mywgbm90IGZvdW5kID0+IC0xKVxuICAgICAgYnVmZmVyID0gY2hhcnMuaW5kZXhPZihidWZmZXIpO1xuICAgIH1cbiAgICByZXR1cm4gb3V0cHV0O1xuICB9KTtcblxufSgpKTtcbiIsIid1c2Ugc3RyaWN0Jztcbi8qIGVzbGludC1kaXNhYmxlIG5vLXVudXNlZC12YXJzICovXG52YXIgaGFzT3duUHJvcGVydHkgPSBPYmplY3QucHJvdG90eXBlLmhhc093blByb3BlcnR5O1xudmFyIHByb3BJc0VudW1lcmFibGUgPSBPYmplY3QucHJvdG90eXBlLnByb3BlcnR5SXNFbnVtZXJhYmxlO1xuXG5mdW5jdGlvbiB0b09iamVjdCh2YWwpIHtcblx0aWYgKHZhbCA9PT0gbnVsbCB8fCB2YWwgPT09IHVuZGVmaW5lZCkge1xuXHRcdHRocm93IG5ldyBUeXBlRXJyb3IoJ09iamVjdC5hc3NpZ24gY2Fubm90IGJlIGNhbGxlZCB3aXRoIG51bGwgb3IgdW5kZWZpbmVkJyk7XG5cdH1cblxuXHRyZXR1cm4gT2JqZWN0KHZhbCk7XG59XG5cbmZ1bmN0aW9uIHNob3VsZFVzZU5hdGl2ZSgpIHtcblx0dHJ5IHtcblx0XHRpZiAoIU9iamVjdC5hc3NpZ24pIHtcblx0XHRcdHJldHVybiBmYWxzZTtcblx0XHR9XG5cblx0XHQvLyBEZXRlY3QgYnVnZ3kgcHJvcGVydHkgZW51bWVyYXRpb24gb3JkZXIgaW4gb2xkZXIgVjggdmVyc2lvbnMuXG5cblx0XHQvLyBodHRwczovL2J1Z3MuY2hyb21pdW0ub3JnL3AvdjgvaXNzdWVzL2RldGFpbD9pZD00MTE4XG5cdFx0dmFyIHRlc3QxID0gbmV3IFN0cmluZygnYWJjJyk7ICAvLyBlc2xpbnQtZGlzYWJsZS1saW5lXG5cdFx0dGVzdDFbNV0gPSAnZGUnO1xuXHRcdGlmIChPYmplY3QuZ2V0T3duUHJvcGVydHlOYW1lcyh0ZXN0MSlbMF0gPT09ICc1Jykge1xuXHRcdFx0cmV0dXJuIGZhbHNlO1xuXHRcdH1cblxuXHRcdC8vIGh0dHBzOi8vYnVncy5jaHJvbWl1bS5vcmcvcC92OC9pc3N1ZXMvZGV0YWlsP2lkPTMwNTZcblx0XHR2YXIgdGVzdDIgPSB7fTtcblx0XHRmb3IgKHZhciBpID0gMDsgaSA8IDEwOyBpKyspIHtcblx0XHRcdHRlc3QyWydfJyArIFN0cmluZy5mcm9tQ2hhckNvZGUoaSldID0gaTtcblx0XHR9XG5cdFx0dmFyIG9yZGVyMiA9IE9iamVjdC5nZXRPd25Qcm9wZXJ0eU5hbWVzKHRlc3QyKS5tYXAoZnVuY3Rpb24gKG4pIHtcblx0XHRcdHJldHVybiB0ZXN0MltuXTtcblx0XHR9KTtcblx0XHRpZiAob3JkZXIyLmpvaW4oJycpICE9PSAnMDEyMzQ1Njc4OScpIHtcblx0XHRcdHJldHVybiBmYWxzZTtcblx0XHR9XG5cblx0XHQvLyBodHRwczovL2J1Z3MuY2hyb21pdW0ub3JnL3AvdjgvaXNzdWVzL2RldGFpbD9pZD0zMDU2XG5cdFx0dmFyIHRlc3QzID0ge307XG5cdFx0J2FiY2RlZmdoaWprbG1ub3BxcnN0Jy5zcGxpdCgnJykuZm9yRWFjaChmdW5jdGlvbiAobGV0dGVyKSB7XG5cdFx0XHR0ZXN0M1tsZXR0ZXJdID0gbGV0dGVyO1xuXHRcdH0pO1xuXHRcdGlmIChPYmplY3Qua2V5cyhPYmplY3QuYXNzaWduKHt9LCB0ZXN0MykpLmpvaW4oJycpICE9PVxuXHRcdFx0XHQnYWJjZGVmZ2hpamtsbW5vcHFyc3QnKSB7XG5cdFx0XHRyZXR1cm4gZmFsc2U7XG5cdFx0fVxuXG5cdFx0cmV0dXJuIHRydWU7XG5cdH0gY2F0Y2ggKGUpIHtcblx0XHQvLyBXZSBkb24ndCBleHBlY3QgYW55IG9mIHRoZSBhYm92ZSB0byB0aHJvdywgYnV0IGJldHRlciB0byBiZSBzYWZlLlxuXHRcdHJldHVybiBmYWxzZTtcblx0fVxufVxuXG5tb2R1bGUuZXhwb3J0cyA9IHNob3VsZFVzZU5hdGl2ZSgpID8gT2JqZWN0LmFzc2lnbiA6IGZ1bmN0aW9uICh0YXJnZXQsIHNvdXJjZSkge1xuXHR2YXIgZnJvbTtcblx0dmFyIHRvID0gdG9PYmplY3QodGFyZ2V0KTtcblx0dmFyIHN5bWJvbHM7XG5cblx0Zm9yICh2YXIgcyA9IDE7IHMgPCBhcmd1bWVudHMubGVuZ3RoOyBzKyspIHtcblx0XHRmcm9tID0gT2JqZWN0KGFyZ3VtZW50c1tzXSk7XG5cblx0XHRmb3IgKHZhciBrZXkgaW4gZnJvbSkge1xuXHRcdFx0aWYgKGhhc093blByb3BlcnR5LmNhbGwoZnJvbSwga2V5KSkge1xuXHRcdFx0XHR0b1trZXldID0gZnJvbVtrZXldO1xuXHRcdFx0fVxuXHRcdH1cblxuXHRcdGlmIChPYmplY3QuZ2V0T3duUHJvcGVydHlTeW1ib2xzKSB7XG5cdFx0XHRzeW1ib2xzID0gT2JqZWN0LmdldE93blByb3BlcnR5U3ltYm9scyhmcm9tKTtcblx0XHRcdGZvciAodmFyIGkgPSAwOyBpIDwgc3ltYm9scy5sZW5ndGg7IGkrKykge1xuXHRcdFx0XHRpZiAocHJvcElzRW51bWVyYWJsZS5jYWxsKGZyb20sIHN5bWJvbHNbaV0pKSB7XG5cdFx0XHRcdFx0dG9bc3ltYm9sc1tpXV0gPSBmcm9tW3N5bWJvbHNbaV1dO1xuXHRcdFx0XHR9XG5cdFx0XHR9XG5cdFx0fVxuXHR9XG5cblx0cmV0dXJuIHRvO1xufTtcbiIsIm1vZHVsZS5leHBvcnRzPXtcbiAgICBcInZlcnNpb25cIjogXCJ2MlwiXG59XG4iLCIvKipcbiAqIEVwaWNlbnRlciBKYXZhc2NyaXB0IGxpYnJhcmllc1xuICogdjwlPSB2ZXJzaW9uICU+XG4gKiBodHRwczovL2dpdGh1Yi5jb20vZm9yaW8vZXBpY2VudGVyLWpzLWxpYnNcbiAqL1xuXG52YXIgRiA9IHtcbiAgICBfcHJpdmF0ZToge30sIC8vbmVlZCB0aGlzIGhvb2sgbm93IGJlY2F1c2UgdGVzdHMgZXhwZWN0IGV2ZXJ5dGhpbmcgdG8gYmUgZ2xvYmFsLiBEZWxldGUgb25jZSB0ZXN0cyBhcmUgYnJvd3NlcmlmaWVkXG4gICAgdXRpbDoge30sXG4gICAgZmFjdG9yeToge30sXG4gICAgdHJhbnNwb3J0OiB7fSxcbiAgICBzdG9yZToge30sXG4gICAgc2VydmljZToge30sXG4gICAgbWFuYWdlcjoge1xuICAgICAgICBzdHJhdGVneToge31cbiAgICB9LFxuXG59O1xuXG5GLmxvYWQgPSByZXF1aXJlKCcuL2Vudi1sb2FkJyk7XG5cbmlmICghZ2xvYmFsLlNLSVBfRU5WX0xPQUQpIHtcbiAgICBGLmxvYWQoKTtcbn1cblxuRi51dGlsLnF1ZXJ5ID0gcmVxdWlyZSgnLi91dGlsL3F1ZXJ5LXV0aWwnKTtcbkYudXRpbC5ydW4gPSByZXF1aXJlKCcuL3V0aWwvcnVuLXV0aWwnKTtcbkYudXRpbC5jbGFzc0Zyb20gPSByZXF1aXJlKCcuL3V0aWwvaW5oZXJpdCcpO1xuRi5fcHJpdmF0ZS5zdHJhdGVneXV0aWxzID0gcmVxdWlyZSgnLi9tYW5hZ2Vycy9zdHJhdGVneS11dGlscycpO1xuXG5GLmZhY3RvcnkuVHJhbnNwb3J0ID0gcmVxdWlyZSgnLi90cmFuc3BvcnQvaHR0cC10cmFuc3BvcnQtZmFjdG9yeScpO1xuRi50cmFuc3BvcnQuQWpheCA9IHJlcXVpcmUoJy4vdHJhbnNwb3J0L2FqYXgtaHR0cC10cmFuc3BvcnQnKTtcblxuRi5zZXJ2aWNlLlVSTCA9IHJlcXVpcmUoJy4vc2VydmljZS91cmwtY29uZmlnLXNlcnZpY2UnKTtcbkYuc2VydmljZS5Db25maWcgPSByZXF1aXJlKCcuL3NlcnZpY2UvY29uZmlndXJhdGlvbi1zZXJ2aWNlJyk7XG5GLnNlcnZpY2UuUnVuID0gcmVxdWlyZSgnLi9zZXJ2aWNlL3J1bi1hcGktc2VydmljZScpO1xuRi5zZXJ2aWNlLkZpbGUgPSByZXF1aXJlKCcuL3NlcnZpY2UvYWRtaW4tZmlsZS1zZXJ2aWNlJyk7XG5GLnNlcnZpY2UuVmFyaWFibGVzID0gcmVxdWlyZSgnLi9zZXJ2aWNlL3ZhcmlhYmxlcy1hcGktc2VydmljZScpO1xuRi5zZXJ2aWNlLkRhdGEgPSByZXF1aXJlKCcuL3NlcnZpY2UvZGF0YS1hcGktc2VydmljZScpO1xuRi5zZXJ2aWNlLkF1dGggPSByZXF1aXJlKCcuL3NlcnZpY2UvYXV0aC1hcGktc2VydmljZScpO1xuRi5zZXJ2aWNlLldvcmxkID0gcmVxdWlyZSgnLi9zZXJ2aWNlL3dvcmxkLWFwaS1hZGFwdGVyJyk7XG5GLnNlcnZpY2UuU3RhdGUgPSByZXF1aXJlKCcuL3NlcnZpY2Uvc3RhdGUtYXBpLWFkYXB0ZXInKTtcbkYuc2VydmljZS5Vc2VyID0gcmVxdWlyZSgnLi9zZXJ2aWNlL3VzZXItYXBpLWFkYXB0ZXInKTtcbkYuc2VydmljZS5NZW1iZXIgPSByZXF1aXJlKCcuL3NlcnZpY2UvbWVtYmVyLWFwaS1hZGFwdGVyJyk7XG5GLnNlcnZpY2UuQXNzZXQgPSByZXF1aXJlKCcuL3NlcnZpY2UvYXNzZXQtYXBpLWFkYXB0ZXInKTtcbkYuc2VydmljZS5Hcm91cCA9IHJlcXVpcmUoJy4vc2VydmljZS9ncm91cC1hcGktc2VydmljZScpO1xuRi5zZXJ2aWNlLkludHJvc3BlY3QgPSByZXF1aXJlKCcuL3NlcnZpY2UvaW50cm9zcGVjdGlvbi1hcGktc2VydmljZScpO1xuRi5zZXJ2aWNlLlByZXNlbmNlID0gcmVxdWlyZSgnLi9zZXJ2aWNlL3ByZXNlbmNlLWFwaS1zZXJ2aWNlJyk7XG5cbkYuc3RvcmUuQ29va2llID0gcmVxdWlyZSgnLi9zdG9yZS9jb29raWUtc3RvcmUnKTtcbkYuZmFjdG9yeS5TdG9yZSA9IHJlcXVpcmUoJy4vc3RvcmUvc3RvcmUtZmFjdG9yeScpO1xuXG5GLm1hbmFnZXIuU2NlbmFyaW9NYW5hZ2VyID0gcmVxdWlyZSgnLi9tYW5hZ2Vycy9zY2VuYXJpby1tYW5hZ2VyJyk7XG5GLm1hbmFnZXIuUnVuTWFuYWdlciA9IHJlcXVpcmUoJy4vbWFuYWdlcnMvcnVuLW1hbmFnZXInKTtcbkYubWFuYWdlci5BdXRoTWFuYWdlciA9IHJlcXVpcmUoJy4vbWFuYWdlcnMvYXV0aC1tYW5hZ2VyJyk7XG5GLm1hbmFnZXIuV29ybGRNYW5hZ2VyID0gcmVxdWlyZSgnLi9tYW5hZ2Vycy93b3JsZC1tYW5hZ2VyJyk7XG5GLm1hbmFnZXIuU2F2ZWRSdW5zTWFuYWdlciA9IHJlcXVpcmUoJy4vbWFuYWdlcnMvc2F2ZWQtcnVucy1tYW5hZ2VyJyk7XG5cbnZhciBzdHJhdGVnaWVzID0gcmVxdWlyZSgnLi9tYW5hZ2Vycy9ydW4tc3RyYXRlZ2llcycpO1xuRi5tYW5hZ2VyLnN0cmF0ZWd5ID0gc3RyYXRlZ2llcy5saXN0OyAvL1RPRE86IHRoaXMgaXMgbm90IHJlYWxseSBhIG1hbmFnZXIgc28gbmFtZXNwYWNlIHRoaXMgYmV0dGVyXG5cbkYubWFuYWdlci5DaGFubmVsTWFuYWdlciA9IHJlcXVpcmUoJy4vbWFuYWdlcnMvZXBpY2VudGVyLWNoYW5uZWwtbWFuYWdlcicpO1xuRi5zZXJ2aWNlLkNoYW5uZWwgPSByZXF1aXJlKCcuL3NlcnZpY2UvY2hhbm5lbC1zZXJ2aWNlJyk7XG5cbkYudmVyc2lvbiA9ICc8JT0gdmVyc2lvbiAlPic7XG5GLmFwaSA9IHJlcXVpcmUoJy4vYXBpLXZlcnNpb24uanNvbicpO1xuXG5GLmNvbnN0YW50cyA9IHJlcXVpcmUoJy4vbWFuYWdlcnMva2V5LW5hbWVzJyk7XG5cbmdsb2JhbC5GID0gRjtcbm1vZHVsZS5leHBvcnRzID0gRjtcbiIsIid1c2Ugc3RyaWN0JztcblxudmFyIFVSTENvbmZpZ1NlcnZpY2UgPSByZXF1aXJlKCcuL3NlcnZpY2UvdXJsLWNvbmZpZy1zZXJ2aWNlJyk7XG5cbnZhciBlbnZMb2FkID0gZnVuY3Rpb24gKGNhbGxiYWNrKSB7XG4gICAgdmFyIHVybFNlcnZpY2UgPSBuZXcgVVJMQ29uZmlnU2VydmljZSgpO1xuICAgIHZhciBpbmZvVXJsID0gdXJsU2VydmljZS5nZXRBUElQYXRoKCdjb25maWcnKTtcbiAgICB2YXIgZW52UHJvbWlzZSA9ICQuYWpheCh7IHVybDogaW5mb1VybCwgYXN5bmM6IGZhbHNlIH0pO1xuICAgIGVudlByb21pc2UgPSBlbnZQcm9taXNlLnRoZW4oZnVuY3Rpb24gKHJlcykge1xuICAgICAgICB2YXIgb3ZlcnJpZGVzID0gcmVzLmFwaTtcbiAgICAgICAgVVJMQ29uZmlnU2VydmljZS5kZWZhdWx0cyA9ICQuZXh0ZW5kKFVSTENvbmZpZ1NlcnZpY2UuZGVmYXVsdHMsIG92ZXJyaWRlcyk7XG4gICAgfSk7XG4gICAgcmV0dXJuIGVudlByb21pc2UudGhlbihjYWxsYmFjaykuZmFpbChjYWxsYmFjayk7XG59O1xuXG5tb2R1bGUuZXhwb3J0cyA9IGVudkxvYWQ7XG4iLCIvKipcbiogIyMgQXV0aG9yaXphdGlvbiBNYW5hZ2VyXG4qXG4qIFRoZSBBdXRob3JpemF0aW9uIE1hbmFnZXIgcHJvdmlkZXMgYW4gZWFzeSB3YXkgdG8gbWFuYWdlIHVzZXIgYXV0aGVudGljYXRpb24gKGxvZ2dpbmcgaW4gYW5kIG91dCkgYW5kIGF1dGhvcml6YXRpb24gKGtlZXBpbmcgdHJhY2sgb2YgdG9rZW5zLCBzZXNzaW9ucywgYW5kIGdyb3VwcykgZm9yIHByb2plY3RzLlxuKlxuKiBUaGUgQXV0aG9yaXphdGlvbiBNYW5hZ2VyIGlzIG1vc3QgdXNlZnVsIGZvciBbdGVhbSBwcm9qZWN0c10oLi4vLi4vLi4vZ2xvc3NhcnkvI3RlYW0pIHdpdGggYW4gYWNjZXNzIGxldmVsIG9mIFtBdXRoZW50aWNhdGVkXSguLi8uLi8uLi9nbG9zc2FyeS8jYWNjZXNzKS4gVGhlc2UgcHJvamVjdHMgYXJlIGFjY2Vzc2VkIGJ5IFtlbmQgdXNlcnNdKC4uLy4uLy4uL2dsb3NzYXJ5LyN1c2Vycykgd2hvIGFyZSBtZW1iZXJzIG9mIG9uZSBvciBtb3JlIFtncm91cHNdKC4uLy4uLy4uL2dsb3NzYXJ5LyNncm91cHMpLlxuKlxuKiAjIyMjIFVzaW5nIHRoZSBBdXRob3JpemF0aW9uIE1hbmFnZXJcbipcbiogVG8gdXNlIHRoZSBBdXRob3JpemF0aW9uIE1hbmFnZXIsIGluc3RhbnRpYXRlIGl0LiBUaGVuLCBtYWtlIGNhbGxzIHRvIGFueSBvZiB0aGUgbWV0aG9kcyB5b3UgbmVlZDpcbipcbiogICAgICAgdmFyIGF1dGhNZ3IgPSBuZXcgRi5tYW5hZ2VyLkF1dGhNYW5hZ2VyKHtcbiogICAgICAgICAgIGFjY291bnQ6ICdhY21lLXNpbXVsYXRpb25zJyxcbiogICAgICAgICAgIHVzZXJOYW1lOiAnZW5kdXNlcjEnLFxuKiAgICAgICAgICAgcGFzc3dvcmQ6ICdwYXNzdzByZCdcbiogICAgICAgfSk7XG4qICAgICAgIGF1dGhNZ3IubG9naW4oKS50aGVuKGZ1bmN0aW9uICgpIHtcbiogICAgICAgICAgIGF1dGhNZ3IuZ2V0Q3VycmVudFVzZXJTZXNzaW9uSW5mbygpO1xuKiAgICAgICB9KTtcbipcbipcbiogVGhlIGBvcHRpb25zYCBvYmplY3QgcGFzc2VkIHRvIHRoZSBgRi5tYW5hZ2VyLkF1dGhNYW5hZ2VyKClgIGNhbGwgY2FuIGluY2x1ZGU6XG4qXG4qICAgKiBgYWNjb3VudGA6IFRoZSBhY2NvdW50IGlkIGZvciB0aGlzIGB1c2VyTmFtZWAuIEluIHRoZSBFcGljZW50ZXIgVUksIHRoaXMgaXMgdGhlICoqVGVhbSBJRCoqIChmb3IgdGVhbSBwcm9qZWN0cykgb3IgdGhlICoqVXNlciBJRCoqIChmb3IgcGVyc29uYWwgcHJvamVjdHMpLlxuKiAgICogYHVzZXJOYW1lYDogRW1haWwgb3IgdXNlcm5hbWUgdG8gdXNlIGZvciBsb2dnaW5nIGluLlxuKiAgICogYHBhc3N3b3JkYDogUGFzc3dvcmQgZm9yIHNwZWNpZmllZCBgdXNlck5hbWVgLlxuKiAgICogYHByb2plY3RgOiBUaGUgKipQcm9qZWN0IElEKiogZm9yIHRoZSBwcm9qZWN0IHRvIGxvZyB0aGlzIHVzZXIgaW50by4gT3B0aW9uYWwuXG4qICAgKiBgZ3JvdXBJZGA6IElkIG9mIHRoZSBncm91cCB0byB3aGljaCBgdXNlck5hbWVgIGJlbG9uZ3MuIFJlcXVpcmVkIGZvciBlbmQgdXNlcnMgaWYgdGhlIGBwcm9qZWN0YCBpcyBzcGVjaWZpZWQuXG4qXG4qIElmIHlvdSBwcmVmZXIgc3RhcnRpbmcgZnJvbSBhIHRlbXBsYXRlLCB0aGUgRXBpY2VudGVyIEpTIExpYnMgW0xvZ2luIENvbXBvbmVudF0oLi4vLi4vI2NvbXBvbmVudHMpIHVzZXMgdGhlIEF1dGhvcml6YXRpb24gTWFuYWdlciBhcyB3ZWxsLiBUaGlzIHNhbXBsZSBIVE1MIHBhZ2UgKGFuZCBhc3NvY2lhdGVkIENTUyBhbmQgSlMgZmlsZXMpIHByb3ZpZGVzIGEgbG9naW4gZm9ybSBmb3IgdGVhbSBtZW1iZXJzIGFuZCBlbmQgdXNlcnMgb2YgeW91ciBwcm9qZWN0LiBJdCBhbHNvIGluY2x1ZGVzIGEgZ3JvdXAgc2VsZWN0b3IgZm9yIGVuZCB1c2VycyB0aGF0IGFyZSBtZW1iZXJzIG9mIG11bHRpcGxlIGdyb3Vwcy5cbiovXG5cbid1c2Ugc3RyaWN0JztcbnZhciBBdXRoQWRhcHRlciA9IHJlcXVpcmUoJy4uL3NlcnZpY2UvYXV0aC1hcGktc2VydmljZScpO1xudmFyIE1lbWJlckFkYXB0ZXIgPSByZXF1aXJlKCcuLi9zZXJ2aWNlL21lbWJlci1hcGktYWRhcHRlcicpO1xudmFyIEdyb3VwU2VydmljZSA9IHJlcXVpcmUoJy4uL3NlcnZpY2UvZ3JvdXAtYXBpLXNlcnZpY2UnKTtcbnZhciBTZXNzaW9uTWFuYWdlciA9IHJlcXVpcmUoJy4uL3N0b3JlL3Nlc3Npb24tbWFuYWdlcicpO1xudmFyIF9waWNrID0gcmVxdWlyZSgnLi4vdXRpbC9vYmplY3QtdXRpbCcpLl9waWNrO1xudmFyIG9iamVjdEFzc2lnbiA9IHJlcXVpcmUoJ29iamVjdC1hc3NpZ24nKTtcblxudmFyIGF0b2IgPSB3aW5kb3cuYXRvYiB8fCByZXF1aXJlKCdCYXNlNjQnKS5hdG9iO1xuXG52YXIgZGVmYXVsdHMgPSB7XG4gICAgcmVxdWlyZXNHcm91cDogdHJ1ZVxufTtcblxuZnVuY3Rpb24gQXV0aE1hbmFnZXIob3B0aW9ucykge1xuICAgIG9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSwgZGVmYXVsdHMsIG9wdGlvbnMpO1xuICAgIHRoaXMuc2Vzc2lvbk1hbmFnZXIgPSBuZXcgU2Vzc2lvbk1hbmFnZXIob3B0aW9ucyk7XG4gICAgdGhpcy5vcHRpb25zID0gdGhpcy5zZXNzaW9uTWFuYWdlci5nZXRNZXJnZWRPcHRpb25zKCk7XG5cbiAgICB0aGlzLmF1dGhBZGFwdGVyID0gbmV3IEF1dGhBZGFwdGVyKHRoaXMub3B0aW9ucyk7XG59XG5cbnZhciBfZmluZFVzZXJJbkdyb3VwID0gZnVuY3Rpb24gKG1lbWJlcnMsIGlkKSB7XG4gICAgZm9yICh2YXIgaiA9IDA7IGogPCBtZW1iZXJzLmxlbmd0aDsgaisrKSB7XG4gICAgICAgIGlmIChtZW1iZXJzW2pdLnVzZXJJZCA9PT0gaWQpIHtcbiAgICAgICAgICAgIHJldHVybiBtZW1iZXJzW2pdO1xuICAgICAgICB9XG4gICAgfVxuICAgIHJldHVybiBudWxsO1xufTtcblxuQXV0aE1hbmFnZXIucHJvdG90eXBlID0gJC5leHRlbmQoQXV0aE1hbmFnZXIucHJvdG90eXBlLCB7XG5cbiAgICAvKipcbiAgICAqIExvZ3MgdXNlciBpbi5cbiAgICAqXG4gICAgKiAqKkV4YW1wbGUqKlxuICAgICpcbiAgICAqICAgICAgIGF1dGhNZ3IubG9naW4oe1xuICAgICogICAgICAgICAgIGFjY291bnQ6ICdhY21lLXNpbXVsYXRpb25zJyxcbiAgICAqICAgICAgICAgICBwcm9qZWN0OiAnc3VwcGx5LWNoYWluLWdhbWUnLFxuICAgICogICAgICAgICAgIHVzZXJOYW1lOiAnZW5kdXNlcjEnLFxuICAgICogICAgICAgICAgIHBhc3N3b3JkOiAncGFzc3cwcmQnXG4gICAgKiAgICAgICB9KVxuICAgICogICAgICAgICAgIC50aGVuKGZ1bmN0aW9uKHN0YXR1c09iaikge1xuICAgICogICAgICAgICAgICAgICAvLyBpZiBlbmR1c2VyMSBiZWxvbmdzIHRvIGV4YWN0bHkgb25lIGdyb3VwXG4gICAgKiAgICAgICAgICAgICAgIC8vIChvciBpZiB0aGUgbG9naW4oKSBjYWxsIGlzIG1vZGlmaWVkIHRvIGluY2x1ZGUgdGhlIGdyb3VwIGlkKVxuICAgICogICAgICAgICAgICAgICAvLyBjb250aW51ZSBoZXJlXG4gICAgKiAgICAgICAgICAgfSlcbiAgICAqICAgICAgICAgICAuZmFpbChmdW5jdGlvbihzdGF0dXNPYmopIHtcbiAgICAqICAgICAgICAgICAgICAgLy8gaWYgZW5kdXNlcjEgYmVsb25ncyB0byBtdWx0aXBsZSBncm91cHMsXG4gICAgKiAgICAgICAgICAgICAgIC8vIHRoZSBsb2dpbigpIGNhbGwgZmFpbHNcbiAgICAqICAgICAgICAgICAgICAgLy8gYW5kIHJldHVybnMgYWxsIGdyb3VwcyBvZiB3aGljaCB0aGUgdXNlciBpcyBhIG1lbWJlclxuICAgICogICAgICAgICAgICAgICBmb3IgKHZhciBpPTA7IGkgPCBzdGF0dXNPYmoudXNlckdyb3Vwcy5sZW5ndGg7IGkrKykge1xuICAgICogICAgICAgICAgICAgICAgICAgY29uc29sZS5sb2coc3RhdHVzT2JqLnVzZXJHcm91cHNbaV0ubmFtZSwgc3RhdHVzT2JqLnVzZXJHcm91cHNbaV0uZ3JvdXBJZCk7XG4gICAgKiAgICAgICAgICAgICAgIH1cbiAgICAqICAgICAgICAgICB9KTtcbiAgICAqXG4gICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICpcbiAgICAqIEBwYXJhbSB7T2JqZWN0fSBvcHRpb25zIChPcHRpb25hbCkgT3ZlcnJpZGVzIGZvciBjb25maWd1cmF0aW9uIG9wdGlvbnMuIElmIG5vdCBwYXNzZWQgaW4gd2hlbiBjcmVhdGluZyBhbiBpbnN0YW5jZSBvZiB0aGUgbWFuYWdlciAoYEYubWFuYWdlci5BdXRoTWFuYWdlcigpYCksIHRoZXNlIG9wdGlvbnMgc2hvdWxkIGluY2x1ZGU6XG4gICAgKiBAcGFyYW0ge3N0cmluZ30gb3B0aW9ucy5hY2NvdW50IFRoZSBhY2NvdW50IGlkIGZvciB0aGlzIGB1c2VyTmFtZWAuIEluIHRoZSBFcGljZW50ZXIgVUksIHRoaXMgaXMgdGhlICoqVGVhbSBJRCoqIChmb3IgdGVhbSBwcm9qZWN0cykgb3IgdGhlICoqVXNlciBJRCoqIChmb3IgcGVyc29uYWwgcHJvamVjdHMpLlxuICAgICogQHBhcmFtIHtzdHJpbmd9IG9wdGlvbnMudXNlck5hbWUgRW1haWwgb3IgdXNlcm5hbWUgdG8gdXNlIGZvciBsb2dnaW5nIGluLlxuICAgICogQHBhcmFtIHtzdHJpbmd9IG9wdGlvbnMucGFzc3dvcmQgUGFzc3dvcmQgZm9yIHNwZWNpZmllZCBgdXNlck5hbWVgLlxuICAgICogQHBhcmFtIHtzdHJpbmd9IG9wdGlvbnMucHJvamVjdCAoT3B0aW9uYWwpIFRoZSAqKlByb2plY3QgSUQqKiBmb3IgdGhlIHByb2plY3QgdG8gbG9nIHRoaXMgdXNlciBpbnRvLlxuICAgICogQHBhcmFtIHtzdHJpbmd9IG9wdGlvbnMuZ3JvdXBJZCBUaGUgaWQgb2YgdGhlIGdyb3VwIHRvIHdoaWNoIGB1c2VyTmFtZWAgYmVsb25ncy4gUmVxdWlyZWQgZm9yIFtlbmQgdXNlcnNdKC4uLy4uLy4uL2dsb3NzYXJ5LyN1c2VycykgaWYgdGhlIGBwcm9qZWN0YCBpcyBzcGVjaWZpZWQgYW5kIGlmIHRoZSBlbmQgdXNlcnMgYXJlIG1lbWJlcnMgb2YgbXVsdGlwbGUgW2dyb3Vwc10oLi4vLi4vLi4vZ2xvc3NhcnkvI2dyb3VwcyksIG90aGVyd2lzZSBvcHRpb25hbC5cbiAgICAqIEByZXR1cm4ge1Byb21pc2V9XG4gICAgKi9cbiAgICBsb2dpbjogZnVuY3Rpb24gKG9wdGlvbnMpIHtcbiAgICAgICAgdmFyIG1lID0gdGhpcztcbiAgICAgICAgdmFyICRkID0gJC5EZWZlcnJlZCgpO1xuICAgICAgICB2YXIgc2Vzc2lvbk1hbmFnZXIgPSB0aGlzLnNlc3Npb25NYW5hZ2VyO1xuICAgICAgICB2YXIgYWRhcHRlck9wdGlvbnMgPSBzZXNzaW9uTWFuYWdlci5nZXRNZXJnZWRPcHRpb25zKHsgc3VjY2VzczogJC5ub29wLCBlcnJvcjogJC5ub29wIH0sIG9wdGlvbnMpO1xuICAgICAgICB2YXIgb3V0U3VjY2VzcyA9IGFkYXB0ZXJPcHRpb25zLnN1Y2Nlc3M7XG4gICAgICAgIHZhciBvdXRFcnJvciA9IGFkYXB0ZXJPcHRpb25zLmVycm9yO1xuICAgICAgICB2YXIgZ3JvdXBJZCA9IGFkYXB0ZXJPcHRpb25zLmdyb3VwSWQ7XG5cbiAgICAgICAgdmFyIGRlY29kZVRva2VuID0gZnVuY3Rpb24gKHRva2VuKSB7XG4gICAgICAgICAgICB2YXIgZW5jb2RlZCA9IHRva2VuLnNwbGl0KCcuJylbMV07XG4gICAgICAgICAgICB3aGlsZSAoZW5jb2RlZC5sZW5ndGggJSA0ICE9PSAwKSB7IC8vZXNsaW50LWRpc2FibGUtbGluZVxuICAgICAgICAgICAgICAgIGVuY29kZWQgKz0gJz0nO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgcmV0dXJuIEpTT04ucGFyc2UoYXRvYihlbmNvZGVkKSk7XG4gICAgICAgIH07XG5cbiAgICAgICAgdmFyIGhhbmRsZUdyb3VwRXJyb3IgPSBmdW5jdGlvbiAobWVzc2FnZSwgc3RhdHVzQ29kZSwgZGF0YSwgdHlwZSkge1xuICAgICAgICAgICAgLy8gbG9nb3V0IHRoZSB1c2VyIHNpbmNlIGl0J3MgaW4gYW4gaW52YWxpZCBzdGF0ZSB3aXRoIG5vIGdyb3VwIHNlbGVjdGVkXG4gICAgICAgICAgICBtZS5sb2dvdXQoKS50aGVuKGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgICAgICB2YXIgZXJyb3IgPSAkLmV4dGVuZCh0cnVlLCB7fSwgZGF0YSwgeyBzdGF0dXNUZXh0OiBtZXNzYWdlLCBzdGF0dXM6IHN0YXR1c0NvZGUsIHR5cGU6IHR5cGUgfSk7XG4gICAgICAgICAgICAgICAgJGQucmVqZWN0KGVycm9yKTtcbiAgICAgICAgICAgIH0pO1xuICAgICAgICB9O1xuXG4gICAgICAgIHZhciBoYW5kbGVTdWNjZXNzID0gZnVuY3Rpb24gKHJlc3BvbnNlKSB7XG4gICAgICAgICAgICB2YXIgdG9rZW4gPSByZXNwb25zZS5hY2Nlc3NfdG9rZW47XG4gICAgICAgICAgICB2YXIgdXNlckluZm8gPSBkZWNvZGVUb2tlbih0b2tlbik7XG4gICAgICAgICAgICB2YXIgb2xkR3JvdXBzID0gc2Vzc2lvbk1hbmFnZXIuZ2V0U2Vzc2lvbihhZGFwdGVyT3B0aW9ucykuZ3JvdXBzIHx8IHt9O1xuICAgICAgICAgICAgdmFyIHVzZXJHcm91cE9wdHMgPSAkLmV4dGVuZCh0cnVlLCB7fSwgYWRhcHRlck9wdGlvbnMsIHsgc3VjY2VzczogJC5ub29wIH0pO1xuICAgICAgICAgICAgdmFyIGRhdGEgPSB7IGF1dGg6IHJlc3BvbnNlLCB1c2VyOiB1c2VySW5mbyB9O1xuICAgICAgICAgICAgdmFyIHByb2plY3QgPSBhZGFwdGVyT3B0aW9ucy5wcm9qZWN0O1xuICAgICAgICAgICAgdmFyIGlzVGVhbU1lbWJlciA9IHVzZXJJbmZvLnBhcmVudF9hY2NvdW50X2lkID09PSBudWxsO1xuICAgICAgICAgICAgdmFyIHJlcXVpcmVzR3JvdXAgPSBhZGFwdGVyT3B0aW9ucy5yZXF1aXJlc0dyb3VwICYmIHByb2plY3Q7XG5cbiAgICAgICAgICAgIHZhciB1c2VyTmFtZSA9ICh1c2VySW5mby51c2VyX25hbWUgfHwgJycpLnNwbGl0KCcvJylbMF07IC8vb2YgZm9ybSA8dXNlcj4vPHRlYW0+XG4gICAgICAgICAgICB2YXIgc2Vzc2lvbkluZm8gPSB7XG4gICAgICAgICAgICAgICAgYXV0aF90b2tlbjogdG9rZW4sXG4gICAgICAgICAgICAgICAgYWNjb3VudDogYWRhcHRlck9wdGlvbnMuYWNjb3VudCxcbiAgICAgICAgICAgICAgICBwcm9qZWN0OiBwcm9qZWN0LFxuICAgICAgICAgICAgICAgIHVzZXJJZDogdXNlckluZm8udXNlcl9pZCxcbiAgICAgICAgICAgICAgICBncm91cHM6IG9sZEdyb3VwcyxcbiAgICAgICAgICAgICAgICBpc1RlYW1NZW1iZXI6IGlzVGVhbU1lbWJlcixcbiAgICAgICAgICAgICAgICB1c2VyTmFtZTogdXNlck5hbWUsXG4gICAgICAgICAgICB9O1xuICAgICAgICAgICAgLy8gVGhlIGdyb3VwIGlzIG5vdCByZXF1aXJlZCBpZiB0aGUgdXNlciBpcyBub3QgbG9nZ2luZyBpbnRvIGEgcHJvamVjdFxuICAgICAgICAgICAgaWYgKCFyZXF1aXJlc0dyb3VwKSB7XG4gICAgICAgICAgICAgICAgc2Vzc2lvbk1hbmFnZXIuc2F2ZVNlc3Npb24oc2Vzc2lvbkluZm8pO1xuICAgICAgICAgICAgICAgIG91dFN1Y2Nlc3MuYXBwbHkodGhpcywgW2RhdGFdKTtcbiAgICAgICAgICAgICAgICAkZC5yZXNvbHZlKGRhdGEpO1xuICAgICAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgdmFyIGhhbmRsZUdyb3VwTGlzdCA9IGZ1bmN0aW9uIChncm91cExpc3QpIHtcbiAgICAgICAgICAgICAgICBkYXRhLnVzZXJHcm91cHMgPSBncm91cExpc3Q7XG5cbiAgICAgICAgICAgICAgICB2YXIgZ3JvdXAgPSBudWxsO1xuICAgICAgICAgICAgICAgIGlmIChncm91cExpc3QubGVuZ3RoID09PSAwKSB7XG4gICAgICAgICAgICAgICAgICAgIGhhbmRsZUdyb3VwRXJyb3IoJ1RoZSB1c2VyIGhhcyBubyBncm91cHMgYXNzb2NpYXRlZCBpbiB0aGlzIGFjY291bnQnLCA0MDMsIGRhdGEsICdOT19HUk9VUFMnKTtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgICAgICAgIH0gZWxzZSBpZiAoZ3JvdXBMaXN0Lmxlbmd0aCA9PT0gMSkge1xuICAgICAgICAgICAgICAgICAgICAvLyBTZWxlY3QgdGhlIG9ubHkgZ3JvdXBcbiAgICAgICAgICAgICAgICAgICAgZ3JvdXAgPSBncm91cExpc3RbMF07XG4gICAgICAgICAgICAgICAgfSBlbHNlIGlmIChncm91cExpc3QubGVuZ3RoID4gMSkge1xuICAgICAgICAgICAgICAgICAgICBpZiAoZ3JvdXBJZCkge1xuICAgICAgICAgICAgICAgICAgICAgICAgdmFyIGZpbHRlcmVkR3JvdXBzID0gJC5ncmVwKGdyb3VwTGlzdCwgZnVuY3Rpb24gKHJlc0dyb3VwKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIHJlc0dyb3VwLmdyb3VwSWQgPT09IGdyb3VwSWQ7XG4gICAgICAgICAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgICAgICAgICAgIGdyb3VwID0gZmlsdGVyZWRHcm91cHMubGVuZ3RoID09PSAxID8gZmlsdGVyZWRHcm91cHNbMF0gOiBudWxsO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgaWYgKGdyb3VwKSB7XG4gICAgICAgICAgICAgICAgICAgIC8vIEEgdGVhbSBtZW1iZXIgZG9lcyBub3QgZ2V0IHRoZSBncm91cCBtZW1iZXJzIGJlY2F1c2UgaXMgY2FsbGluZyB0aGUgR3JvdXAgQVBJXG4gICAgICAgICAgICAgICAgICAgIC8vIGJ1dCBpdCdzIGF1dG9tYXRpY2FsbHkgYSBmYWMgdXNlclxuICAgICAgICAgICAgICAgICAgICB2YXIgaXNGYWMgPSBpc1RlYW1NZW1iZXIgPyB0cnVlIDogX2ZpbmRVc2VySW5Hcm91cChncm91cC5tZW1iZXJzLCB1c2VySW5mby51c2VyX2lkKS5yb2xlID09PSAnZmFjaWxpdGF0b3InO1xuICAgICAgICAgICAgICAgICAgICB2YXIgZ3JvdXBEYXRhID0ge1xuICAgICAgICAgICAgICAgICAgICAgICAgZ3JvdXBJZDogZ3JvdXAuZ3JvdXBJZCxcbiAgICAgICAgICAgICAgICAgICAgICAgIGdyb3VwTmFtZTogZ3JvdXAubmFtZSxcbiAgICAgICAgICAgICAgICAgICAgICAgIGlzRmFjOiBpc0ZhY1xuICAgICAgICAgICAgICAgICAgICB9O1xuICAgICAgICAgICAgICAgICAgICB2YXIgc2Vzc2lvbkluZm9XaXRoR3JvdXAgPSBvYmplY3RBc3NpZ24oe30sIHNlc3Npb25JbmZvLCBncm91cERhdGEpO1xuICAgICAgICAgICAgICAgICAgICBzZXNzaW9uSW5mby5ncm91cHNbcHJvamVjdF0gPSBncm91cERhdGE7XG4gICAgICAgICAgICAgICAgICAgIG1lLnNlc3Npb25NYW5hZ2VyLnNhdmVTZXNzaW9uKHNlc3Npb25JbmZvV2l0aEdyb3VwLCBhZGFwdGVyT3B0aW9ucyk7XG4gICAgICAgICAgICAgICAgICAgIG91dFN1Y2Nlc3MuYXBwbHkodGhpcywgW2RhdGFdKTtcbiAgICAgICAgICAgICAgICAgICAgJGQucmVzb2x2ZShkYXRhKTtcbiAgICAgICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICBoYW5kbGVHcm91cEVycm9yKCdUaGlzIHVzZXIgaXMgYXNzb2NpYXRlZCB3aXRoIG1vcmUgdGhhbiBvbmUgZ3JvdXAuIFBsZWFzZSBzcGVjaWZ5IGEgZ3JvdXAgaWQgdG8gbG9nIGludG8gYW5kIHRyeSBhZ2FpbicsIDQwMywgZGF0YSwgJ01VTFRJUExFX0dST1VQUycpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH07XG5cbiAgICAgICAgICAgIGlmICghaXNUZWFtTWVtYmVyKSB7XG4gICAgICAgICAgICAgICAgbWUuZ2V0VXNlckdyb3Vwcyh7IHVzZXJJZDogdXNlckluZm8udXNlcl9pZCwgdG9rZW46IHRva2VuIH0sIHVzZXJHcm91cE9wdHMpXG4gICAgICAgICAgICAgICAgICAgIC50aGVuKGhhbmRsZUdyb3VwTGlzdCwgJGQucmVqZWN0KTtcbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgdmFyIG9wdHMgPSBvYmplY3RBc3NpZ24oe30sIHVzZXJHcm91cE9wdHMsIHsgdG9rZW46IHRva2VuIH0pO1xuICAgICAgICAgICAgICAgIHZhciBncm91cFNlcnZpY2UgPSBuZXcgR3JvdXBTZXJ2aWNlKG9wdHMpO1xuICAgICAgICAgICAgICAgIGdyb3VwU2VydmljZS5nZXRHcm91cHMoeyBhY2NvdW50OiBhZGFwdGVyT3B0aW9ucy5hY2NvdW50LCBwcm9qZWN0OiBwcm9qZWN0IH0pXG4gICAgICAgICAgICAgICAgICAgIC50aGVuKGZ1bmN0aW9uIChncm91cHMpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIEdyb3VwIEFQSSByZXR1cm5zIGlkIGluc3RlYWQgb2YgZ3JvdXBJZFxuICAgICAgICAgICAgICAgICAgICAgICAgZ3JvdXBzLmZvckVhY2goZnVuY3Rpb24gKGdyb3VwKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgZ3JvdXAuZ3JvdXBJZCA9IGdyb3VwLmlkO1xuICAgICAgICAgICAgICAgICAgICAgICAgfSk7XG5cbiAgICAgICAgICAgICAgICAgICAgICAgIGlmIChncm91cHMubGVuZ3RoKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgaGFuZGxlR3JvdXBMaXN0KGdyb3Vwcyk7XG4gICAgICAgICAgICAgICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vZWl0aGVyIGl0J3MgYSBwcml2YXRlIHByb2plY3Qgb3IgdGhlcmUgYXJlIG5vIGdyb3Vwc1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNlc3Npb25NYW5hZ2VyLnNhdmVTZXNzaW9uKHNlc3Npb25JbmZvKTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBvdXRTdWNjZXNzLmFwcGx5KHRoaXMsIFtkYXRhXSk7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgJGQucmVzb2x2ZShkYXRhKTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICByZXR1cm47XG4gICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgIH0sICRkLnJlamVjdCk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH07XG5cbiAgICAgICAgYWRhcHRlck9wdGlvbnMuc3VjY2VzcyA9IGhhbmRsZVN1Y2Nlc3M7XG4gICAgICAgIGFkYXB0ZXJPcHRpb25zLmVycm9yID0gZnVuY3Rpb24gKHJlc3BvbnNlKSB7XG4gICAgICAgICAgICBpZiAoYWRhcHRlck9wdGlvbnMuYWNjb3VudCkge1xuICAgICAgICAgICAgICAgIC8vIFRyeSB0byBsb2dpbiBhcyBhIHN5c3RlbSB1c2VyXG4gICAgICAgICAgICAgICAgYWRhcHRlck9wdGlvbnMuYWNjb3VudCA9IG51bGw7XG4gICAgICAgICAgICAgICAgYWRhcHRlck9wdGlvbnMuZXJyb3IgPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICAgICAgICAgIG91dEVycm9yLmFwcGx5KHRoaXMsIGFyZ3VtZW50cyk7XG4gICAgICAgICAgICAgICAgICAgICRkLnJlamVjdChyZXNwb25zZSk7XG4gICAgICAgICAgICAgICAgfTtcblxuICAgICAgICAgICAgICAgIG1lLmF1dGhBZGFwdGVyLmxvZ2luKGFkYXB0ZXJPcHRpb25zKTtcbiAgICAgICAgICAgICAgICByZXR1cm47XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIG91dEVycm9yLmFwcGx5KHRoaXMsIGFyZ3VtZW50cyk7XG4gICAgICAgICAgICAkZC5yZWplY3QocmVzcG9uc2UpO1xuICAgICAgICB9O1xuXG4gICAgICAgIHRoaXMuYXV0aEFkYXB0ZXIubG9naW4oYWRhcHRlck9wdGlvbnMpO1xuICAgICAgICByZXR1cm4gJGQucHJvbWlzZSgpO1xuICAgIH0sXG5cbiAgICAvKipcbiAgICAqIExvZ3MgdXNlciBvdXQgYnkgY2xlYXJpbmcgYWxsIHNlc3Npb24gaW5mb3JtYXRpb24uXG4gICAgKlxuICAgICogKipFeGFtcGxlKipcbiAgICAqXG4gICAgKiAgICAgICBhdXRoTWdyLmxvZ291dCgpO1xuICAgICpcbiAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgKlxuICAgICogQHBhcmFtIHtPYmplY3R9IG9wdGlvbnMgKE9wdGlvbmFsKSBPdmVycmlkZXMgZm9yIGNvbmZpZ3VyYXRpb24gb3B0aW9ucy5cbiAgICAqIEByZXR1cm4ge1Byb21pc2V9XG4gICAgKi9cbiAgICBsb2dvdXQ6IGZ1bmN0aW9uIChvcHRpb25zKSB7XG4gICAgICAgIHZhciBtZSA9IHRoaXM7XG4gICAgICAgIHZhciBhZGFwdGVyT3B0aW9ucyA9IHRoaXMuc2Vzc2lvbk1hbmFnZXIuZ2V0TWVyZ2VkT3B0aW9ucyhvcHRpb25zKTtcblxuICAgICAgICB2YXIgcmVtb3ZlQ29va2llRm4gPSBmdW5jdGlvbiAocmVzcG9uc2UpIHtcbiAgICAgICAgICAgIG1lLnNlc3Npb25NYW5hZ2VyLnJlbW92ZVNlc3Npb24oKTtcbiAgICAgICAgfTtcblxuICAgICAgICByZXR1cm4gdGhpcy5hdXRoQWRhcHRlci5sb2dvdXQoYWRhcHRlck9wdGlvbnMpLnRoZW4ocmVtb3ZlQ29va2llRm4pO1xuICAgIH0sXG5cbiAgICAvKipcbiAgICAgKiBSZXR1cm5zIHRoZSBleGlzdGluZyB1c2VyIGFjY2VzcyB0b2tlbiBpZiB0aGUgdXNlciBpcyBhbHJlYWR5IGxvZ2dlZCBpbi4gT3RoZXJ3aXNlLCBsb2dzIHRoZSB1c2VyIGluLCBjcmVhdGluZyBhIG5ldyB1c2VyIGFjY2VzcyB0b2tlbiwgYW5kIHJldHVybnMgdGhlIG5ldyB0b2tlbi4gKFNlZSBbbW9yZSBiYWNrZ3JvdW5kIG9uIGFjY2VzcyB0b2tlbnNdKC4uLy4uLy4uL3Byb2plY3RfYWNjZXNzLykpLlxuICAgICAqXG4gICAgICogKipFeGFtcGxlKipcbiAgICAgKlxuICAgICAqICAgICAgYXV0aE1nci5nZXRUb2tlbigpXG4gICAgICogICAgICAgICAgLnRoZW4oZnVuY3Rpb24gKHRva2VuKSB7XG4gICAgICogICAgICAgICAgICAgIGNvbnNvbGUubG9nKCdNeSB0b2tlbiBpcyAnLCB0b2tlbik7XG4gICAgICogICAgICAgICAgfSk7XG4gICAgICpcbiAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAqIEBwYXJhbSB7T2JqZWN0fSBvcHRpb25zIChPcHRpb25hbCkgT3ZlcnJpZGVzIGZvciBjb25maWd1cmF0aW9uIG9wdGlvbnMuXG4gICAgICogQHJldHVybiB7UHJvbWlzZX1cbiAgICAgKi9cbiAgICBnZXRUb2tlbjogZnVuY3Rpb24gKG9wdGlvbnMpIHtcbiAgICAgICAgdmFyIGh0dHBPcHRpb25zID0gdGhpcy5zZXNzaW9uTWFuYWdlci5nZXRNZXJnZWRPcHRpb25zKG9wdGlvbnMpO1xuXG4gICAgICAgIHZhciBzZXNzaW9uID0gdGhpcy5zZXNzaW9uTWFuYWdlci5nZXRTZXNzaW9uKGh0dHBPcHRpb25zKTtcbiAgICAgICAgdmFyICRkID0gJC5EZWZlcnJlZCgpO1xuICAgICAgICBpZiAoc2Vzc2lvbi5hdXRoX3Rva2VuKSB7XG4gICAgICAgICAgICAkZC5yZXNvbHZlKHNlc3Npb24uYXV0aF90b2tlbik7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICB0aGlzLmxvZ2luKGh0dHBPcHRpb25zKS50aGVuKCRkLnJlc29sdmUpO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiAkZC5wcm9taXNlKCk7XG4gICAgfSxcblxuICAgIC8qKlxuICAgICAqIFJldHVybnMgYW4gYXJyYXkgb2YgZ3JvdXAgcmVjb3Jkcywgb25lIGZvciBlYWNoIGdyb3VwIG9mIHdoaWNoIHRoZSBjdXJyZW50IHVzZXIgaXMgYSBtZW1iZXIuIEVhY2ggZ3JvdXAgcmVjb3JkIGluY2x1ZGVzIHRoZSBncm91cCBgbmFtZWAsIGBhY2NvdW50YCwgYHByb2plY3RgLCBhbmQgYGdyb3VwSWRgLlxuICAgICAqXG4gICAgICogSWYgc29tZSBlbmQgdXNlcnMgaW4geW91ciBwcm9qZWN0IGFyZSBtZW1iZXJzIG9mIG11bHRpcGxlIGdyb3VwcywgdGhpcyBpcyBhIHVzZWZ1bCBtZXRob2QgdG8gY2FsbCBvbiB5b3VyIHByb2plY3QncyBsb2dpbiBwYWdlLiBXaGVuIHRoZSB1c2VyIGF0dGVtcHRzIHRvIGxvZyBpbiwgeW91IGNhbiB1c2UgdGhpcyB0byBkaXNwbGF5IHRoZSBncm91cHMgb2Ygd2hpY2ggdGhlIHVzZXIgaXMgbWVtYmVyLCBhbmQgaGF2ZSB0aGUgdXNlciBzZWxlY3QgdGhlIGNvcnJlY3QgZ3JvdXAgdG8gbG9nIGluIHRvIGZvciB0aGlzIHNlc3Npb24uXG4gICAgICpcbiAgICAgKiAqKkV4YW1wbGUqKlxuICAgICAqXG4gICAgICogICAgICAvLyBnZXQgZ3JvdXBzIGZvciBjdXJyZW50IHVzZXJcbiAgICAgKiAgICAgIHZhciBzZXNzaW9uT2JqID0gYXV0aE1nci5nZXRDdXJyZW50VXNlclNlc3Npb25JbmZvKCk7XG4gICAgICogICAgICBhdXRoTWdyLmdldFVzZXJHcm91cHMoeyB1c2VySWQ6IHNlc3Npb25PYmoudXNlcklkLCB0b2tlbjogc2Vzc2lvbk9iai5hdXRoX3Rva2VuIH0pXG4gICAgICogICAgICAgICAgLnRoZW4oZnVuY3Rpb24gKGdyb3Vwcykge1xuICAgICAqICAgICAgICAgICAgICBmb3IgKHZhciBpPTA7IGkgPCBncm91cHMubGVuZ3RoOyBpKyspXG4gICAgICogICAgICAgICAgICAgICAgICB7IGNvbnNvbGUubG9nKGdyb3Vwc1tpXS5uYW1lKTsgfVxuICAgICAqICAgICAgICAgIH0pO1xuICAgICAqXG4gICAgICogICAgICAvLyBnZXQgZ3JvdXBzIGZvciBwYXJ0aWN1bGFyIHVzZXJcbiAgICAgKiAgICAgIGF1dGhNZ3IuZ2V0VXNlckdyb3Vwcyh7dXNlcklkOiAnYjFjMTlkZGEtMmQyZS00Nzc3LWFkNWQtMzkyOWYxN2U4NmQzJywgdG9rZW46IHNhdmVkUHJvakFjY2Vzc1Rva2VuIH0pO1xuICAgICAqXG4gICAgICogKipQYXJhbWV0ZXJzKipcbiAgICAgKiBAcGFyYW0ge09iamVjdH0gcGFyYW1zIE9iamVjdCB3aXRoIGEgdXNlcklkIGFuZCB0b2tlbiBwcm9wZXJ0aWVzLlxuICAgICAqIEBwYXJhbSB7U3RyaW5nfSBwYXJhbXMudXNlcklkIFRoZSB1c2VySWQuIElmIGxvb2tpbmcgdXAgZ3JvdXBzIGZvciB0aGUgY3VycmVudGx5IGxvZ2dlZCBpbiB1c2VyLCB0aGlzIGlzIGluIHRoZSBzZXNzaW9uIGluZm9ybWF0aW9uLiBPdGhlcndpc2UsIHBhc3MgYSBzdHJpbmcuXG4gICAgICogQHBhcmFtIHtTdHJpbmd9IHBhcmFtcy50b2tlbiBUaGUgYXV0aG9yaXphdGlvbiBjcmVkZW50aWFscyAoYWNjZXNzIHRva2VuKSB0byB1c2UgZm9yIGNoZWNraW5nIHRoZSBncm91cHMgZm9yIHRoaXMgdXNlci4gSWYgbG9va2luZyB1cCBncm91cHMgZm9yIHRoZSBjdXJyZW50bHkgbG9nZ2VkIGluIHVzZXIsIHRoaXMgaXMgaW4gdGhlIHNlc3Npb24gaW5mb3JtYXRpb24uIEEgdGVhbSBtZW1iZXIncyB0b2tlbiBvciBhIHByb2plY3QgYWNjZXNzIHRva2VuIGNhbiBhY2Nlc3MgYWxsIHRoZSBncm91cHMgZm9yIGFsbCBlbmQgdXNlcnMgaW4gdGhlIHRlYW0gb3IgcHJvamVjdC5cbiAgICAgKiBAcGFyYW0ge09iamVjdH0gb3B0aW9ucyAoT3B0aW9uYWwpIE92ZXJyaWRlcyBmb3IgY29uZmlndXJhdGlvbiBvcHRpb25zLlxuICAgICAqIEByZXR1cm4ge1Byb21pc2V9XG4gICAgICovXG4gICAgZ2V0VXNlckdyb3VwczogZnVuY3Rpb24gKHBhcmFtcywgb3B0aW9ucykge1xuICAgICAgICB2YXIgYWRhcHRlck9wdGlvbnMgPSB0aGlzLnNlc3Npb25NYW5hZ2VyLmdldE1lcmdlZE9wdGlvbnMoeyBzdWNjZXNzOiAkLm5vb3AgfSwgb3B0aW9ucyk7XG4gICAgICAgIHZhciAkZCA9ICQuRGVmZXJyZWQoKTtcbiAgICAgICAgdmFyIG91dFN1Y2Nlc3MgPSBhZGFwdGVyT3B0aW9ucy5zdWNjZXNzO1xuXG4gICAgICAgIGFkYXB0ZXJPcHRpb25zLnN1Y2Nlc3MgPSBmdW5jdGlvbiAobWVtYmVySW5mbykge1xuICAgICAgICAgICAgLy8gVGhlIG1lbWJlciBBUEkgaXMgYXQgdGhlIGFjY291bnQgc2NvcGUsIHdlIGZpbHRlciBieSBwcm9qZWN0XG4gICAgICAgICAgICBpZiAoYWRhcHRlck9wdGlvbnMucHJvamVjdCkge1xuICAgICAgICAgICAgICAgIG1lbWJlckluZm8gPSAkLmdyZXAobWVtYmVySW5mbywgZnVuY3Rpb24gKGdyb3VwKSB7XG4gICAgICAgICAgICAgICAgICAgIHJldHVybiBncm91cC5wcm9qZWN0ID09PSBhZGFwdGVyT3B0aW9ucy5wcm9qZWN0O1xuICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICBvdXRTdWNjZXNzLmFwcGx5KHRoaXMsIFttZW1iZXJJbmZvXSk7XG4gICAgICAgICAgICAkZC5yZXNvbHZlKG1lbWJlckluZm8pO1xuICAgICAgICB9O1xuXG4gICAgICAgIHZhciBtZW1iZXJBZGFwdGVyID0gbmV3IE1lbWJlckFkYXB0ZXIoeyB0b2tlbjogcGFyYW1zLnRva2VuLCBzZXJ2ZXI6IGFkYXB0ZXJPcHRpb25zLnNlcnZlciB9KTtcbiAgICAgICAgbWVtYmVyQWRhcHRlci5nZXRHcm91cHNGb3JVc2VyKHBhcmFtcywgYWRhcHRlck9wdGlvbnMpLmZhaWwoJGQucmVqZWN0KTtcbiAgICAgICAgcmV0dXJuICRkLnByb21pc2UoKTtcbiAgICB9LFxuXG4gICAgLyoqXG4gICAgICogSGVscGVyIG1ldGhvZCB0byBjaGVjayBpZiB5b3UncmUgY3VycmVudGx5IGxvZ2dlZCBpblxuICAgICAqXG4gICAgICogICoqRXhhbXBsZSoqXG4gICAgICogIFxuICAgICAqICAgICAgdmFyIGFtSUxvZ2dlZEluID0gYXV0aE1nci5pc0xvZ2dlZEluKCk7XG4gICAgICpcbiAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAqIEBwYXJhbSB7bm9uZX0gbm9uZVxuICAgICAqIEByZXR1cm4ge0Jvb2xlYW59IHRydWUgaWYgeW91J3JlIGxvZ2dlZCBpblxuICAgICAqL1xuICAgIGlzTG9nZ2VkSW46IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgdmFyIHNlc3Npb24gPSB0aGlzLmdldEN1cnJlbnRVc2VyU2Vzc2lvbkluZm8oKTtcbiAgICAgICAgcmV0dXJuICEhKHNlc3Npb24gJiYgc2Vzc2lvbi51c2VySWQpO1xuICAgIH0sXG5cbiAgICAvKipcbiAgICAgKiBSZXR1cm5zIHNlc3Npb24gaW5mb3JtYXRpb24gZm9yIHRoZSBjdXJyZW50IHVzZXIsIGluY2x1ZGluZyB0aGUgYHVzZXJJZGAsIGBhY2NvdW50YCwgYHByb2plY3RgLCBgZ3JvdXBJZGAsIGBncm91cE5hbWVgLCBgaXNGYWNgICh3aGV0aGVyIHRoZSBlbmQgdXNlciBpcyBhIGZhY2lsaXRhdG9yIG9mIHRoaXMgZ3JvdXApLCBhbmQgYGF1dGhfdG9rZW5gICh1c2VyIGFjY2VzcyB0b2tlbikuXG4gICAgICpcbiAgICAgKiAqSW1wb3J0YW50KjogVGhpcyBtZXRob2QgaXMgc3luY2hyb25vdXMuIFRoZSBzZXNzaW9uIGluZm9ybWF0aW9uIGlzIHJldHVybmVkIGltbWVkaWF0ZWx5IGluIGFuIG9iamVjdDsgbm8gY2FsbGJhY2tzIG9yIHByb21pc2VzIGFyZSBuZWVkZWQuXG4gICAgICpcbiAgICAgKiBTZXNzaW9uIGluZm9ybWF0aW9uIGlzIHN0b3JlZCBpbiBhIGNvb2tpZSBpbiB0aGUgYnJvd3Nlci5cbiAgICAgKlxuICAgICAqICoqRXhhbXBsZSoqXG4gICAgICpcbiAgICAgKiAgICAgIHZhciBzZXNzaW9uT2JqID0gYXV0aE1nci5nZXRDdXJyZW50VXNlclNlc3Npb25JbmZvKCk7XG4gICAgICpcbiAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAqIEBwYXJhbSB7T2JqZWN0fSBvcHRpb25zIChPcHRpb25hbCkgT3ZlcnJpZGVzIGZvciBjb25maWd1cmF0aW9uIG9wdGlvbnMuXG4gICAgICogQHJldHVybiB7T2JqZWN0fSBzZXNzaW9uIGluZm9ybWF0aW9uXG4gICAgICovXG4gICAgZ2V0Q3VycmVudFVzZXJTZXNzaW9uSW5mbzogZnVuY3Rpb24gKG9wdGlvbnMpIHtcbiAgICAgICAgdmFyIGFkYXB0ZXJPcHRpb25zID0gdGhpcy5zZXNzaW9uTWFuYWdlci5nZXRNZXJnZWRPcHRpb25zKHsgc3VjY2VzczogJC5ub29wIH0sIG9wdGlvbnMpO1xuICAgICAgICByZXR1cm4gdGhpcy5zZXNzaW9uTWFuYWdlci5nZXRTZXNzaW9uKGFkYXB0ZXJPcHRpb25zKTtcbiAgICB9LFxuXG4gICAgLypcbiAgICAgKiBBZGRzIG9uZSBvciBtb3JlIGdyb3VwcyB0byB0aGUgY3VycmVudCBzZXNzaW9uLiBcbiAgICAgKlxuICAgICAqIFRoaXMgbWV0aG9kIGFzc3VtZXMgdGhhdCB0aGUgcHJvamVjdCBhbmQgZ3JvdXAgZXhpc3QgYW5kIHRoZSB1c2VyIHNwZWNpZmllZCBpbiB0aGUgc2Vzc2lvbiBpcyBwYXJ0IG9mIHRoaXMgcHJvamVjdCBhbmQgZ3JvdXAuXG4gICAgICpcbiAgICAgKiBSZXR1cm5zIHRoZSBuZXcgc2Vzc2lvbiBvYmplY3QuXG4gICAgICpcbiAgICAgKiAqKkV4YW1wbGUqKlxuICAgICAqXG4gICAgICogICAgICBhdXRoTWdyLmFkZEdyb3Vwcyh7IHByb2plY3Q6ICdoZWxsby13b3JsZCcsIGdyb3VwTmFtZTogJ2dyb3VwTmFtZScsIGdyb3VwSWQ6ICdncm91cElkJyB9KTtcbiAgICAgKiAgICAgIGF1dGhNZ3IuYWRkR3JvdXBzKFt7IHByb2plY3Q6ICdoZWxsby13b3JsZCcsIGdyb3VwTmFtZTogJ2dyb3VwTmFtZScsIGdyb3VwSWQ6ICdncm91cElkJyB9LCB7IHByb2plY3Q6ICdoZWxsby13b3JsZCcsIGdyb3VwTmFtZTogJy4uLicgfV0pO1xuICAgICAqXG4gICAgICogKipQYXJhbWV0ZXJzKipcbiAgICAgKiBAcGFyYW0ge29iamVjdHxhcnJheX0gZ3JvdXBzIChSZXF1aXJlZCkgVGhlIGdyb3VwIG9iamVjdCBtdXN0IGNvbnRhaW4gdGhlIGBwcm9qZWN0YCAoKipQcm9qZWN0IElEKiopIGFuZCBgZ3JvdXBOYW1lYCBwcm9wZXJ0aWVzLiBJZiBwYXNzaW5nIGFuIGFycmF5IG9mIHN1Y2ggb2JqZWN0cywgYWxsIG9mIHRoZSBvYmplY3RzIG11c3QgY29udGFpbiAqZGlmZmVyZW50KiBgcHJvamVjdGAgKCoqUHJvamVjdCBJRCoqKSB2YWx1ZXM6IGFsdGhvdWdoIGVuZCB1c2VycyBtYXkgYmUgbG9nZ2VkIGluIHRvIG11bHRpcGxlIHByb2plY3RzIGF0IG9uY2UsIHRoZXkgbWF5IG9ubHkgYmUgbG9nZ2VkIGluIHRvIG9uZSBncm91cCBwZXIgcHJvamVjdCBhdCBhIHRpbWUuXG4gICAgICogQHBhcmFtIHtzdHJpbmd9IGdyb3VwLmlzRmFjIChvcHRpb25hbCkgRGVmYXVsdHMgdG8gYGZhbHNlYC4gU2V0IHRvIGB0cnVlYCBpZiB0aGUgdXNlciBpbiB0aGUgc2Vzc2lvbiBzaG91bGQgYmUgYSBmYWNpbGl0YXRvciBpbiB0aGlzIGdyb3VwLlxuICAgICAqIEBwYXJhbSB7c3RyaW5nfSBncm91cC5ncm91cElkIChvcHRpb25hbCkgRGVmYXVsdHMgdG8gdW5kZWZpbmVkLiBOZWVkZWQgbW9zdGx5IGZvciB0aGUgTWVtYmVycyBBUEkuXG4gICAgICogQHJldHVybiB7T2JqZWN0fSBzZXNzaW9uIGluZm9ybWF0aW9uXG4gICAgKi9cbiAgICBhZGRHcm91cHM6IGZ1bmN0aW9uIChncm91cHMpIHtcbiAgICAgICAgdmFyIHNlc3Npb24gPSB0aGlzLmdldEN1cnJlbnRVc2VyU2Vzc2lvbkluZm8oKTtcbiAgICAgICAgdmFyIGlzQXJyYXkgPSBBcnJheS5pc0FycmF5KGdyb3Vwcyk7XG4gICAgICAgIGdyb3VwcyA9IGlzQXJyYXkgPyBncm91cHMgOiBbZ3JvdXBzXTtcblxuICAgICAgICAkLmVhY2goZ3JvdXBzLCBmdW5jdGlvbiAoaW5kZXgsIGdyb3VwKSB7XG4gICAgICAgICAgICB2YXIgZXh0ZW5kZWRHcm91cCA9ICQuZXh0ZW5kKHt9LCB7IGlzRmFjOiBmYWxzZSB9LCBncm91cCk7XG4gICAgICAgICAgICB2YXIgcHJvamVjdCA9IGV4dGVuZGVkR3JvdXAucHJvamVjdDtcbiAgICAgICAgICAgIHZhciB2YWxpZFByb3BzID0gWydncm91cE5hbWUnLCAnZ3JvdXBJZCcsICdpc0ZhYyddO1xuICAgICAgICAgICAgaWYgKCFwcm9qZWN0IHx8ICFleHRlbmRlZEdyb3VwLmdyb3VwTmFtZSkge1xuICAgICAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcignTm8gcHJvamVjdCBvciBncm91cE5hbWUgc3BlY2lmaWVkLicpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgLy8gZmlsdGVyIG9iamVjdFxuICAgICAgICAgICAgZXh0ZW5kZWRHcm91cCA9IF9waWNrKGV4dGVuZGVkR3JvdXAsIHZhbGlkUHJvcHMpO1xuICAgICAgICAgICAgc2Vzc2lvbi5ncm91cHNbcHJvamVjdF0gPSBleHRlbmRlZEdyb3VwO1xuICAgICAgICB9KTtcbiAgICAgICAgdGhpcy5zZXNzaW9uTWFuYWdlci5zYXZlU2Vzc2lvbihzZXNzaW9uKTtcbiAgICAgICAgcmV0dXJuIHNlc3Npb247XG4gICAgfVxufSk7XG5cbm1vZHVsZS5leHBvcnRzID0gQXV0aE1hbmFnZXI7XG4iLCIndXNlIHN0cmljdCc7XG5cbi8qKlxuICogIyMgQ2hhbm5lbCBNYW5hZ2VyXG4gKlxuICogVGhlcmUgYXJlIHR3byBtYWluIHVzZSBjYXNlcyBmb3IgdGhlIGNoYW5uZWw6IGV2ZW50IG5vdGlmaWNhdGlvbnMgYW5kIGNoYXQgbWVzc2FnZXMuXG4gKlxuICogSWYgeW91IGFyZSBkZXZlbG9waW5nIHdpdGggRXBpY2VudGVyLmpzLCB5b3Ugc2hvdWxkIHVzZSB0aGUgW0VwaWNlbnRlciBDaGFubmVsIE1hbmFnZXJdKC4uL2VwaWNlbnRlci1jaGFubmVsLW1hbmFnZXIvKSByYXRoZXIgdGhhbiB0aGlzIG1vcmUgZ2VuZXJpYyBDaGFubmVsIE1hbmFnZXIuIChUaGUgRXBpY2VudGVyIENoYW5uZWwgTWFuYWdlciBpcyBhIHdyYXBwZXIgdGhhdCBpbnN0YW50aWF0ZXMgYSBDaGFubmVsIE1hbmFnZXIgd2l0aCBFcGljZW50ZXItc3BlY2lmaWMgZGVmYXVsdHMuKSBUaGUgRXBpY2VudGVyIENoYW5uZWwgTWFuYWdlciBkb2N1bWVudGF0aW9uIGFsc28gaGFzIG1vcmUgW2JhY2tncm91bmRdKC4uL2VwaWNlbnRlci1jaGFubmVsLW1hbmFnZXIvI2JhY2tncm91bmQpIGluZm9ybWF0aW9uIG9uIGNoYW5uZWxzIGFuZCB0aGVpciB1c2UuIFxuICpcbiAqIEhvd2V2ZXIsIHlvdSBjYW4gd29yayBkaXJlY3RseSB3aXRoIHRoZSBDaGFubmVsIE1hbmFnZXIgaWYgeW91IGxpa2UuIChUaGlzIG1pZ2h0IGJlIHVzZWZ1bCBpZiB5b3UgYXJlIHdvcmtpbmcgdGhyb3VnaCBOb2RlLmpzLCBmb3IgZXhhbXBsZSwgYHJlcXVpcmUoJ21hbmFnZXIvY2hhbm5lbC1tYW5hZ2VyJylgLilcbiAqXG4gKiBUaGUgQ2hhbm5lbCBNYW5hZ2VyIGlzIGEgd3JhcHBlciBhcm91bmQgdGhlIGRlZmF1bHQgW2NvbWV0ZCBKYXZhU2NyaXB0IGxpYnJhcnldKGh0dHA6Ly9kb2NzLmNvbWV0ZC5vcmcvMi9yZWZlcmVuY2UvamF2YXNjcmlwdC5odG1sKSwgYCQuY29tZXRkYC4gSXQgcHJvdmlkZXMgYSBmZXcgbmljZSBmZWF0dXJlcyB0aGF0IGAkLmNvbWV0ZGAgZG9lc24ndCwgaW5jbHVkaW5nOlxuICpcbiAqICogQXV0b21hdGljIHJlLXN1YnNjcmlwdGlvbiB0byBjaGFubmVscyBpZiB5b3UgbG9zZSB5b3VyIGNvbm5lY3Rpb25cbiAqICogT25saW5lIC8gT2ZmbGluZSBub3RpZmljYXRpb25zXG4gKiAqICdFdmVudHMnIGZvciBjb21ldGQgbm90aWZpY2F0aW9ucyAoaW5zdGVhZCBvZiBoYXZpbmcgdG8gbGlzdGVuIG9uIHNwZWNpZmljIG1ldGEgY2hhbm5lbHMpXG4gKlxuICogWW91J2xsIG5lZWQgdG8gaW5jbHVkZSB0aGUgYGVwaWNlbnRlci1tdWx0aXBsYXllci1kZXBlbmRlbmNpZXMuanNgIGxpYnJhcnkgaW4gYWRkaXRpb24gdG8gdGhlIGBlcGljZW50ZXIuanNgIGxpYnJhcnkgaW4geW91ciBwcm9qZWN0IHRvIHVzZSB0aGUgQ2hhbm5lbCBNYW5hZ2VyLiAoU2VlIFtJbmNsdWRpbmcgRXBpY2VudGVyLmpzXSguLi8uLi8jaW5jbHVkZSkuKVxuICpcbiAqIFRvIHVzZSB0aGUgQ2hhbm5lbCBNYW5hZ2VyIGluIGNsaWVudC1zaWRlIEphdmFTY3JpcHQsIGluc3RhbnRpYXRlIHRoZSBbRXBpY2VudGVyIENoYW5uZWwgTWFuYWdlcl0oLi4vZXBpY2VudGVyLWNoYW5uZWwtbWFuYWdlci8pLCBnZXQgYSBwYXJ0aWN1bGFyIGNoYW5uZWwgLS0gdGhhdCBpcywgYW4gaW5zdGFuY2Ugb2YgYSBbQ2hhbm5lbCBTZXJ2aWNlXSguLi9jaGFubmVsLXNlcnZpY2UvKSAtLSB0aGVuIHVzZSB0aGUgY2hhbm5lbCdzIGBzdWJzY3JpYmUoKWAgYW5kIGBwdWJsaXNoKClgIG1ldGhvZHMgdG8gc3Vic2NyaWJlIHRvIHRvcGljcyBvciBwdWJsaXNoIGRhdGEgdG8gdG9waWNzLlxuICpcbiAqICAgICAgdmFyIGNtID0gbmV3IEYubWFuYWdlci5DaGFubmVsTWFuYWdlcigpO1xuICogICAgICB2YXIgZ2MgPSBjbS5nZXRHcm91cENoYW5uZWwoKTtcbiAqICAgICAgLy8gYmVjYXVzZSB3ZSB1c2VkIGFuIEVwaWNlbnRlciBDaGFubmVsIE1hbmFnZXIgdG8gZ2V0IHRoZSBncm91cCBjaGFubmVsLFxuICogICAgICAvLyBzdWJzY3JpYmUoKSBhbmQgcHVibGlzaCgpIGhlcmUgZGVmYXVsdCB0byB0aGUgYmFzZSB0b3BpYyBmb3IgdGhlIGdyb3VwO1xuICogICAgICBnYy5zdWJzY3JpYmUoJycsIGZ1bmN0aW9uKGRhdGEpIHsgY29uc29sZS5sb2coZGF0YSk7IH0pO1xuICogICAgICBnYy5wdWJsaXNoKCcnLCB7IG1lc3NhZ2U6ICdhIG5ldyBtZXNzYWdlIHRvIHRoZSBncm91cCcgfSk7XG4gKlxuICogVGhlIHBhcmFtZXRlcnMgZm9yIGluc3RhbnRpYXRpbmcgYSBDaGFubmVsIE1hbmFnZXIgaW5jbHVkZTpcbiAqXG4gKiAqIGBvcHRpb25zYCBUaGUgb3B0aW9ucyBvYmplY3QgdG8gY29uZmlndXJlIHRoZSBDaGFubmVsIE1hbmFnZXIuIEJlc2lkZXMgdGhlIGNvbW1vbiBvcHRpb25zIGxpc3RlZCBoZXJlLCBzZWUgaHR0cDovL2RvY3MuY29tZXRkLm9yZy9yZWZlcmVuY2UvamF2YXNjcmlwdC5odG1sIGZvciBvdGhlciBzdXBwb3J0ZWQgb3B0aW9ucy5cbiAqICogYG9wdGlvbnMudXJsYCBUaGUgQ29tZXRkIGVuZHBvaW50IFVSTC5cbiAqICogYG9wdGlvbnMud2Vic29ja2V0RW5hYmxlZGAgV2hldGhlciB3ZWJzb2NrZXQgc3VwcG9ydCBpcyBhY3RpdmUgKGJvb2xlYW4pLlxuICogKiBgb3B0aW9ucy5jaGFubmVsYCBPdGhlciBkZWZhdWx0cyB0byBwYXNzIG9uIHRvIGluc3RhbmNlcyBvZiB0aGUgdW5kZXJseWluZyBDaGFubmVsIFNlcnZpY2UuIFNlZSBbQ2hhbm5lbCBTZXJ2aWNlXSguLi9jaGFubmVsLXNlcnZpY2UvKSBmb3IgZGV0YWlscy5cbiAqXG4gKi9cblxudmFyIENoYW5uZWwgPSByZXF1aXJlKCcuLi9zZXJ2aWNlL2NoYW5uZWwtc2VydmljZScpO1xudmFyIFNlc3Npb25NYW5hZ2VyID0gcmVxdWlyZSgnLi4vc3RvcmUvc2Vzc2lvbi1tYW5hZ2VyJyk7XG5cbnZhciBDaGFubmVsTWFuYWdlciA9IGZ1bmN0aW9uIChvcHRpb25zKSB7XG4gICAgaWYgKCEkLmNvbWV0ZCkge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ0NvbWV0ZCBsaWJyYXJ5IG5vdCBmb3VuZC4gUGxlYXNlIGluY2x1ZGUgZXBpY2VudGVyLW11bHRpcGxheWVyLWRlcGVuZGVuY2llcy5qcycpO1xuICAgIH1cbiAgICBpZiAoIW9wdGlvbnMgfHwgIW9wdGlvbnMudXJsKSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcignUGxlYXNlIHByb3ZpZGUgYW4gdXJsIGZvciB0aGUgY29tZXRkIHNlcnZlcicpO1xuICAgIH1cblxuICAgIHZhciBkZWZhdWx0cyA9IHtcbiAgICAgICAgLyoqXG4gICAgICAgICAqIFRoZSBDb21ldGQgZW5kcG9pbnQgVVJMLlxuICAgICAgICAgKiBAdHlwZSB7c3RyaW5nfVxuICAgICAgICAgKi9cbiAgICAgICAgdXJsOiAnJyxcblxuICAgICAgICAvKipcbiAgICAgICAgICogVGhlIGxvZyBsZXZlbCBmb3IgdGhlIGNoYW5uZWwgKGxvZ3MgdG8gY29uc29sZSkuXG4gICAgICAgICAqIEB0eXBlIHtzdHJpbmd9XG4gICAgICAgICAqL1xuICAgICAgICBsb2dMZXZlbDogJ2luZm8nLFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBXaGV0aGVyIHdlYnNvY2tldCBzdXBwb3J0IGlzIGFjdGl2ZS4gRGVmYXVsdHMgdG8gYHRydWVgLlxuICAgICAgICAgKiBAdHlwZSB7Ym9vbGVhbn1cbiAgICAgICAgICovXG4gICAgICAgIHdlYnNvY2tldEVuYWJsZWQ6IHRydWUsXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIFdoZXRoZXIgdGhlIEFDSyBleHRlbnNpb24gaXMgZW5hYmxlZC4gRGVmYXVsdHMgdG8gYHRydWVgLiBTZWUgW2h0dHBzOi8vZG9jcy5jb21ldGQub3JnL2N1cnJlbnQvcmVmZXJlbmNlLyNfZXh0ZW5zaW9uc19hY2tub3dsZWRnZV0oaHR0cHM6Ly9kb2NzLmNvbWV0ZC5vcmcvY3VycmVudC9yZWZlcmVuY2UvI19leHRlbnNpb25zX2Fja25vd2xlZGdlKSBmb3IgbW9yZSBpbmZvLlxuICAgICAgICAgKiBAdHlwZSB7Ym9vbGVhbn1cbiAgICAgICAgICovXG4gICAgICAgIGFja0VuYWJsZWQ6IHRydWUsXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIElmIGZhbHNlIGVhY2ggaW5zdGFuY2Ugb2YgQ2hhbm5lbCB3aWxsIGhhdmUgYSBzZXBhcmF0ZSBjb21ldGQgY29ubmVjdGlvbiB0byBzZXJ2ZXIsIHdoaWNoIGNvdWxkIGJlIG5vaXN5LiBTZXQgdG8gdHJ1ZSB0byByZS11c2UgdGhlIHNhbWUgY29ubmVjdGlvbiBhY3Jvc3MgaW5zdGFuY2VzLlxuICAgICAgICAgKiBAdHlwZSB7Ym9vbGVhbn1cbiAgICAgICAgICovXG4gICAgICAgIHNoYXJlQ29ubmVjdGlvbjogZmFsc2UsXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIE90aGVyIGRlZmF1bHRzIHRvIHBhc3Mgb24gdG8gaW5zdGFuY2VzIG9mIHRoZSB1bmRlcmx5aW5nIFtDaGFubmVsIFNlcnZpY2VdKC4uL2NoYW5uZWwtc2VydmljZS8pLCB3aGljaCBhcmUgY3JlYXRlZCB0aHJvdWdoIGBnZXRDaGFubmVsKClgLlxuICAgICAgICAgKiBAdHlwZSB7b2JqZWN0fVxuICAgICAgICAgKi9cbiAgICAgICAgY2hhbm5lbDoge1xuXG4gICAgICAgIH0sXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIE9wdGlvbnMgdG8gcGFzcyB0byB0aGUgY2hhbm5lbCBoYW5kc2hha2UuXG4gICAgICAgICAqXG4gICAgICAgICAqIEZvciBleGFtcGxlLCB0aGUgW0VwaWNlbnRlciBDaGFubmVsIE1hbmFnZXJdKC4uL2VwaWNlbnRlci1jaGFubmVsLW1hbmFnZXIvKSBwYXNzZXMgYGV4dGAgYW5kIGF1dGhvcml6YXRpb24gaW5mb3JtYXRpb24uIE1vcmUgaW5mb3JtYXRpb24gb24gcG9zc2libGUgb3B0aW9ucyBpcyBpbiB0aGUgZGV0YWlscyBvZiB0aGUgdW5kZXJseWluZyBbUHVzaCBDaGFubmVsIEFQSV0oLi4vLi4vLi4vcmVzdF9hcGlzL211bHRpcGxheWVyL2NoYW5uZWwvKS5cbiAgICAgICAgICpcbiAgICAgICAgICogQHR5cGUge29iamVjdH1cbiAgICAgICAgICovXG4gICAgICAgIGhhbmRzaGFrZTogdW5kZWZpbmVkXG4gICAgfTtcbiAgICB0aGlzLnNlc3Npb25NYW5hZ2VyID0gbmV3IFNlc3Npb25NYW5hZ2VyKCk7XG4gICAgdmFyIGRlZmF1bHRDb21ldE9wdGlvbnMgPSB0aGlzLnNlc3Npb25NYW5hZ2VyLmdldE1lcmdlZE9wdGlvbnMoZGVmYXVsdHMsIG9wdGlvbnMpO1xuICAgIHRoaXMuY3VycmVudFN1YnNjcmlwdGlvbnMgPSBbXTtcbiAgICB0aGlzLm9wdGlvbnMgPSBkZWZhdWx0Q29tZXRPcHRpb25zO1xuXG4gICAgaWYgKGRlZmF1bHRDb21ldE9wdGlvbnMuc2hhcmVDb25uZWN0aW9uICYmIENoYW5uZWxNYW5hZ2VyLnByb3RvdHlwZS5fY29tZXRkKSB7XG4gICAgICAgIHRoaXMuY29tZXRkID0gQ2hhbm5lbE1hbmFnZXIucHJvdG90eXBlLl9jb21ldGQ7XG4gICAgICAgIHJldHVybiB0aGlzO1xuICAgIH1cbiAgICB2YXIgY29tZXRkID0gbmV3ICQuQ29tZXREKCk7XG4gICAgQ2hhbm5lbE1hbmFnZXIucHJvdG90eXBlLl9jb21ldGQgPSBjb21ldGQ7XG5cbiAgICBjb21ldGQud2Vic29ja2V0RW5hYmxlZCA9IGRlZmF1bHRDb21ldE9wdGlvbnMud2Vic29ja2V0RW5hYmxlZDtcbiAgICBjb21ldGQuYWNrRW5hYmxlZCA9IGRlZmF1bHRDb21ldE9wdGlvbnMuYWNrRW5hYmxlZDtcblxuICAgIHRoaXMuaXNDb25uZWN0ZWQgPSBmYWxzZTtcbiAgICB2YXIgY29ubmVjdGlvbkJyb2tlbiA9IGZ1bmN0aW9uIChtZXNzYWdlKSB7XG4gICAgICAgICQodGhpcykudHJpZ2dlcignZGlzY29ubmVjdCcsIG1lc3NhZ2UpO1xuICAgIH07XG4gICAgdmFyIGNvbm5lY3Rpb25TdWNjZWVkZWQgPSBmdW5jdGlvbiAobWVzc2FnZSkge1xuICAgICAgICAkKHRoaXMpLnRyaWdnZXIoJ2Nvbm5lY3QnLCBtZXNzYWdlKTtcbiAgICB9O1xuICAgIHZhciBtZSA9IHRoaXM7XG5cbiAgICBjb21ldGQuY29uZmlndXJlKGRlZmF1bHRDb21ldE9wdGlvbnMpO1xuXG4gICAgY29tZXRkLmFkZExpc3RlbmVyKCcvbWV0YS9jb25uZWN0JywgZnVuY3Rpb24gKG1lc3NhZ2UpIHtcbiAgICAgICAgdmFyIHdhc0Nvbm5lY3RlZCA9IHRoaXMuaXNDb25uZWN0ZWQ7XG4gICAgICAgIHRoaXMuaXNDb25uZWN0ZWQgPSAobWVzc2FnZS5zdWNjZXNzZnVsID09PSB0cnVlKTtcbiAgICAgICAgaWYgKCF3YXNDb25uZWN0ZWQgJiYgdGhpcy5pc0Nvbm5lY3RlZCkgeyAvL0Nvbm5lY3RpbmcgZm9yIHRoZSBmaXJzdCB0aW1lXG4gICAgICAgICAgICBjb25uZWN0aW9uU3VjY2VlZGVkLmNhbGwodGhpcywgbWVzc2FnZSk7XG4gICAgICAgIH0gZWxzZSBpZiAod2FzQ29ubmVjdGVkICYmICF0aGlzLmlzQ29ubmVjdGVkKSB7IC8vT25seSB0aHJvdyBkaXNjb25uZWN0ZWQgbWVzc2FnZSBmcm8gdGhlIGZpcnN0IGRpc2Nvbm5lY3QsIG5vdCBvbmNlIHBlciB0cnlcbiAgICAgICAgICAgIGNvbm5lY3Rpb25Ccm9rZW4uY2FsbCh0aGlzLCBtZXNzYWdlKTtcbiAgICAgICAgfVxuICAgIH0uYmluZCh0aGlzKSk7XG5cbiAgICBjb21ldGQuYWRkTGlzdGVuZXIoJy9tZXRhL2Rpc2Nvbm5lY3QnLCBjb25uZWN0aW9uQnJva2VuKTtcblxuICAgIGNvbWV0ZC5hZGRMaXN0ZW5lcignL21ldGEvaGFuZHNoYWtlJywgZnVuY3Rpb24gKG1lc3NhZ2UpIHtcbiAgICAgICAgaWYgKG1lc3NhZ2Uuc3VjY2Vzc2Z1bCkge1xuICAgICAgICAgICAgLy9odHRwOi8vZG9jcy5jb21ldGQub3JnL3JlZmVyZW5jZS9qYXZhc2NyaXB0X3N1YnNjcmliZS5odG1sI2phdmFzY3JpcHRfc3Vic2NyaWJlX21ldGFfY2hhbm5lbHNcbiAgICAgICAgICAgIC8vIF4gXCJkeW5hbWljIHN1YnNjcmlwdGlvbnMgYXJlIGNsZWFyZWQgKGxpa2UgYW55IG90aGVyIHN1YnNjcmlwdGlvbikgYW5kIHRoZSBhcHBsaWNhdGlvbiBuZWVkcyB0byBmaWd1cmUgb3V0IHdoaWNoIGR5bmFtaWMgc3Vic2NyaXB0aW9uIG11c3QgYmUgcGVyZm9ybWVkIGFnYWluXCJcbiAgICAgICAgICAgIGNvbWV0ZC5iYXRjaChmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICAgICAgJChtZS5jdXJyZW50U3Vic2NyaXB0aW9ucykuZWFjaChmdW5jdGlvbiAoaW5kZXgsIHN1YnMpIHtcbiAgICAgICAgICAgICAgICAgICAgY29tZXRkLnJlc3Vic2NyaWJlKHN1YnMpO1xuICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgfSk7XG4gICAgICAgIH1cbiAgICB9KTtcblxuICAgIC8vT3RoZXIgaW50ZXJlc3RpbmcgZXZlbnRzIGZvciByZWZlcmVuY2VcbiAgICBjb21ldGQuYWRkTGlzdGVuZXIoJy9tZXRhL3N1YnNjcmliZScsIGZ1bmN0aW9uIChtZXNzYWdlKSB7XG4gICAgICAgICQobWUpLnRyaWdnZXIoJ3N1YnNjcmliZScsIG1lc3NhZ2UpO1xuICAgIH0pO1xuICAgIGNvbWV0ZC5hZGRMaXN0ZW5lcignL21ldGEvdW5zdWJzY3JpYmUnLCBmdW5jdGlvbiAobWVzc2FnZSkge1xuICAgICAgICAkKG1lKS50cmlnZ2VyKCd1bnN1YnNjcmliZScsIG1lc3NhZ2UpO1xuICAgIH0pO1xuICAgIGNvbWV0ZC5hZGRMaXN0ZW5lcignL21ldGEvcHVibGlzaCcsIGZ1bmN0aW9uIChtZXNzYWdlKSB7XG4gICAgICAgICQobWUpLnRyaWdnZXIoJ3B1Ymxpc2gnLCBtZXNzYWdlKTtcbiAgICB9KTtcbiAgICBjb21ldGQuYWRkTGlzdGVuZXIoJy9tZXRhL3Vuc3VjY2Vzc2Z1bCcsIGZ1bmN0aW9uIChtZXNzYWdlKSB7XG4gICAgICAgICQobWUpLnRyaWdnZXIoJ2Vycm9yJywgbWVzc2FnZSk7XG4gICAgfSk7XG5cbiAgICBjb21ldGQuaGFuZHNoYWtlKGRlZmF1bHRDb21ldE9wdGlvbnMuaGFuZHNoYWtlKTtcblxuICAgIHRoaXMuY29tZXRkID0gY29tZXRkO1xufTtcblxuXG5DaGFubmVsTWFuYWdlci5wcm90b3R5cGUgPSAkLmV4dGVuZChDaGFubmVsTWFuYWdlci5wcm90b3R5cGUsIHtcblxuICAgIC8qKlxuICAgICAqIENyZWF0ZXMgYW5kIHJldHVybnMgYSBjaGFubmVsLCB0aGF0IGlzLCBhbiBpbnN0YW5jZSBvZiBhIFtDaGFubmVsIFNlcnZpY2VdKC4uL2NoYW5uZWwtc2VydmljZS8pLlxuICAgICAqXG4gICAgICogKipFeGFtcGxlKipcbiAgICAgKlxuICAgICAqICAgICAgdmFyIGNtID0gbmV3IEYubWFuYWdlci5DaGFubmVsTWFuYWdlcigpO1xuICAgICAqICAgICAgdmFyIGNoYW5uZWwgPSBjbS5nZXRDaGFubmVsKCk7XG4gICAgICpcbiAgICAgKiAgICAgIGNoYW5uZWwuc3Vic2NyaWJlKCd0b3BpYycsIGNhbGxiYWNrKTtcbiAgICAgKiAgICAgIGNoYW5uZWwucHVibGlzaCgndG9waWMnLCB7IG15RGF0YTogMTAwIH0pO1xuICAgICAqXG4gICAgICogKipQYXJhbWV0ZXJzKipcbiAgICAgKiBAcGFyYW0ge09iamVjdHxTdHJpbmd9IG9wdGlvbnMgKE9wdGlvbmFsKSBJZiBzdHJpbmcsIGFzc3VtZWQgdG8gYmUgdGhlIGJhc2UgY2hhbm5lbCB1cmwuIElmIG9iamVjdCwgYXNzdW1lZCB0byBiZSBjb25maWd1cmF0aW9uIG9wdGlvbnMgZm9yIHRoZSBjb25zdHJ1Y3Rvci5cbiAgICAgKiBAcmV0dXJuIHtDaGFubmVsfSBDaGFubmVsIGluc3RhbmNlXG4gICAgICovXG4gICAgZ2V0Q2hhbm5lbDogZnVuY3Rpb24gKG9wdGlvbnMpIHtcbiAgICAgICAgLy9JZiB5b3UganVzdCB3YW50IHRvIHBhc3MgaW4gYSBzdHJpbmdcbiAgICAgICAgaWYgKG9wdGlvbnMgJiYgISQuaXNQbGFpbk9iamVjdChvcHRpb25zKSkge1xuICAgICAgICAgICAgb3B0aW9ucyA9IHtcbiAgICAgICAgICAgICAgICBiYXNlOiBvcHRpb25zXG4gICAgICAgICAgICB9O1xuICAgICAgICB9XG4gICAgICAgIHZhciBkZWZhdWx0cyA9IHtcbiAgICAgICAgICAgIHRyYW5zcG9ydDogdGhpcy5jb21ldGRcbiAgICAgICAgfTtcbiAgICAgICAgdmFyIGNoYW5uZWwgPSBuZXcgQ2hhbm5lbCgkLmV4dGVuZCh0cnVlLCB7fSwgdGhpcy5vcHRpb25zLmNoYW5uZWwsIGRlZmF1bHRzLCBvcHRpb25zKSk7XG5cblxuICAgICAgICAvL1dyYXAgc3VicyBhbmQgdW5zdWJzIHNvIHdlIGNhbiB1c2UgaXQgdG8gcmUtYXR0YWNoIGhhbmRsZXJzIGFmdGVyIGJlaW5nIGRpc2Nvbm5lY3RlZFxuICAgICAgICB2YXIgc3VicyA9IGNoYW5uZWwuc3Vic2NyaWJlO1xuICAgICAgICBjaGFubmVsLnN1YnNjcmliZSA9IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIHZhciBzdWJpZCA9IHN1YnMuYXBwbHkoY2hhbm5lbCwgYXJndW1lbnRzKTtcbiAgICAgICAgICAgIHRoaXMuY3VycmVudFN1YnNjcmlwdGlvbnMgPSB0aGlzLmN1cnJlbnRTdWJzY3JpcHRpb25zLmNvbmNhdChzdWJpZCk7XG4gICAgICAgICAgICByZXR1cm4gc3ViaWQ7XG4gICAgICAgIH0uYmluZCh0aGlzKTtcblxuXG4gICAgICAgIHZhciB1bnN1YnMgPSBjaGFubmVsLnVuc3Vic2NyaWJlO1xuICAgICAgICBjaGFubmVsLnVuc3Vic2NyaWJlID0gZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgdmFyIHJlbW92ZWQgPSB1bnN1YnMuYXBwbHkoY2hhbm5lbCwgYXJndW1lbnRzKTtcbiAgICAgICAgICAgIGZvciAodmFyIGkgPSAwOyBpIDwgdGhpcy5jdXJyZW50U3Vic2NyaXB0aW9ucy5sZW5ndGg7IGkrKykge1xuICAgICAgICAgICAgICAgIGlmICh0aGlzLmN1cnJlbnRTdWJzY3JpcHRpb25zW2ldLmlkID09PSByZW1vdmVkLmlkKSB7XG4gICAgICAgICAgICAgICAgICAgIHRoaXMuY3VycmVudFN1YnNjcmlwdGlvbnMuc3BsaWNlKGksIDEpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHJldHVybiByZW1vdmVkO1xuICAgICAgICB9LmJpbmQodGhpcyk7XG5cbiAgICAgICAgcmV0dXJuIGNoYW5uZWw7XG4gICAgfSxcblxuICAgIC8qKlxuICAgICAqIFN0YXJ0IGxpc3RlbmluZyBmb3IgZXZlbnRzIG9uIHRoaXMgaW5zdGFuY2UuIFNpZ25hdHVyZSBpcyBzYW1lIGFzIGZvciBqUXVlcnkgRXZlbnRzOiBodHRwOi8vYXBpLmpxdWVyeS5jb20vb24vLlxuICAgICAqXG4gICAgICogU3VwcG9ydGVkIGV2ZW50cyBhcmU6IGBjb25uZWN0YCwgYGRpc2Nvbm5lY3RgLCBgc3Vic2NyaWJlYCwgYHVuc3Vic2NyaWJlYCwgYHB1Ymxpc2hgLCBgZXJyb3JgLlxuICAgICAqXG4gICAgICogKipQYXJhbWV0ZXJzKipcbiAgICAgKlxuICAgICAqIEBwYXJhbSB7c3RyaW5nfSBldmVudCBUaGUgZXZlbnQgdHlwZS4gU2VlIG1vcmUgZGV0YWlsIGF0IGpRdWVyeSBFdmVudHM6IGh0dHA6Ly9hcGkuanF1ZXJ5LmNvbS9vbi8uXG4gICAgICovXG4gICAgb246IGZ1bmN0aW9uIChldmVudCkge1xuICAgICAgICAkKHRoaXMpLm9uLmFwcGx5KCQodGhpcyksIGFyZ3VtZW50cyk7XG4gICAgfSxcblxuICAgIC8qKlxuICAgICAqIFN0b3AgbGlzdGVuaW5nIGZvciBldmVudHMgb24gdGhpcyBpbnN0YW5jZS4gU2lnbmF0dXJlIGlzIHNhbWUgYXMgZm9yIGpRdWVyeSBFdmVudHM6IGh0dHA6Ly9hcGkuanF1ZXJ5LmNvbS9vZmYvLlxuICAgICAqXG4gICAgICogKipQYXJhbWV0ZXJzKipcbiAgICAgKlxuICAgICAqIEBwYXJhbSB7c3RyaW5nfSBldmVudCBUaGUgZXZlbnQgdHlwZS4gU2VlIG1vcmUgZGV0YWlsIGF0IGpRdWVyeSBFdmVudHM6IGh0dHA6Ly9hcGkuanF1ZXJ5LmNvbS9vZmYvLlxuICAgICAqL1xuICAgIG9mZjogZnVuY3Rpb24gKGV2ZW50KSB7XG4gICAgICAgICQodGhpcykub2ZmLmFwcGx5KCQodGhpcyksIGFyZ3VtZW50cyk7XG4gICAgfSxcblxuICAgIC8qKlxuICAgICAqIFRyaWdnZXIgZXZlbnRzIGFuZCBleGVjdXRlIGhhbmRsZXJzLiBTaWduYXR1cmUgaXMgc2FtZSBhcyBmb3IgalF1ZXJ5IEV2ZW50czogaHR0cDovL2FwaS5qcXVlcnkuY29tL3RyaWdnZXIvLlxuICAgICAqXG4gICAgICogKipQYXJhbWV0ZXJzKipcbiAgICAgKlxuICAgICAqIEBwYXJhbSB7c3RyaW5nfSBldmVudCBUaGUgZXZlbnQgdHlwZS4gU2VlIG1vcmUgZGV0YWlsIGF0IGpRdWVyeSBFdmVudHM6IGh0dHA6Ly9hcGkuanF1ZXJ5LmNvbS90cmlnZ2VyLy5cbiAgICAgKi9cbiAgICB0cmlnZ2VyOiBmdW5jdGlvbiAoZXZlbnQpIHtcbiAgICAgICAgJCh0aGlzKS50cmlnZ2VyLmFwcGx5KCQodGhpcyksIGFyZ3VtZW50cyk7XG4gICAgfVxufSk7XG5cbm1vZHVsZS5leHBvcnRzID0gQ2hhbm5lbE1hbmFnZXI7XG4iLCIndXNlIHN0cmljdCc7XG5cbi8qKlxuICogIyMgRXBpY2VudGVyIENoYW5uZWwgTWFuYWdlclxuICpcbiAqIFRoZSBFcGljZW50ZXIgcGxhdGZvcm0gcHJvdmlkZXMgYSBwdXNoIGNoYW5uZWwsIHdoaWNoIGFsbG93cyB5b3UgdG8gcHVibGlzaCBhbmQgc3Vic2NyaWJlIHRvIG1lc3NhZ2VzIHdpdGhpbiBhIFtwcm9qZWN0XSguLi8uLi8uLi9nbG9zc2FyeS8jcHJvamVjdHMpLCBbZ3JvdXBdKC4uLy4uLy4uL2dsb3NzYXJ5LyNncm91cHMpLCBvciBbbXVsdGlwbGF5ZXIgd29ybGRdKC4uLy4uLy4uL2dsb3NzYXJ5LyN3b3JsZCkuXG4gKlxuICogPGEgbmFtZT1cImJhY2tncm91bmRcIj48L2E+XG4gKiAjIyMgQ2hhbm5lbCBCYWNrZ3JvdW5kXG4gKlxuICogQ2hhbm5lbCBub3RpZmljYXRpb25zIGFyZSBvbmx5IGF2YWlsYWJsZSBmb3IgW3RlYW0gcHJvamVjdHNdKC4uLy4uLy4uL2dsb3NzYXJ5LyN0ZWFtKS4gVGhlcmUgYXJlIHR3byBtYWluIHVzZSBjYXNlcyBmb3IgdGhlIHB1c2ggY2hhbm5lbDogZXZlbnQgbm90aWZpY2F0aW9ucyBhbmQgY2hhdCBtZXNzYWdlcy5cbiAqXG4gKiAjIyMjIEV2ZW50IE5vdGlmaWNhdGlvbnNcbiAqXG4gKiBXaXRoaW4gYSBbbXVsdGlwbGF5ZXIgc2ltdWxhdGlvbiBvciB3b3JsZF0oLi4vLi4vLi4vZ2xvc3NhcnkvI3dvcmxkKSwgaXQgaXMgb2Z0ZW4gdXNlZnVsIGZvciB5b3VyIHByb2plY3QncyBbbW9kZWxdKC4uLy4uLy4uL3dyaXRpbmdfeW91cl9tb2RlbC8pIHRvIGFsZXJ0IHRoZSBbdXNlciBpbnRlcmZhY2UgKGJyb3dzZXIpXSguLi8uLi8uLi9jcmVhdGluZ195b3VyX2ludGVyZmFjZS8pIHRoYXQgc29tZXRoaW5nIG5ldyBoYXMgaGFwcGVuZWQuXG4gKlxuICogVXN1YWxseSwgdGhpcyBcInNvbWV0aGluZyBuZXdcIiBpcyBhbiBldmVudCB3aXRoaW4gdGhlIHByb2plY3QsIGdyb3VwLCBvciB3b3JsZCwgc3VjaCBhczpcbiAqXG4gKiAqIEFuIGVuZCB1c2VyIGNvbWVzIG9ubGluZSAobG9ncyBpbikgb3IgZ29lcyBvZmZsaW5lLiAoVGhpcyBpcyBlc3BlY2lhbGx5IGludGVyZXN0aW5nIGluIGEgbXVsdGlwbGF5ZXIgd29ybGQ7IG9ubHkgYXZhaWxhYmxlIGlmIHlvdSBoYXZlIFtlbmFibGVkIGF1dGhvcml6YXRpb25dKC4uLy4uLy4uL3VwZGF0aW5nX3lvdXJfc2V0dGluZ3MvI2dlbmVyYWwtc2V0dGluZ3MpIGZvciB0aGUgY2hhbm5lbC4pXG4gKiAqIEFuIGVuZCB1c2VyIGlzIGFzc2lnbmVkIHRvIGEgd29ybGQuXG4gKiAqIEFuIGVuZCB1c2VyIHVwZGF0ZXMgYSB2YXJpYWJsZSAvIG1ha2VzIGEgZGVjaXNpb24uXG4gKiAqIEFuIGVuZCB1c2VyIGNyZWF0ZXMgb3IgdXBkYXRlcyBkYXRhIHN0b3JlZCBpbiB0aGUgW0RhdGEgQVBJXSguLi9kYXRhLWFwaS1zZXJ2aWNlLykuXG4gKiAqIEFuIG9wZXJhdGlvbiAobWV0aG9kKSBpcyBjYWxsZWQuIChUaGlzIGlzIGVzcGVjaWFsbHkgaW50ZXJlc3RpbmcgaWYgdGhlIG1vZGVsIGlzIGFkdmFuY2VkLCBmb3IgaW5zdGFuY2UsIHRoZSBWZW5zaW0gYHN0ZXBgIG9wZXJhdGlvbiBpcyBjYWxsZWQuKVxuICpcbiAqIFdoZW4gdGhlc2UgZXZlbnRzIG9jY3VyLCB5b3Ugb2Z0ZW4gd2FudCB0byBoYXZlIHRoZSB1c2VyIGludGVyZmFjZSBmb3Igb25lIG9yIG1vcmUgZW5kIHVzZXJzIGF1dG9tYXRpY2FsbHkgdXBkYXRlIHdpdGggbmV3IGluZm9ybWF0aW9uLlxuICpcbiAqICMjIyMgQ2hhdCBNZXNzYWdlc1xuICpcbiAqIEFub3RoZXIgcmVhc29uIHRvIHVzZSB0aGUgcHVzaCBjaGFubmVsIGlzIHRvIGFsbG93IHBsYXllcnMgKGVuZCB1c2VycykgdG8gc2VuZCBjaGF0IG1lc3NhZ2VzIHRvIG90aGVyIHBsYXllcnMsIGFuZCB0byBoYXZlIHRob3NlIG1lc3NhZ2VzIGFwcGVhciBpbW1lZGlhdGVseS5cbiAqXG4gKiAjIyMjIEdldHRpbmcgU3RhcnRlZFxuICpcbiAqIEZvciBib3RoIHRoZSBldmVudCBub3RpZmljYXRpb24gYW5kIGNoYXQgbWVzc2FnZSB1c2UgY2FzZXM6XG4gKlxuICogKiBGaXJzdCwgZW5hYmxlIGNoYW5uZWwgbm90aWZpY2F0aW9ucyBmb3IgeW91ciBwcm9qZWN0LlxuICogICAgICAqIENoYW5uZWwgbm90aWZpY2F0aW9ucyBhcmUgb25seSBhdmFpbGFibGUgZm9yIFt0ZWFtIHByb2plY3RzXSguLi8uLi8uLi9nbG9zc2FyeS8jdGVhbSkuIFRvIGVuYWJsZSBub3RpZmljYXRpb25zIGZvciB5b3VyIHByb2plY3QsIFt1cGRhdGUgeW91ciBwcm9qZWN0IHNldHRpbmdzXSguLi8uLi8uLi91cGRhdGluZ195b3VyX3NldHRpbmdzLyNnZW5lcmFsLXNldHRpbmdzKSB0byB0dXJuIG9uIHRoZSAqKlB1c2ggQ2hhbm5lbCoqIHNldHRpbmcsIGFuZCBvcHRpb25hbGx5IHJlcXVpcmUgYXV0aG9yaXphdGlvbiBmb3IgdGhlIGNoYW5uZWwuXG4gKiAqIFRoZW4sIGluc3RhbnRpYXRlIGFuIEVwaWNlbnRlciBDaGFubmVsIE1hbmFnZXIuXG4gKiAqIE5leHQsIGdldCB0aGUgY2hhbm5lbCB3aXRoIHRoZSBzY29wZSB5b3Ugd2FudCAodXNlciwgd29ybGQsIGdyb3VwLCBkYXRhKS5cbiAqICogRmluYWxseSwgdXNlIHRoZSBjaGFubmVsJ3MgYHN1YnNjcmliZSgpYCBhbmQgYHB1Ymxpc2goKWAgbWV0aG9kcyB0byBzdWJzY3JpYmUgdG8gdG9waWNzIG9yIHB1Ymxpc2ggZGF0YSB0byB0b3BpY3MuXG4gKlxuICogSGVyZSdzIGFuIGV4YW1wbGUgb2YgdGhvc2UgbGFzdCB0aHJlZSBzdGVwcyAoaW5zdGFudGlhdGUsIGdldCBjaGFubmVsLCBzdWJzY3JpYmUpOlxuICpcbiAqICAgICB2YXIgY20gPSBuZXcgRi5tYW5hZ2VyLkNoYW5uZWxNYW5hZ2VyKCk7XG4gKiAgICAgdmFyIGdjID0gY20uZ2V0R3JvdXBDaGFubmVsKCk7XG4gKiAgICAgZ2Muc3Vic2NyaWJlKCcnLCBmdW5jdGlvbihkYXRhKSB7IGNvbnNvbGUubG9nKGRhdGEpOyB9KTtcbiAqICAgICBnYy5wdWJsaXNoKCcnLCB7IG1lc3NhZ2U6ICdhIG5ldyBtZXNzYWdlIHRvIHRoZSBncm91cCcgfSk7XG4gKlxuICogRm9yIGEgbW9yZSBkZXRhaWxlZCBleGFtcGxlLCBzZWUgYSBbY29tcGxldGUgcHVibGlzaCBhbmQgc3Vic2NyaWJlIGV4YW1wbGVdKC4uLy4uLy4uL3Jlc3RfYXBpcy9tdWx0aXBsYXllci9jaGFubmVsLyNlcGlqcy1leGFtcGxlKS5cbiAqXG4gKiBGb3IgZGV0YWlscyBvbiB3aGF0IGRhdGEgaXMgcHVibGlzaGVkIGF1dG9tYXRpY2FsbHkgdG8gd2hpY2ggY2hhbm5lbHMsIHNlZSBbQXV0b21hdGljIFB1Ymxpc2hpbmcgb2YgRXZlbnRzXSguLi8uLi8uLi9yZXN0X2FwaXMvbXVsdGlwbGF5ZXIvY2hhbm5lbC8jcHVibGlzaC1tZXNzYWdlLWF1dG8pLlxuICpcbiAqICMjIyMgQ3JlYXRpbmcgYW4gRXBpY2VudGVyIENoYW5uZWwgTWFuYWdlclxuICpcbiAqIFRoZSBFcGljZW50ZXIgQ2hhbm5lbCBNYW5hZ2VyIGlzIGEgd3JhcHBlciBhcm91bmQgdGhlIChtb3JlIGdlbmVyaWMpIFtDaGFubmVsIE1hbmFnZXJdKC4uL2NoYW5uZWwtbWFuYWdlci8pLCB0byBpbnN0YW50aWF0ZSBpdCB3aXRoIEVwaWNlbnRlci1zcGVjaWZpYyBkZWZhdWx0cy4gSWYgeW91IGFyZSBpbnRlcmVzdGVkIGluIGluY2x1ZGluZyBhIG5vdGlmaWNhdGlvbiBvciBjaGF0IGZlYXR1cmUgaW4geW91ciBwcm9qZWN0LCB1c2luZyBhbiBFcGljZW50ZXIgQ2hhbm5lbCBNYW5hZ2VyIGlzIHRoZSBlYXNpZXN0IHdheSB0byBnZXQgc3RhcnRlZC5cbiAqXG4gKiBZb3UnbGwgbmVlZCB0byBpbmNsdWRlIHRoZSBgZXBpY2VudGVyLW11bHRpcGxheWVyLWRlcGVuZGVuY2llcy5qc2AgbGlicmFyeSBpbiBhZGRpdGlvbiB0byB0aGUgYGVwaWNlbnRlci5qc2AgbGlicmFyeSBpbiB5b3VyIHByb2plY3QgdG8gdXNlIHRoZSBFcGljZW50ZXIgQ2hhbm5lbCBNYW5hZ2VyLiBTZWUgW0luY2x1ZGluZyBFcGljZW50ZXIuanNdKC4uLy4uLyNpbmNsdWRlKS5cbiAqXG4gKiBUaGUgcGFyYW1ldGVycyBmb3IgaW5zdGFudGlhdGluZyBhbiBFcGljZW50ZXIgQ2hhbm5lbCBNYW5hZ2VyIGluY2x1ZGU6XG4gKlxuICogKiBgb3B0aW9uc2AgT2JqZWN0IHdpdGggZGV0YWlscyBhYm91dCB0aGUgRXBpY2VudGVyIHByb2plY3QgZm9yIHRoaXMgRXBpY2VudGVyIENoYW5uZWwgTWFuYWdlciBpbnN0YW5jZS5cbiAqICogYG9wdGlvbnMuYWNjb3VudGAgVGhlIEVwaWNlbnRlciBhY2NvdW50IGlkICgqKlRlYW0gSUQqKiBmb3IgdGVhbSBwcm9qZWN0cywgKipVc2VyIElEKiogZm9yIHBlcnNvbmFsIHByb2plY3RzKS5cbiAqICogYG9wdGlvbnMucHJvamVjdGAgRXBpY2VudGVyIHByb2plY3QgaWQuXG4gKiAqIGBvcHRpb25zLnVzZXJOYW1lYCBFcGljZW50ZXIgdXNlck5hbWUgdXNlZCBmb3IgYXV0aGVudGljYXRpb24uXG4gKiAqIGBvcHRpb25zLnVzZXJJZGAgRXBpY2VudGVyIHVzZXIgaWQgdXNlZCBmb3IgYXV0aGVudGljYXRpb24uIE9wdGlvbmFsOyBgb3B0aW9ucy51c2VyTmFtZWAgaXMgcHJlZmVycmVkLlxuICogKiBgb3B0aW9ucy50b2tlbmAgRXBpY2VudGVyIHRva2VuIHVzZWQgZm9yIGF1dGhlbnRpY2F0aW9uLiAoWW91IGNhbiByZXRyaWV2ZSB0aGlzIHVzaW5nIGBhdXRoTWFuYWdlci5nZXRUb2tlbigpYCBmcm9tIHRoZSBbQXV0aG9yaXphdGlvbiBNYW5hZ2VyXSguLi9hdXRoLW1hbmFnZXIvKS4pXG4gKiAqIGBvcHRpb25zLmFsbG93QWxsQ2hhbm5lbHNgIElmIG5vdCBpbmNsdWRlZCBvciBpZiBzZXQgdG8gYGZhbHNlYCwgYWxsIGNoYW5uZWwgcGF0aHMgYXJlIHZhbGlkYXRlZDsgaWYgeW91ciBwcm9qZWN0IHJlcXVpcmVzIFtQdXNoIENoYW5uZWwgQXV0aG9yaXphdGlvbl0oLi4vLi4vLi4vdXBkYXRpbmdfeW91cl9zZXR0aW5ncy8pLCB5b3Ugc2hvdWxkIHVzZSB0aGlzIG9wdGlvbi4gSWYgeW91IHdhbnQgdG8gYWxsb3cgb3RoZXIgY2hhbm5lbCBwYXRocywgc2V0IHRvIGB0cnVlYDsgdGhpcyBpcyBub3QgY29tbW9uLlxuICovXG5cbnZhciBDaGFubmVsTWFuYWdlciA9IHJlcXVpcmUoJy4vY2hhbm5lbC1tYW5hZ2VyJyk7XG52YXIgQ29uZmlnU2VydmljZSA9IHJlcXVpcmUoJy4uL3NlcnZpY2UvY29uZmlndXJhdGlvbi1zZXJ2aWNlJyk7XG52YXIgY2xhc3NGcm9tID0gcmVxdWlyZSgnLi4vdXRpbC9pbmhlcml0Jyk7XG52YXIgU2Vzc2lvbk1hbmFnZXIgPSByZXF1aXJlKCcuLi9zdG9yZS9zZXNzaW9uLW1hbmFnZXInKTtcblxudmFyIHZhbGlkVHlwZXMgPSB7XG4gICAgcHJvamVjdDogdHJ1ZSxcbiAgICBncm91cDogdHJ1ZSxcbiAgICB3b3JsZDogdHJ1ZSxcbiAgICB1c2VyOiB0cnVlLFxuICAgIGRhdGE6IHRydWUsXG4gICAgZ2VuZXJhbDogdHJ1ZSxcbiAgICBjaGF0OiB0cnVlXG59O1xudmFyIGdldEZyb21TZXNzaW9uT3JFcnJvciA9IGZ1bmN0aW9uICh2YWx1ZSwgc2Vzc2lvbktleU5hbWUsIHNldHRpbmdzKSB7XG4gICAgaWYgKCF2YWx1ZSkge1xuICAgICAgICBpZiAoc2V0dGluZ3MgJiYgc2V0dGluZ3Nbc2Vzc2lvbktleU5hbWVdKSB7XG4gICAgICAgICAgICB2YWx1ZSA9IHNldHRpbmdzW3Nlc3Npb25LZXlOYW1lXTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihzZXNzaW9uS2V5TmFtZSArICcgbm90IGZvdW5kLiBQbGVhc2UgbG9nLWluIGFnYWluLCBvciBzcGVjaWZ5ICcgKyBzZXNzaW9uS2V5TmFtZSArICcgZXhwbGljaXRseScpO1xuICAgICAgICB9XG4gICAgfVxuICAgIHJldHVybiB2YWx1ZTtcbn07XG5cbnZhciBpc1ByZXNlbmNlRGF0YSA9IGZ1bmN0aW9uIChwYXlsb2FkKSB7XG4gICAgcmV0dXJuIHBheWxvYWQuZGF0YSAmJiBwYXlsb2FkLmRhdGEudHlwZSA9PT0gJ3VzZXInICYmIHBheWxvYWQuZGF0YS51c2VyO1xufTtcblxudmFyIF9fc3VwZXIgPSBDaGFubmVsTWFuYWdlci5wcm90b3R5cGU7XG52YXIgRXBpY2VudGVyQ2hhbm5lbE1hbmFnZXIgPSBjbGFzc0Zyb20oQ2hhbm5lbE1hbmFnZXIsIHtcbiAgICBjb25zdHJ1Y3RvcjogZnVuY3Rpb24gKG9wdGlvbnMpIHtcbiAgICAgICAgdGhpcy5zZXNzaW9uTWFuYWdlciA9IG5ldyBTZXNzaW9uTWFuYWdlcihvcHRpb25zKTtcbiAgICAgICAgdmFyIGRlZmF1bHRDb21ldE9wdGlvbnMgPSB0aGlzLnNlc3Npb25NYW5hZ2VyLmdldE1lcmdlZE9wdGlvbnMob3B0aW9ucyk7XG5cbiAgICAgICAgdmFyIHVybENvbmZpZyA9IG5ldyBDb25maWdTZXJ2aWNlKGRlZmF1bHRDb21ldE9wdGlvbnMpLmdldCgnc2VydmVyJyk7XG4gICAgICAgIGlmICghZGVmYXVsdENvbWV0T3B0aW9ucy51cmwpIHtcbiAgICAgICAgICAgIGRlZmF1bHRDb21ldE9wdGlvbnMudXJsID0gdXJsQ29uZmlnLmdldEFQSVBhdGgoJ2NoYW5uZWwnKTtcbiAgICAgICAgfVxuXG4gICAgICAgIGlmIChkZWZhdWx0Q29tZXRPcHRpb25zLmhhbmRzaGFrZSA9PT0gdW5kZWZpbmVkKSB7XG4gICAgICAgICAgICB2YXIgdXNlck5hbWUgPSBkZWZhdWx0Q29tZXRPcHRpb25zLnVzZXJOYW1lO1xuICAgICAgICAgICAgdmFyIHVzZXJJZCA9IGRlZmF1bHRDb21ldE9wdGlvbnMudXNlcklkO1xuICAgICAgICAgICAgdmFyIHRva2VuID0gZGVmYXVsdENvbWV0T3B0aW9ucy50b2tlbjtcbiAgICAgICAgICAgIGlmICgodXNlck5hbWUgfHwgdXNlcklkKSAmJiB0b2tlbikge1xuICAgICAgICAgICAgICAgIHZhciB1c2VyUHJvcCA9IHVzZXJOYW1lID8gJ3VzZXJOYW1lJyA6ICd1c2VySWQnO1xuICAgICAgICAgICAgICAgIHZhciBleHQgPSB7XG4gICAgICAgICAgICAgICAgICAgIGF1dGhvcml6YXRpb246ICdCZWFyZXIgJyArIHRva2VuXG4gICAgICAgICAgICAgICAgfTtcbiAgICAgICAgICAgICAgICBleHRbdXNlclByb3BdID0gdXNlck5hbWUgPyB1c2VyTmFtZSA6IHVzZXJJZDtcblxuICAgICAgICAgICAgICAgIGRlZmF1bHRDb21ldE9wdGlvbnMuaGFuZHNoYWtlID0ge1xuICAgICAgICAgICAgICAgICAgICBleHQ6IGV4dFxuICAgICAgICAgICAgICAgIH07XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICB0aGlzLm9wdGlvbnMgPSBkZWZhdWx0Q29tZXRPcHRpb25zO1xuICAgICAgICByZXR1cm4gX19zdXBlci5jb25zdHJ1Y3Rvci5jYWxsKHRoaXMsIGRlZmF1bHRDb21ldE9wdGlvbnMpO1xuICAgIH0sXG5cbiAgICAvKipcbiAgICAgKiBDcmVhdGVzIGFuZCByZXR1cm5zIGEgY2hhbm5lbCwgdGhhdCBpcywgYW4gaW5zdGFuY2Ugb2YgYSBbQ2hhbm5lbCBTZXJ2aWNlXSguLi9jaGFubmVsLXNlcnZpY2UvKS5cbiAgICAgKlxuICAgICAqIFRoaXMgbWV0aG9kIGVuZm9yY2VzIEVwaWNlbnRlci1zcGVjaWZpYyBjaGFubmVsIG5hbWluZzogYWxsIGNoYW5uZWxzIHJlcXVlc3RlZCBtdXN0IGJlIGluIHRoZSBmb3JtIGAve3R5cGV9L3thY2NvdW50IGlkfS97cHJvamVjdCBpZH0vey4uLn1gLCB3aGVyZSBgdHlwZWAgaXMgb25lIG9mIGBydW5gLCBgZGF0YWAsIGB1c2VyYCwgYHdvcmxkYCwgb3IgYGNoYXRgLlxuICAgICAqXG4gICAgICogKipFeGFtcGxlKipcbiAgICAgKlxuICAgICAqICAgICAgdmFyIGNtID0gbmV3IEYubWFuYWdlci5FcGljZW50ZXJDaGFubmVsTWFuYWdlcigpO1xuICAgICAqICAgICAgdmFyIGNoYW5uZWwgPSBjbS5nZXRDaGFubmVsKCcvZ3JvdXAvYWNtZS9zdXBwbHktY2hhaW4tZ2FtZS8nKTtcbiAgICAgKlxuICAgICAqICAgICAgY2hhbm5lbC5zdWJzY3JpYmUoJ3RvcGljJywgY2FsbGJhY2spO1xuICAgICAqICAgICAgY2hhbm5lbC5wdWJsaXNoKCd0b3BpYycsIHsgbXlEYXRhOiAxMDAgfSk7XG4gICAgICpcbiAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAqIEBwYXJhbSB7T2JqZWN0fFN0cmluZ30gb3B0aW9ucyAoT3B0aW9uYWwpIElmIHN0cmluZywgYXNzdW1lZCB0byBiZSB0aGUgYmFzZSBjaGFubmVsIHVybC4gSWYgb2JqZWN0LCBhc3N1bWVkIHRvIGJlIGNvbmZpZ3VyYXRpb24gb3B0aW9ucyBmb3IgdGhlIGNvbnN0cnVjdG9yLlxuICAgICAqIEByZXR1cm4ge0NoYW5uZWx9IENoYW5uZWwgaW5zdGFuY2VcbiAgICAgKi9cbiAgICBnZXRDaGFubmVsOiBmdW5jdGlvbiAob3B0aW9ucykge1xuICAgICAgICBpZiAob3B0aW9ucyAmJiB0eXBlb2Ygb3B0aW9ucyAhPT0gJ29iamVjdCcpIHtcbiAgICAgICAgICAgIG9wdGlvbnMgPSB7XG4gICAgICAgICAgICAgICAgYmFzZTogb3B0aW9uc1xuICAgICAgICAgICAgfTtcbiAgICAgICAgfVxuICAgICAgICB2YXIgY2hhbm5lbE9wdHMgPSAkLmV4dGVuZCh7fSwgdGhpcy5vcHRpb25zLCBvcHRpb25zKTtcbiAgICAgICAgdmFyIGJhc2UgPSBjaGFubmVsT3B0cy5iYXNlO1xuICAgICAgICBpZiAoIWJhc2UpIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcignTm8gYmFzZSB0b3BpYyB3YXMgcHJvdmlkZWQnKTtcbiAgICAgICAgfVxuXG4gICAgICAgIGlmICghY2hhbm5lbE9wdHMuYWxsb3dBbGxDaGFubmVscykge1xuICAgICAgICAgICAgdmFyIGJhc2VQYXJ0cyA9IGJhc2Uuc3BsaXQoJy8nKTtcbiAgICAgICAgICAgIHZhciBjaGFubmVsVHlwZSA9IGJhc2VQYXJ0c1sxXTtcbiAgICAgICAgICAgIGlmIChiYXNlUGFydHMubGVuZ3RoIDwgNCkgeyAvL2VzbGludC1kaXNhYmxlLWxpbmVcbiAgICAgICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ0ludmFsaWQgY2hhbm5lbCBiYXNlIG5hbWUsIGl0IG11c3QgYmUgaW4gdGhlIGZvcm0gL3t0eXBlfS97YWNjb3VudCBpZH0ve3Byb2plY3QgaWR9L3suLi59Jyk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBpZiAoIXZhbGlkVHlwZXNbY2hhbm5lbFR5cGVdKSB7XG4gICAgICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdJbnZhbGlkIGNoYW5uZWwgdHlwZScpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgIHJldHVybiBfX3N1cGVyLmdldENoYW5uZWwuYXBwbHkodGhpcywgYXJndW1lbnRzKTtcbiAgICB9LFxuXG4gICAgLyoqXG4gICAgICogQ3JlYXRlIGFuZCByZXR1cm4gYSBwdWJsaXNoL3N1YnNjcmliZSBjaGFubmVsIChmcm9tIHRoZSB1bmRlcmx5aW5nIFtDaGFubmVsIE1hbmFnZXJdKC4uL2NoYW5uZWwtbWFuYWdlci8pKSBmb3IgdGhlIGdpdmVuIFtncm91cF0oLi4vLi4vLi4vZ2xvc3NhcnkvI2dyb3VwcykuIFRoZSBncm91cCBtdXN0IGV4aXN0IGluIHRoZSBhY2NvdW50ICh0ZWFtKSBhbmQgcHJvamVjdCBwcm92aWRlZC5cbiAgICAgKlxuICAgICAqIFRoZXJlIGFyZSBubyBub3RpZmljYXRpb25zIGZyb20gRXBpY2VudGVyIG9uIHRoaXMgY2hhbm5lbDsgYWxsIG1lc3NhZ2VzIGFyZSB1c2VyLW9yaWdpbmF0ZWQuXG4gICAgICpcbiAgICAgKiAqKkV4YW1wbGUqKlxuICAgICAqXG4gICAgICogICAgIHZhciBjbSA9IG5ldyBGLm1hbmFnZXIuQ2hhbm5lbE1hbmFnZXIoKTtcbiAgICAgKiAgICAgdmFyIGdjID0gY20uZ2V0R3JvdXBDaGFubmVsKCk7XG4gICAgICogICAgIGdjLnN1YnNjcmliZSgnYnJvYWRjYXN0cycsIGNhbGxiYWNrKTtcbiAgICAgKlxuICAgICAqICoqUmV0dXJuIFZhbHVlKipcbiAgICAgKlxuICAgICAqICogKkNoYW5uZWwqIFJldHVybnMgdGhlIGNoYW5uZWwgKGFuIGluc3RhbmNlIG9mIHRoZSBbQ2hhbm5lbCBTZXJ2aWNlXSguLi9jaGFubmVsLXNlcnZpY2UvKSkuXG4gICAgICpcbiAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAqXG4gICAgICogQHBhcmFtICB7U3RyaW5nfSBncm91cE5hbWUgKE9wdGlvbmFsKSBHcm91cCB0byBicm9hZGNhc3QgdG8uIElmIG5vdCBwcm92aWRlZCwgcGlja3MgdXAgZ3JvdXAgZnJvbSBjdXJyZW50IHNlc3Npb24gaWYgZW5kIHVzZXIgaXMgbG9nZ2VkIGluLlxuICAgICAqIEByZXR1cm4ge0NoYW5uZWx9IENoYW5uZWwgaW5zdGFuY2VcbiAgICAgKi9cbiAgICBnZXRHcm91cENoYW5uZWw6IGZ1bmN0aW9uIChncm91cE5hbWUpIHtcbiAgICAgICAgdmFyIHNlc3Npb24gPSB0aGlzLnNlc3Npb25NYW5hZ2VyLmdldE1lcmdlZE9wdGlvbnModGhpcy5vcHRpb25zKTtcbiAgICAgICAgZ3JvdXBOYW1lID0gZ2V0RnJvbVNlc3Npb25PckVycm9yKGdyb3VwTmFtZSwgJ2dyb3VwTmFtZScsIHNlc3Npb24pO1xuICAgICAgICB2YXIgYWNjb3VudCA9IGdldEZyb21TZXNzaW9uT3JFcnJvcignJywgJ2FjY291bnQnLCBzZXNzaW9uKTtcbiAgICAgICAgdmFyIHByb2plY3QgPSBnZXRGcm9tU2Vzc2lvbk9yRXJyb3IoJycsICdwcm9qZWN0Jywgc2Vzc2lvbik7XG5cbiAgICAgICAgdmFyIGJhc2VUb3BpYyA9IFsnL2dyb3VwJywgYWNjb3VudCwgcHJvamVjdCwgZ3JvdXBOYW1lXS5qb2luKCcvJyk7XG4gICAgICAgIHZhciBjaGFubmVsID0gX19zdXBlci5nZXRDaGFubmVsLmNhbGwodGhpcywgeyBiYXNlOiBiYXNlVG9waWMgfSk7XG4gICAgICAgIHZhciBvbGRzdWJzID0gY2hhbm5lbC5zdWJzY3JpYmU7XG4gICAgICAgIGNoYW5uZWwuc3Vic2NyaWJlID0gZnVuY3Rpb24gKHRvcGljLCBjYWxsYmFjaywgY29udGV4dCwgb3B0aW9ucykge1xuICAgICAgICAgICAgdmFyIGNhbGxiYWNrV2l0aG91dFByZXNlbmNlRGF0YSA9IGZ1bmN0aW9uIChwYXlsb2FkKSB7XG4gICAgICAgICAgICAgICAgaWYgKCFpc1ByZXNlbmNlRGF0YShwYXlsb2FkKSkge1xuICAgICAgICAgICAgICAgICAgICBjYWxsYmFjay5jYWxsKGNvbnRleHQsIHBheWxvYWQpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH07XG4gICAgICAgICAgICByZXR1cm4gb2xkc3Vicy5jYWxsKGNoYW5uZWwsIHRvcGljLCBjYWxsYmFja1dpdGhvdXRQcmVzZW5jZURhdGEsIGNvbnRleHQsIG9wdGlvbnMpO1xuICAgICAgICB9O1xuICAgICAgICByZXR1cm4gY2hhbm5lbDtcbiAgICB9LFxuXG4gICAgLyoqXG4gICAgICogQ3JlYXRlIGFuZCByZXR1cm4gYSBwdWJsaXNoL3N1YnNjcmliZSBjaGFubmVsIChmcm9tIHRoZSB1bmRlcmx5aW5nIFtDaGFubmVsIE1hbmFnZXJdKC4uL2NoYW5uZWwtbWFuYWdlci8pKSBmb3IgdGhlIGdpdmVuIFt3b3JsZF0oLi4vLi4vLi4vZ2xvc3NhcnkvI3dvcmxkKS5cbiAgICAgKlxuICAgICAqIFRoaXMgaXMgdHlwaWNhbGx5IHVzZWQgdG9nZXRoZXIgd2l0aCB0aGUgW1dvcmxkIE1hbmFnZXJdKC4uL3dvcmxkLW1hbmFnZXIpLlxuICAgICAqXG4gICAgICogKipFeGFtcGxlKipcbiAgICAgKlxuICAgICAqICAgICB2YXIgY20gPSBuZXcgRi5tYW5hZ2VyLkNoYW5uZWxNYW5hZ2VyKCk7XG4gICAgICogICAgIHZhciB3b3JsZE1hbmFnZXIgPSBuZXcgRi5tYW5hZ2VyLldvcmxkTWFuYWdlcih7XG4gICAgICogICAgICAgICBhY2NvdW50OiAnYWNtZS1zaW11bGF0aW9ucycsXG4gICAgICogICAgICAgICBwcm9qZWN0OiAnc3VwcGx5LWNoYWluLWdhbWUnLFxuICAgICAqICAgICAgICAgZ3JvdXA6ICd0ZWFtMScsXG4gICAgICogICAgICAgICBydW46IHsgbW9kZWw6ICdtb2RlbC5lcW4nIH1cbiAgICAgKiAgICAgfSk7XG4gICAgICogICAgIHdvcmxkTWFuYWdlci5nZXRDdXJyZW50V29ybGQoKS50aGVuKGZ1bmN0aW9uICh3b3JsZE9iamVjdCwgd29ybGRBZGFwdGVyKSB7XG4gICAgICogICAgICAgICB2YXIgd29ybGRDaGFubmVsID0gY20uZ2V0V29ybGRDaGFubmVsKHdvcmxkT2JqZWN0KTtcbiAgICAgKiAgICAgICAgIHdvcmxkQ2hhbm5lbC5zdWJzY3JpYmUoJycsIGZ1bmN0aW9uIChkYXRhKSB7XG4gICAgICogICAgICAgICAgICAgY29uc29sZS5sb2coZGF0YSk7XG4gICAgICogICAgICAgICB9KTtcbiAgICAgKiAgICAgIH0pO1xuICAgICAqXG4gICAgICogKipSZXR1cm4gVmFsdWUqKlxuICAgICAqXG4gICAgICogKiAqQ2hhbm5lbCogUmV0dXJucyB0aGUgY2hhbm5lbCAoYW4gaW5zdGFuY2Ugb2YgdGhlIFtDaGFubmVsIFNlcnZpY2VdKC4uL2NoYW5uZWwtc2VydmljZS8pKS5cbiAgICAgKlxuICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICpcbiAgICAgKiBAcGFyYW0gIHtTdHJpbmd8T2JqZWN0fSB3b3JsZCBUaGUgd29ybGQgb2JqZWN0IG9yIGlkLlxuICAgICAqIEBwYXJhbSAge1N0cmluZ30gZ3JvdXBOYW1lIChPcHRpb25hbCkgR3JvdXAgdGhlIHdvcmxkIGV4aXN0cyBpbi4gSWYgbm90IHByb3ZpZGVkLCBwaWNrcyB1cCBncm91cCBmcm9tIGN1cnJlbnQgc2Vzc2lvbiBpZiBlbmQgdXNlciBpcyBsb2dnZWQgaW4uXG4gICAgICogQHJldHVybiB7Q2hhbm5lbH0gQ2hhbm5lbCBpbnN0YW5jZVxuICAgICAqL1xuICAgIGdldFdvcmxkQ2hhbm5lbDogZnVuY3Rpb24gKHdvcmxkLCBncm91cE5hbWUpIHtcbiAgICAgICAgdmFyIHdvcmxkaWQgPSAoJC5pc1BsYWluT2JqZWN0KHdvcmxkKSAmJiB3b3JsZC5pZCkgPyB3b3JsZC5pZCA6IHdvcmxkO1xuICAgICAgICBpZiAoIXdvcmxkaWQpIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcignUGxlYXNlIHNwZWNpZnkgYSB3b3JsZCBpZCcpO1xuICAgICAgICB9XG4gICAgICAgIHZhciBzZXNzaW9uID0gdGhpcy5zZXNzaW9uTWFuYWdlci5nZXRNZXJnZWRPcHRpb25zKHRoaXMub3B0aW9ucyk7XG5cbiAgICAgICAgZ3JvdXBOYW1lID0gZ2V0RnJvbVNlc3Npb25PckVycm9yKGdyb3VwTmFtZSwgJ2dyb3VwTmFtZScsIHNlc3Npb24pO1xuICAgICAgICB2YXIgYWNjb3VudCA9IGdldEZyb21TZXNzaW9uT3JFcnJvcignJywgJ2FjY291bnQnLCBzZXNzaW9uKTtcbiAgICAgICAgdmFyIHByb2plY3QgPSBnZXRGcm9tU2Vzc2lvbk9yRXJyb3IoJycsICdwcm9qZWN0Jywgc2Vzc2lvbik7XG5cbiAgICAgICAgdmFyIGJhc2VUb3BpYyA9IFsnL3dvcmxkJywgYWNjb3VudCwgcHJvamVjdCwgZ3JvdXBOYW1lLCB3b3JsZGlkXS5qb2luKCcvJyk7XG4gICAgICAgIHJldHVybiBfX3N1cGVyLmdldENoYW5uZWwuY2FsbCh0aGlzLCB7IGJhc2U6IGJhc2VUb3BpYyB9KTtcbiAgICB9LFxuXG4gICAgLyoqXG4gICAgICogQ3JlYXRlIGFuZCByZXR1cm4gYSBwdWJsaXNoL3N1YnNjcmliZSBjaGFubmVsIChmcm9tIHRoZSB1bmRlcmx5aW5nIFtDaGFubmVsIE1hbmFnZXJdKC4uL2NoYW5uZWwtbWFuYWdlci8pKSBmb3IgdGhlIGN1cnJlbnQgW2VuZCB1c2VyXSguLi8uLi8uLi9nbG9zc2FyeS8jdXNlcnMpIGluIHRoYXQgdXNlcidzIGN1cnJlbnQgW3dvcmxkXSguLi8uLi8uLi9nbG9zc2FyeS8jd29ybGQpLlxuICAgICAqXG4gICAgICogVGhpcyBpcyB0eXBpY2FsbHkgdXNlZCB0b2dldGhlciB3aXRoIHRoZSBbV29ybGQgTWFuYWdlcl0oLi4vd29ybGQtbWFuYWdlcikuIE5vdGUgdGhhdCB0aGlzIGNoYW5uZWwgb25seSBnZXRzIG5vdGlmaWNhdGlvbnMgZm9yIHdvcmxkcyBjdXJyZW50bHkgaW4gbWVtb3J5LiAoU2VlIG1vcmUgYmFja2dyb3VuZCBvbiBbcGVyc2lzdGVuY2VdKC4uLy4uLy4uL3J1bl9wZXJzaXN0ZW5jZSkuKVxuICAgICAqXG4gICAgICogKipFeGFtcGxlKipcbiAgICAgKlxuICAgICAqICAgICB2YXIgY20gPSBuZXcgRi5tYW5hZ2VyLkNoYW5uZWxNYW5hZ2VyKCk7XG4gICAgICogICAgIHZhciB3b3JsZE1hbmFnZXIgPSBuZXcgRi5tYW5hZ2VyLldvcmxkTWFuYWdlcih7XG4gICAgICogICAgICAgICBhY2NvdW50OiAnYWNtZS1zaW11bGF0aW9ucycsXG4gICAgICogICAgICAgICBwcm9qZWN0OiAnc3VwcGx5LWNoYWluLWdhbWUnLFxuICAgICAqICAgICAgICAgZ3JvdXA6ICd0ZWFtMScsXG4gICAgICogICAgICAgICBydW46IHsgbW9kZWw6ICdtb2RlbC5lcW4nIH1cbiAgICAgKiAgICAgfSk7XG4gICAgICogICAgIHdvcmxkTWFuYWdlci5nZXRDdXJyZW50V29ybGQoKS50aGVuKGZ1bmN0aW9uICh3b3JsZE9iamVjdCwgd29ybGRBZGFwdGVyKSB7XG4gICAgICogICAgICAgICB2YXIgdXNlckNoYW5uZWwgPSBjbS5nZXRVc2VyQ2hhbm5lbCh3b3JsZE9iamVjdCk7XG4gICAgICogICAgICAgICB1c2VyQ2hhbm5lbC5zdWJzY3JpYmUoJycsIGZ1bmN0aW9uIChkYXRhKSB7XG4gICAgICogICAgICAgICAgICAgY29uc29sZS5sb2coZGF0YSk7XG4gICAgICogICAgICAgICB9KTtcbiAgICAgKiAgICAgIH0pO1xuICAgICAqXG4gICAgICpcbiAgICAgKiAqKlJldHVybiBWYWx1ZSoqXG4gICAgICpcbiAgICAgKiAqICpDaGFubmVsKiBSZXR1cm5zIHRoZSBjaGFubmVsIChhbiBpbnN0YW5jZSBvZiB0aGUgW0NoYW5uZWwgU2VydmljZV0oLi4vY2hhbm5lbC1zZXJ2aWNlLykpLlxuICAgICAqXG4gICAgICogKipQYXJhbWV0ZXJzKipcbiAgICAgKlxuICAgICAqIEBwYXJhbSAge1N0cmluZ3xPYmplY3R9IHdvcmxkIFdvcmxkIG9iamVjdCBvciBpZC5cbiAgICAgKiBAcGFyYW0gIHtTdHJpbmd8T2JqZWN0fSB1c2VyIChPcHRpb25hbCkgVXNlciBvYmplY3Qgb3IgaWQuIElmIG5vdCBwcm92aWRlZCwgcGlja3MgdXAgdXNlciBpZCBmcm9tIGN1cnJlbnQgc2Vzc2lvbiBpZiBlbmQgdXNlciBpcyBsb2dnZWQgaW4uXG4gICAgICogQHBhcmFtICB7U3RyaW5nfSBncm91cE5hbWUgKE9wdGlvbmFsKSBHcm91cCB0aGUgd29ybGQgZXhpc3RzIGluLiBJZiBub3QgcHJvdmlkZWQsIHBpY2tzIHVwIGdyb3VwIGZyb20gY3VycmVudCBzZXNzaW9uIGlmIGVuZCB1c2VyIGlzIGxvZ2dlZCBpbi5cbiAgICAgKiBAcmV0dXJuIHtDaGFubmVsfSBDaGFubmVsIGluc3RhbmNlXG4gICAgICovXG4gICAgZ2V0VXNlckNoYW5uZWw6IGZ1bmN0aW9uICh3b3JsZCwgdXNlciwgZ3JvdXBOYW1lKSB7XG4gICAgICAgIHZhciB3b3JsZGlkID0gKCQuaXNQbGFpbk9iamVjdCh3b3JsZCkgJiYgd29ybGQuaWQpID8gd29ybGQuaWQgOiB3b3JsZDtcbiAgICAgICAgaWYgKCF3b3JsZGlkKSB7XG4gICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ1BsZWFzZSBzcGVjaWZ5IGEgd29ybGQgaWQnKTtcbiAgICAgICAgfVxuICAgICAgICB2YXIgc2Vzc2lvbiA9IHRoaXMuc2Vzc2lvbk1hbmFnZXIuZ2V0TWVyZ2VkT3B0aW9ucyh0aGlzLm9wdGlvbnMpO1xuXG4gICAgICAgIHZhciB1c2VyaWQgPSAoJC5pc1BsYWluT2JqZWN0KHVzZXIpICYmIHVzZXIuaWQpID8gdXNlci5pZCA6IHVzZXI7XG4gICAgICAgIHVzZXJpZCA9IGdldEZyb21TZXNzaW9uT3JFcnJvcih1c2VyaWQsICd1c2VySWQnLCBzZXNzaW9uKTtcbiAgICAgICAgZ3JvdXBOYW1lID0gZ2V0RnJvbVNlc3Npb25PckVycm9yKGdyb3VwTmFtZSwgJ2dyb3VwTmFtZScsIHNlc3Npb24pO1xuXG4gICAgICAgIHZhciBhY2NvdW50ID0gZ2V0RnJvbVNlc3Npb25PckVycm9yKCcnLCAnYWNjb3VudCcsIHNlc3Npb24pO1xuICAgICAgICB2YXIgcHJvamVjdCA9IGdldEZyb21TZXNzaW9uT3JFcnJvcignJywgJ3Byb2plY3QnLCBzZXNzaW9uKTtcblxuICAgICAgICB2YXIgYmFzZVRvcGljID0gWycvdXNlcicsIGFjY291bnQsIHByb2plY3QsIGdyb3VwTmFtZSwgd29ybGRpZCwgdXNlcmlkXS5qb2luKCcvJyk7XG4gICAgICAgIHJldHVybiBfX3N1cGVyLmdldENoYW5uZWwuY2FsbCh0aGlzLCB7IGJhc2U6IGJhc2VUb3BpYyB9KTtcbiAgICB9LFxuXG4gICAgLyoqXG4gICAgICogQ3JlYXRlIGFuZCByZXR1cm4gYSBwdWJsaXNoL3N1YnNjcmliZSBjaGFubmVsIChmcm9tIHRoZSB1bmRlcmx5aW5nIFtDaGFubmVsIE1hbmFnZXJdKC4uL2NoYW5uZWwtbWFuYWdlci8pKSB0aGF0IGF1dG9tYXRpY2FsbHkgdHJhY2tzIHRoZSBwcmVzZW5jZSBvZiBhbiBbZW5kIHVzZXJdKC4uLy4uLy4uL2dsb3NzYXJ5LyN1c2VycyksIHRoYXQgaXMsIHdoZXRoZXIgdGhlIGVuZCB1c2VyIGlzIGN1cnJlbnRseSBvbmxpbmUgaW4gdGhpcyBncm91cC4gTm90aWZpY2F0aW9ucyBhcmUgYXV0b21hdGljYWxseSBzZW50IHdoZW4gdGhlIGVuZCB1c2VyIGNvbWVzIG9ubGluZSwgYW5kIHdoZW4gdGhlIGVuZCB1c2VyIGdvZXMgb2ZmbGluZSAobm90IHByZXNlbnQgZm9yIG1vcmUgdGhhbiAyIG1pbnV0ZXMpLiBVc2VmdWwgaW4gbXVsdGlwbGF5ZXIgZ2FtZXMgZm9yIGxldHRpbmcgZWFjaCBlbmQgdXNlciBrbm93IHdoZXRoZXIgb3RoZXIgdXNlcnMgaW4gdGhlaXIgZ3JvdXAgYXJlIGFsc28gb25saW5lLlxuICAgICAqXG4gICAgICogTm90ZSB0aGF0IHRoZSBwcmVzZW5jZSBjaGFubmVsIGlzIHRyYWNraW5nIGFsbCBlbmQgdXNlcnMgaW4gYSBncm91cC4gSW4gcGFydGljdWxhciwgaWYgdGhlIHByb2plY3QgYWRkaXRpb25hbGx5IHNwbGl0cyBlYWNoIGdyb3VwIGludG8gW3dvcmxkc10oLi4vd29ybGQtbWFuYWdlci8pLCB0aGlzIGNoYW5uZWwgY29udGludWVzIHRvIHNob3cgbm90aWZpY2F0aW9ucyBmb3IgYWxsIGVuZCB1c2VycyBpbiB0aGUgZ3JvdXAgKG5vdCByZXN0cmljdGVkIGJ5IHdvcmxkcykuXG4gICAgICpcbiAgICAgKiAqKkV4YW1wbGUqKlxuICAgICAqXG4gICAgICogICAgIHZhciBjbSA9IG5ldyBGLm1hbmFnZXIuQ2hhbm5lbE1hbmFnZXIoKTtcbiAgICAgKiAgICAgdmFyIHBjID0gY20uZ2V0UHJlc2VuY2VDaGFubmVsKCk7XG4gICAgICogICAgIHBjLnN1YnNjcmliZSgnJywgZnVuY3Rpb24gKGRhdGEpIHtcbiAgICAgKiAgICAgICAgICAvLyAnZGF0YScgaXMgdGhlIGVudGlyZSBtZXNzYWdlIG9iamVjdCB0byB0aGUgY2hhbm5lbDtcbiAgICAgKiAgICAgICAgICAvLyBwYXJzZSBmb3IgaW5mb3JtYXRpb24gb2YgaW50ZXJlc3RcbiAgICAgKiAgICAgICAgICBpZiAoZGF0YS5kYXRhLnN1YlR5cGUgPT09ICdkaXNjb25uZWN0Jykge1xuICAgICAqICAgICAgICAgICAgICAgY29uc29sZS5sb2coJ3VzZXIgJywgZGF0YS5kYXRhLnVzZXIudXNlck5hbWUsICdkaXNjb25uZWN0ZWQgYXQgJywgZGF0YS5kYXRhLmRhdGUpO1xuICAgICAqICAgICAgICAgIH1cbiAgICAgKiAgICAgICAgICBpZiAoZGF0YS5kYXRhLnN1YlR5cGUgPT09ICdjb25uZWN0Jykge1xuICAgICAqICAgICAgICAgICAgICAgY29uc29sZS5sb2coJ3VzZXIgJywgZGF0YS5kYXRhLnVzZXIudXNlck5hbWUsICdjb25uZWN0ZWQgYXQgJywgZGF0YS5kYXRhLmRhdGUpO1xuICAgICAqICAgICAgICAgIH1cbiAgICAgKiAgICAgfSk7XG4gICAgICpcbiAgICAgKlxuICAgICAqICoqUmV0dXJuIFZhbHVlKipcbiAgICAgKlxuICAgICAqICogKkNoYW5uZWwqIFJldHVybnMgdGhlIGNoYW5uZWwgKGFuIGluc3RhbmNlIG9mIHRoZSBbQ2hhbm5lbCBTZXJ2aWNlXSguLi9jaGFubmVsLXNlcnZpY2UvKSkuXG4gICAgICpcbiAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAqXG4gICAgICogQHBhcmFtICB7U3RyaW5nfSBncm91cE5hbWUgKE9wdGlvbmFsKSBHcm91cCB0aGUgZW5kIHVzZXIgaXMgaW4uIElmIG5vdCBwcm92aWRlZCwgcGlja3MgdXAgZ3JvdXAgZnJvbSBjdXJyZW50IHNlc3Npb24gaWYgZW5kIHVzZXIgaXMgbG9nZ2VkIGluLlxuICAgICAqIEByZXR1cm4ge0NoYW5uZWx9IENoYW5uZWwgaW5zdGFuY2VcbiAgICAgKi9cbiAgICBnZXRQcmVzZW5jZUNoYW5uZWw6IGZ1bmN0aW9uIChncm91cE5hbWUpIHtcbiAgICAgICAgdmFyIHNlc3Npb24gPSB0aGlzLnNlc3Npb25NYW5hZ2VyLmdldE1lcmdlZE9wdGlvbnModGhpcy5vcHRpb25zKTtcbiAgICAgICAgZ3JvdXBOYW1lID0gZ2V0RnJvbVNlc3Npb25PckVycm9yKGdyb3VwTmFtZSwgJ2dyb3VwTmFtZScsIHNlc3Npb24pO1xuICAgICAgICB2YXIgYWNjb3VudCA9IGdldEZyb21TZXNzaW9uT3JFcnJvcignJywgJ2FjY291bnQnLCBzZXNzaW9uKTtcbiAgICAgICAgdmFyIHByb2plY3QgPSBnZXRGcm9tU2Vzc2lvbk9yRXJyb3IoJycsICdwcm9qZWN0Jywgc2Vzc2lvbik7XG5cbiAgICAgICAgdmFyIGJhc2VUb3BpYyA9IFsnL2dyb3VwJywgYWNjb3VudCwgcHJvamVjdCwgZ3JvdXBOYW1lXS5qb2luKCcvJyk7XG4gICAgICAgIHZhciBjaGFubmVsID0gX19zdXBlci5nZXRDaGFubmVsLmNhbGwodGhpcywgeyBiYXNlOiBiYXNlVG9waWMgfSk7XG4gICAgICAgIHZhciBvbGRzdWJzID0gY2hhbm5lbC5zdWJzY3JpYmU7XG4gICAgICAgIGNoYW5uZWwuc3Vic2NyaWJlID0gZnVuY3Rpb24gKHRvcGljLCBjYWxsYmFjaywgY29udGV4dCwgb3B0aW9ucykge1xuICAgICAgICAgICAgdmFyIGNhbGxiYWNrV2l0aE9ubHlQcmVzZW5jZURhdGEgPSBmdW5jdGlvbiAocGF5bG9hZCkge1xuICAgICAgICAgICAgICAgIGlmIChpc1ByZXNlbmNlRGF0YShwYXlsb2FkKSkge1xuICAgICAgICAgICAgICAgICAgICBjYWxsYmFjay5jYWxsKGNvbnRleHQsIHBheWxvYWQpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH07XG4gICAgICAgICAgICByZXR1cm4gb2xkc3Vicy5jYWxsKGNoYW5uZWwsIHRvcGljLCBjYWxsYmFja1dpdGhPbmx5UHJlc2VuY2VEYXRhLCBjb250ZXh0LCBvcHRpb25zKTtcbiAgICAgICAgfTtcbiAgICAgICAgcmV0dXJuIGNoYW5uZWw7XG4gICAgfSxcblxuICAgIC8qKlxuICAgICAqIENyZWF0ZSBhbmQgcmV0dXJuIGEgcHVibGlzaC9zdWJzY3JpYmUgY2hhbm5lbCAoZnJvbSB0aGUgdW5kZXJseWluZyBbQ2hhbm5lbCBNYW5hZ2VyXSguLi9jaGFubmVsLW1hbmFnZXIvKSkgZm9yIHRoZSBnaXZlbiBjb2xsZWN0aW9uLiAoVGhlIGNvbGxlY3Rpb24gbmFtZSBpcyBzcGVjaWZpZWQgaW4gdGhlIGByb290YCBhcmd1bWVudCB3aGVuIHRoZSBbRGF0YSBTZXJ2aWNlXSguLi9kYXRhLWFwaS1zZXJ2aWNlLykgaXMgaW5zdGFudGlhdGVkLikgTXVzdCBiZSBvbmUgb2YgdGhlIGNvbGxlY3Rpb25zIGluIHRoaXMgYWNjb3VudCAodGVhbSkgYW5kIHByb2plY3QuXG4gICAgICpcbiAgICAgKiBUaGVyZSBhcmUgYXV0b21hdGljIG5vdGlmaWNhdGlvbnMgZnJvbSBFcGljZW50ZXIgb24gdGhpcyBjaGFubmVsIHdoZW4gZGF0YSBpcyBjcmVhdGVkLCB1cGRhdGVkLCBvciBkZWxldGVkIGluIHRoaXMgY29sbGVjdGlvbi4gU2VlIG1vcmUgb24gW2F1dG9tYXRpYyBtZXNzYWdlcyB0byB0aGUgZGF0YSBjaGFubmVsXSguLi8uLi8uLi9yZXN0X2FwaXMvbXVsdGlwbGF5ZXIvY2hhbm5lbC8jZGF0YS1tZXNzYWdlcykuXG4gICAgICpcbiAgICAgKiAqKkV4YW1wbGUqKlxuICAgICAqXG4gICAgICogICAgIHZhciBjbSA9IG5ldyBGLm1hbmFnZXIuQ2hhbm5lbE1hbmFnZXIoKTtcbiAgICAgKiAgICAgdmFyIGRjID0gY20uZ2V0RGF0YUNoYW5uZWwoJ3N1cnZleS1yZXNwb25zZXMnKTtcbiAgICAgKiAgICAgZGMuc3Vic2NyaWJlKCcnLCBmdW5jdGlvbihkYXRhLCBtZXRhKSB7XG4gICAgICogICAgICAgICAgY29uc29sZS5sb2coZGF0YSk7XG4gICAgICpcbiAgICAgKiAgICAgICAgICAvLyBtZXRhLmRhdGUgaXMgdGltZSBvZiBjaGFuZ2UsXG4gICAgICogICAgICAgICAgLy8gbWV0YS5zdWJUeXBlIGlzIHRoZSBraW5kIG9mIGNoYW5nZTogbmV3LCB1cGRhdGUsIG9yIGRlbGV0ZVxuICAgICAqICAgICAgICAgIC8vIG1ldGEucGF0aCBpcyB0aGUgZnVsbCBwYXRoIHRvIHRoZSBjaGFuZ2VkIGRhdGFcbiAgICAgKiAgICAgICAgICBjb25zb2xlLmxvZyhtZXRhKTtcbiAgICAgKiAgICAgfSk7XG4gICAgICpcbiAgICAgKiAqKlJldHVybiBWYWx1ZSoqXG4gICAgICpcbiAgICAgKiAqICpDaGFubmVsKiBSZXR1cm5zIHRoZSBjaGFubmVsIChhbiBpbnN0YW5jZSBvZiB0aGUgW0NoYW5uZWwgU2VydmljZV0oLi4vY2hhbm5lbC1zZXJ2aWNlLykpLlxuICAgICAqXG4gICAgICogKipQYXJhbWV0ZXJzKipcbiAgICAgKlxuICAgICAqIEBwYXJhbSAge1N0cmluZ30gY29sbGVjdGlvbiBOYW1lIG9mIGNvbGxlY3Rpb24gd2hvc2UgYXV0b21hdGljIG5vdGlmaWNhdGlvbnMgeW91IHdhbnQgdG8gcmVjZWl2ZS5cbiAgICAgKiBAcmV0dXJuIHtDaGFubmVsfSBDaGFubmVsIGluc3RhbmNlXG4gICAgICovXG4gICAgZ2V0RGF0YUNoYW5uZWw6IGZ1bmN0aW9uIChjb2xsZWN0aW9uKSB7XG4gICAgICAgIGlmICghY29sbGVjdGlvbikge1xuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdQbGVhc2Ugc3BlY2lmeSBhIGNvbGxlY3Rpb24gdG8gbGlzdGVuIG9uLicpO1xuICAgICAgICB9XG5cbiAgICAgICAgdmFyIHNlc3Npb24gPSB0aGlzLnNlc3Npb25NYW5hZ2VyLmdldE1lcmdlZE9wdGlvbnModGhpcy5vcHRpb25zKTtcbiAgICAgICAgdmFyIGFjY291bnQgPSBnZXRGcm9tU2Vzc2lvbk9yRXJyb3IoJycsICdhY2NvdW50Jywgc2Vzc2lvbik7XG4gICAgICAgIHZhciBwcm9qZWN0ID0gZ2V0RnJvbVNlc3Npb25PckVycm9yKCcnLCAncHJvamVjdCcsIHNlc3Npb24pO1xuICAgICAgICB2YXIgYmFzZVRvcGljID0gWycvZGF0YScsIGFjY291bnQsIHByb2plY3QsIGNvbGxlY3Rpb25dLmpvaW4oJy8nKTtcbiAgICAgICAgdmFyIGNoYW5uZWwgPSBfX3N1cGVyLmdldENoYW5uZWwuY2FsbCh0aGlzLCB7IGJhc2U6IGJhc2VUb3BpYyB9KTtcblxuICAgICAgICAvL1RPRE86IEZpeCBhZnRlciBFcGljZW50ZXIgYnVnIGlzIHJlc29sdmVkXG4gICAgICAgIHZhciBvbGRzdWJzID0gY2hhbm5lbC5zdWJzY3JpYmU7XG4gICAgICAgIGNoYW5uZWwuc3Vic2NyaWJlID0gZnVuY3Rpb24gKHRvcGljLCBjYWxsYmFjaywgY29udGV4dCwgb3B0aW9ucykge1xuICAgICAgICAgICAgdmFyIGNhbGxiYWNrV2l0aENsZWFuRGF0YSA9IGZ1bmN0aW9uIChwYXlsb2FkKSB7XG4gICAgICAgICAgICAgICAgdmFyIG1ldGEgPSB7XG4gICAgICAgICAgICAgICAgICAgIHBhdGg6IHBheWxvYWQuY2hhbm5lbCxcbiAgICAgICAgICAgICAgICAgICAgc3ViVHlwZTogcGF5bG9hZC5kYXRhLnN1YlR5cGUsXG4gICAgICAgICAgICAgICAgICAgIGRhdGU6IHBheWxvYWQuZGF0YS5kYXRlLFxuICAgICAgICAgICAgICAgICAgICBkYXRhUGF0aDogcGF5bG9hZC5kYXRhLmRhdGEucGF0aCxcbiAgICAgICAgICAgICAgICB9O1xuICAgICAgICAgICAgICAgIHZhciBhY3R1YWxEYXRhID0gcGF5bG9hZC5kYXRhLmRhdGE7XG4gICAgICAgICAgICAgICAgaWYgKGFjdHVhbERhdGEuZGF0YSAhPT0gdW5kZWZpbmVkKSB7IC8vRGVsZXRlIG5vdGlmaWNhdGlvbnMgYXJlIG9uZSBkYXRhLWxldmVsIGJlaGluZCBvZiBjb3Vyc2VcbiAgICAgICAgICAgICAgICAgICAgYWN0dWFsRGF0YSA9IGFjdHVhbERhdGEuZGF0YTtcbiAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICBjYWxsYmFjay5jYWxsKGNvbnRleHQsIGFjdHVhbERhdGEsIG1ldGEpO1xuICAgICAgICAgICAgfTtcbiAgICAgICAgICAgIHJldHVybiBvbGRzdWJzLmNhbGwoY2hhbm5lbCwgdG9waWMsIGNhbGxiYWNrV2l0aENsZWFuRGF0YSwgY29udGV4dCwgb3B0aW9ucyk7XG4gICAgICAgIH07XG5cbiAgICAgICAgcmV0dXJuIGNoYW5uZWw7XG4gICAgfVxufSk7XG5cbm1vZHVsZS5leHBvcnRzID0gRXBpY2VudGVyQ2hhbm5lbE1hbmFnZXI7XG4iLCIndXNlIHN0cmljdCc7XG5cbm1vZHVsZS5leHBvcnRzID0ge1xuICAgIEVQSV9TRVNTSU9OX0tFWTogJ2VwaWNlbnRlcmpzLnNlc3Npb24nLFxuICAgIFNUUkFURUdZX1NFU1NJT05fS0VZOiAnZXBpY2VudGVyLXNjZW5hcmlvJ1xufTsiLCIvKipcbiogIyMgUnVuIE1hbmFnZXJcbipcbiogVGhlIFJ1biBNYW5hZ2VyIGdpdmVzIHlvdSBhY2Nlc3MgdG8gcnVucyBmb3IgeW91ciBwcm9qZWN0LiBUaGlzIGFsbG93cyB5b3UgdG8gcmVhZCBhbmQgdXBkYXRlIHZhcmlhYmxlcywgY2FsbCBvcGVyYXRpb25zLCBldGMuIEFkZGl0aW9uYWxseSwgdGhlIFJ1biBNYW5hZ2VyIGdpdmVzIHlvdSBjb250cm9sIG92ZXIgcnVuIGNyZWF0aW9uIGRlcGVuZGluZyBvbiBydW4gc3RhdGVzLiBTcGVjaWZpY2FsbHksIHlvdSBjYW4gc2VsZWN0IFtydW4gY3JlYXRpb24gc3RyYXRlZ2llcyAocnVsZXMpXSguLi9zdHJhdGVnaWVzLykgZm9yIHdoaWNoIHJ1bnMgZW5kIHVzZXJzIG9mIHlvdXIgcHJvamVjdCB3b3JrIHdpdGggd2hlbiB0aGV5IGxvZyBpbiB0byB5b3VyIHByb2plY3QuXG4qXG4qIFRoZXJlIGFyZSBtYW55IHdheXMgdG8gY3JlYXRlIG5ldyBydW5zLCBpbmNsdWRpbmcgdGhlIEVwaWNlbnRlci5qcyBbUnVuIFNlcnZpY2VdKC4uL3J1bi1hcGktc2VydmljZS8pIGFuZCB0aGUgUkVTRlRmdWwgW1J1biBBUEldKC4uLy4uLy4uL3Jlc3RfYXBpcy9hZ2dyZWdhdGVfcnVuX2FwaSkuIEhvd2V2ZXIsIGZvciBzb21lIHByb2plY3RzIGl0IG1ha2VzIG1vcmUgc2Vuc2UgdG8gcGljayB1cCB3aGVyZSB0aGUgdXNlciBsZWZ0IG9mZiwgdXNpbmcgYW4gZXhpc3RpbmcgcnVuLiBBbmQgaW4gc29tZSBwcm9qZWN0cywgd2hldGhlciB0byBjcmVhdGUgYSBuZXcgcnVuIG9yIHVzZSBhbiBleGlzdGluZyBvbmUgaXMgY29uZGl0aW9uYWwsIGZvciBleGFtcGxlIGJhc2VkIG9uIGNoYXJhY3RlcmlzdGljcyBvZiB0aGUgZXhpc3RpbmcgcnVuIG9yIHlvdXIgb3duIGtub3dsZWRnZSBhYm91dCB0aGUgbW9kZWwuIFRoZSBSdW4gTWFuYWdlciBwcm92aWRlcyB0aGlzIGxldmVsIG9mIGNvbnRyb2w6IHlvdXIgY2FsbCB0byBgZ2V0UnVuKClgLCByYXRoZXIgdGhhbiBhbHdheXMgcmV0dXJuaW5nIGEgbmV3IHJ1biwgcmV0dXJucyBhIHJ1biBiYXNlZCBvbiB0aGUgc3RyYXRlZ3kgeW91J3ZlIHNwZWNpZmllZC5cbipcbipcbiogIyMjIFVzaW5nIHRoZSBSdW4gTWFuYWdlciB0byBjcmVhdGUgYW5kIGFjY2VzcyBydW5zXG4qXG4qIFRvIHVzZSB0aGUgUnVuIE1hbmFnZXIsIGluc3RhbnRpYXRlIGl0IGJ5IHBhc3NpbmcgaW46XG4qXG4qICAgKiBgcnVuYDogKHJlcXVpcmVkKSBSdW4gb2JqZWN0LiBNdXN0IGNvbnRhaW46XG4qICAgICAgICogYGFjY291bnRgOiBFcGljZW50ZXIgYWNjb3VudCBpZCAoKipUZWFtIElEKiogZm9yIHRlYW0gcHJvamVjdHMsICoqVXNlciBJRCoqIGZvciBwZXJzb25hbCBwcm9qZWN0cykuXG4qICAgICAgICogYHByb2plY3RgOiBFcGljZW50ZXIgcHJvamVjdCBpZC5cbiogICAgICAgKiBgbW9kZWxgOiBUaGUgbmFtZSBvZiB5b3VyIHByaW1hcnkgbW9kZWwgZmlsZS4gKFNlZSBtb3JlIG9uIFtXcml0aW5nIHlvdXIgTW9kZWxdKC4uLy4uLy4uL3dyaXRpbmdfeW91cl9tb2RlbC8pLilcbiogICAgICAgKiBgc2NvcGVgOiAob3B0aW9uYWwpIFNjb3BlIG9iamVjdCBmb3IgdGhlIHJ1biwgZm9yIGV4YW1wbGUgYHNjb3BlLmdyb3VwYCB3aXRoIHZhbHVlIG9mIHRoZSBuYW1lIG9mIHRoZSBncm91cC5cbiogICAgICAgKiBgc2VydmVyYDogKG9wdGlvbmFsKSBBbiBvYmplY3Qgd2l0aCBvbmUgZmllbGQsIGBob3N0YC4gVGhlIHZhbHVlIG9mIGBob3N0YCBpcyB0aGUgc3RyaW5nIGBhcGkuZm9yaW8uY29tYCwgdGhlIFVSSSBvZiB0aGUgRm9yaW8gc2VydmVyLiBUaGlzIGlzIGF1dG9tYXRpY2FsbHkgc2V0LCBidXQgeW91IGNhbiBwYXNzIGl0IGV4cGxpY2l0bHkgaWYgZGVzaXJlZC4gSXQgaXMgbW9zdCBjb21tb25seSB1c2VkIGZvciBjbGFyaXR5IHdoZW4geW91IGFyZSBbaG9zdGluZyBhbiBFcGljZW50ZXIgcHJvamVjdCBvbiB5b3VyIG93biBzZXJ2ZXJdKC4uLy4uLy4uL2hvd190by9zZWxmX2hvc3RpbmcvKS5cbiogICAgICAgKiBgZmlsZXNgOiAob3B0aW9uYWwpIElmIGFuZCBvbmx5IGlmIHlvdSBhcmUgdXNpbmcgYSBWZW5zaW0gbW9kZWwgYW5kIHlvdSBoYXZlIGFkZGl0aW9uYWwgZGF0YSB0byBwYXNzIGluIHRvIHlvdXIgbW9kZWwsIHlvdSBjYW4gb3B0aW9uYWxseSBwYXNzIGEgYGZpbGVzYCBvYmplY3Qgd2l0aCB0aGUgbmFtZXMgb2YgdGhlIGZpbGVzLCBmb3IgZXhhbXBsZTogYFwiZmlsZXNcIjoge1wiZGF0YVwiOiBcIm15RXh0cmFEYXRhLnhsc1wifWAuIChTZWUgbW9yZSBvbiBbVXNpbmcgRXh0ZXJuYWwgRGF0YSBpbiBWZW5zaW1dKC4uLy4uLy4uL21vZGVsX2NvZGUvdmVuc2ltL3ZlbnNpbV9leGFtcGxlX3hscy8pLilcbipcbiogICAqIGBzdHJhdGVneWA6IChvcHRpb25hbCkgUnVuIGNyZWF0aW9uIHN0cmF0ZWd5IGZvciB3aGVuIHRvIGNyZWF0ZSBhIG5ldyBydW4gYW5kIHdoZW4gdG8gcmV1c2UgYW4gZW5kIHVzZXIncyBleGlzdGluZyBydW4uIFRoaXMgaXMgKm9wdGlvbmFsKjsgYnkgZGVmYXVsdCwgdGhlIFJ1biBNYW5hZ2VyIHNlbGVjdHMgYHJldXNlLXBlci1zZXNzaW9uYCwgb3IgYHJldXNlLWxhc3QtaW5pdGlhbGl6ZWRgIGlmIHlvdSBhbHNvIHBhc3MgaW4gYW4gaW5pdGlhbCBvcGVyYXRpb24uIFNlZSBbYmVsb3ddKCN1c2luZy10aGUtcnVuLW1hbmFnZXItdG8tYWNjZXNzLWFuZC1yZWdpc3Rlci1zdHJhdGVnaWVzKSBmb3IgbW9yZSBpbmZvcm1hdGlvbiBvbiBzdHJhdGVnaWVzLlxuKlxuKiAgICogYHN0cmF0ZWd5T3B0aW9uc2A6IChvcHRpb25hbCkgQWRkaXRpb25hbCBvcHRpb25zIHBhc3NlZCBkaXJlY3RseSB0byB0aGUgW3J1biBjcmVhdGlvbiBzdHJhdGVneV0oLi4vc3RyYXRlZ2llcy8pLlxuKlxuKiAgICogYHNlc3Npb25LZXlgOiAob3B0aW9uYWwpIE5hbWUgb2YgYnJvd3NlciBjb29raWUgaW4gd2hpY2ggdG8gc3RvcmUgcnVuIGluZm9ybWF0aW9uLCBpbmNsdWRpbmcgcnVuIGlkLiBNYW55IGNvbmRpdGlvbmFsIHN0cmF0ZWdpZXMsIGluY2x1ZGluZyB0aGUgcHJvdmlkZWQgc3RyYXRlZ2llcywgcmVseSBvbiB0aGlzIGJyb3dzZXIgY29va2llIHRvIHN0b3JlIHRoZSBydW4gaWQgYW5kIGhlbHAgbWFrZSB0aGUgZGVjaXNpb24gb2Ygd2hldGhlciB0byBjcmVhdGUgYSBuZXcgcnVuIG9yIHVzZSBhbiBleGlzdGluZyBvbmUuIFRoZSBuYW1lIG9mIHRoaXMgY29va2llIGRlZmF1bHRzIHRvIGBlcGljZW50ZXItc2NlbmFyaW9gIGFuZCBjYW4gYmUgc2V0IHdpdGggdGhlIGBzZXNzaW9uS2V5YCBwYXJhbWV0ZXIuIFRoaXMgY2FuIGFsc28gYmUgYSBmdW5jdGlvbiB3aGljaCByZXR1cm5zIGEgc3RyaW5nLCBpZiB5b3UnZCBsaWtlIHRvIGNvbnRyb2wgdGhpcyBhdCBydW50aW1lLlxuKlxuKlxuKiBBZnRlciBpbnN0YW50aWF0aW5nIGEgUnVuIE1hbmFnZXIsIG1ha2UgYSBjYWxsIHRvIGBnZXRSdW4oKWAgd2hlbmV2ZXIgeW91IG5lZWQgdG8gYWNjZXNzIGEgcnVuIGZvciB0aGlzIGVuZCB1c2VyLiBUaGUgYFJ1bk1hbmFnZXIucnVuYCBjb250YWlucyB0aGUgaW5zdGFudGlhdGVkIFtSdW4gU2VydmljZV0oLi4vcnVuLWFwaS1zZXJ2aWNlLykuIFRoZSBSdW4gU2VydmljZSBhbGxvd3MgeW91IHRvIGFjY2VzcyB2YXJpYWJsZXMsIGNhbGwgb3BlcmF0aW9ucywgZXRjLlxuKlxuKiAqKkV4YW1wbGUqKlxuKlxuKiAgICAgICB2YXIgcm0gPSBuZXcgRi5tYW5hZ2VyLlJ1bk1hbmFnZXIoe1xuKiAgICAgICAgICAgcnVuOiB7XG4qICAgICAgICAgICAgICAgYWNjb3VudDogJ2FjbWUtc2ltdWxhdGlvbnMnLFxuKiAgICAgICAgICAgICAgIHByb2plY3Q6ICdzdXBwbHktY2hhaW4tZ2FtZScsXG4qICAgICAgICAgICAgICAgbW9kZWw6ICdzdXBwbHktY2hhaW4tbW9kZWwuamwnLFxuKiAgICAgICAgICAgICAgIHNlcnZlcjogeyBob3N0OiAnYXBpLmZvcmlvLmNvbScgfVxuKiAgICAgICAgICAgfSxcbiogICAgICAgICAgIHN0cmF0ZWd5OiAncmV1c2UtbmV2ZXInLFxuKiAgICAgICAgICAgc2Vzc2lvbktleTogJ2VwaWNlbnRlci1zZXNzaW9uJ1xuKiAgICAgICB9KTtcbiogICAgICAgcm0uZ2V0UnVuKClcbiogICAgICAgICAgIC50aGVuKGZ1bmN0aW9uKHJ1bikge1xuKiAgICAgICAgICAgICAgIC8vIHRoZSByZXR1cm4gdmFsdWUgb2YgZ2V0UnVuKCkgaXMgYSBydW4gb2JqZWN0XG4qICAgICAgICAgICAgICAgdmFyIHRoaXNSdW5JZCA9IHJ1bi5pZDtcbiogICAgICAgICAgICAgICAvLyB0aGUgUnVuTWFuYWdlci5ydW4gYWxzbyBjb250YWlucyB0aGUgaW5zdGFudGlhdGVkIFJ1biBTZXJ2aWNlLFxuKiAgICAgICAgICAgICAgIC8vIHNvIGFueSBSdW4gU2VydmljZSBtZXRob2QgaXMgdmFsaWQgaGVyZVxuKiAgICAgICAgICAgICAgIHJtLnJ1bi5kbygncnVuTW9kZWwnKTtcbiogICAgICAgfSlcbipcbipcbiogIyMjIFVzaW5nIHRoZSBSdW4gTWFuYWdlciB0byBhY2Nlc3MgYW5kIHJlZ2lzdGVyIHN0cmF0ZWdpZXNcbipcbiogVGhlIGBzdHJhdGVneWAgZm9yIGEgUnVuIE1hbmFnZXIgZGVzY3JpYmVzIHdoZW4gdG8gY3JlYXRlIGEgbmV3IHJ1biBhbmQgd2hlbiB0byByZXVzZSBhbiBlbmQgdXNlcidzIGV4aXN0aW5nIHJ1bi4gVGhlIFJ1biBNYW5hZ2VyIGlzIHJlc3BvbnNpYmxlIGZvciBwYXNzaW5nIGEgc3RyYXRlZ3kgZXZlcnl0aGluZyBpdCBtaWdodCBuZWVkIHRvIGRldGVybWluZSB0aGUgJ2NvcnJlY3QnIHJ1biwgdGhhdCBpcywgaG93IHRvIGZpbmQgdGhlIGJlc3QgZXhpc3RpbmcgcnVuIGFuZCBob3cgdG8gZGVjaWRlIHdoZW4gdG8gY3JlYXRlIGEgbmV3IHJ1bi5cbipcbiogVGhlcmUgYXJlIHNldmVyYWwgY29tbW9uIHN0cmF0ZWdpZXMgcHJvdmlkZWQgYXMgcGFydCBvZiBFcGljZW50ZXIuanMsIHdoaWNoIHlvdSBjYW4gbGlzdCBieSBhY2Nlc3NpbmcgYEYubWFuYWdlci5SdW5NYW5hZ2VyLnN0cmF0ZWdpZXNgLiBZb3UgY2FuIGFsc28gY3JlYXRlIHlvdXIgb3duIHN0cmF0ZWdpZXMsIGFuZCByZWdpc3RlciB0aGVtIHRvIHVzZSB3aXRoIFJ1biBNYW5hZ2Vycy4gU2VlIFtSdW4gTWFuYWdlciBTdHJhdGVnaWVzXSguLi9zdHJhdGVnaWVzLykgZm9yIGRldGFpbHMuXG4qIFxuKi9cblxuJ3VzZSBzdHJpY3QnO1xudmFyIHN0cmF0ZWdpZXMgPSByZXF1aXJlKCcuL3J1bi1zdHJhdGVnaWVzJyk7XG52YXIgc3BlY2lhbE9wZXJhdGlvbnMgPSByZXF1aXJlKCcuL3NwZWNpYWwtb3BlcmF0aW9ucycpO1xuXG52YXIgUnVuU2VydmljZSA9IHJlcXVpcmUoJy4uL3NlcnZpY2UvcnVuLWFwaS1zZXJ2aWNlJyk7XG52YXIgU2Vzc2lvbk1hbmFnZXIgPSByZXF1aXJlKCcuLi9zdG9yZS9zZXNzaW9uLW1hbmFnZXInKTtcblxudmFyIHV0aWwgPSByZXF1aXJlKCcuLi91dGlsL29iamVjdC11dGlsJyk7XG52YXIga2V5TmFtZXMgPSByZXF1aXJlKCcuL2tleS1uYW1lcycpO1xuXG5mdW5jdGlvbiBwYXRjaFJ1blNlcnZpY2Uoc2VydmljZSwgbWFuYWdlcikge1xuICAgIGlmIChzZXJ2aWNlLnBhdGNoZWQpIHtcbiAgICAgICAgcmV0dXJuIHNlcnZpY2U7XG4gICAgfVxuXG4gICAgdmFyIG9yaWcgPSBzZXJ2aWNlLmRvO1xuICAgIHNlcnZpY2UuZG8gPSBmdW5jdGlvbiAob3BlcmF0aW9uLCBwYXJhbXMsIG9wdGlvbnMpIHtcbiAgICAgICAgdmFyIHJlc2VydmVkT3BzID0gT2JqZWN0LmtleXMoc3BlY2lhbE9wZXJhdGlvbnMpO1xuICAgICAgICBpZiAocmVzZXJ2ZWRPcHMuaW5kZXhPZihvcGVyYXRpb24pID09PSAtMSkge1xuICAgICAgICAgICAgcmV0dXJuIG9yaWcuYXBwbHkoc2VydmljZSwgYXJndW1lbnRzKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIHJldHVybiBzcGVjaWFsT3BlcmF0aW9uc1tvcGVyYXRpb25dLmNhbGwoc2VydmljZSwgcGFyYW1zLCBvcHRpb25zLCBtYW5hZ2VyKTtcbiAgICAgICAgfVxuICAgIH07XG5cbiAgICBzZXJ2aWNlLnBhdGNoZWQgPSB0cnVlO1xuXG4gICAgcmV0dXJuIHNlcnZpY2U7XG59XG5cbmZ1bmN0aW9uIHNlc3Npb25LZXlGcm9tT3B0aW9ucyhvcHRpb25zLCBydW5TZXJ2aWNlKSB7XG4gICAgdmFyIGNvbmZpZyA9IHJ1blNlcnZpY2UuZ2V0Q3VycmVudENvbmZpZygpO1xuICAgIHZhciBzZXNzaW9uS2V5ID0gJC5pc0Z1bmN0aW9uKG9wdGlvbnMuc2Vzc2lvbktleSkgPyBvcHRpb25zLnNlc3Npb25LZXkoY29uZmlnKSA6IG9wdGlvbnMuc2Vzc2lvbktleTtcbiAgICByZXR1cm4gc2Vzc2lvbktleTtcbn1cblxuZnVuY3Rpb24gc2V0UnVuSW5TZXNzaW9uKHNlc3Npb25LZXksIHJ1biwgc2Vzc2lvbk1hbmFnZXIpIHtcbiAgICBpZiAoc2Vzc2lvbktleSkge1xuICAgICAgICBkZWxldGUgcnVuLnZhcmlhYmxlcztcbiAgICAgICAgc2Vzc2lvbk1hbmFnZXIuZ2V0U3RvcmUoKS5zZXQoc2Vzc2lvbktleSwgSlNPTi5zdHJpbmdpZnkocnVuKSk7XG4gICAgfVxufVxuXG52YXIgZGVmYXVsdHMgPSB7XG4gICAgc2Vzc2lvbktleTogZnVuY3Rpb24gKGNvbmZpZykgeyBcbiAgICAgICAgdmFyIGJhc2VLZXkgPSBrZXlOYW1lcy5TVFJBVEVHWV9TRVNTSU9OX0tFWTtcbiAgICAgICAgdmFyIGtleSA9IFsnYWNjb3VudCcsICdwcm9qZWN0JywgJ21vZGVsJ10ucmVkdWNlKGZ1bmN0aW9uIChhY2N1bSwga2V5KSB7XG4gICAgICAgICAgICByZXR1cm4gY29uZmlnW2tleV0gPyBhY2N1bSArICctJyArIGNvbmZpZ1trZXldIDogYWNjdW07IFxuICAgICAgICB9LCBiYXNlS2V5KTtcbiAgICAgICAgcmV0dXJuIGtleTtcbiAgICB9XG59O1xuXG5mdW5jdGlvbiBSdW5NYW5hZ2VyKG9wdGlvbnMpIHtcbiAgICB0aGlzLm9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSwgZGVmYXVsdHMsIG9wdGlvbnMpO1xuXG4gICAgaWYgKHRoaXMub3B0aW9ucy5ydW4gaW5zdGFuY2VvZiBSdW5TZXJ2aWNlKSB7XG4gICAgICAgIHRoaXMucnVuID0gdGhpcy5vcHRpb25zLnJ1bjtcbiAgICB9IGVsc2UgaWYgKCF1dGlsLmlzRW1wdHkodGhpcy5vcHRpb25zLnJ1bikpIHtcbiAgICAgICAgdGhpcy5ydW4gPSBuZXcgUnVuU2VydmljZSh0aGlzLm9wdGlvbnMucnVuKTtcbiAgICB9IGVsc2Uge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ05vIHJ1biBvcHRpb25zIHBhc3NlZCB0byBSdW5NYW5hZ2VyJyk7XG4gICAgfVxuICAgIHBhdGNoUnVuU2VydmljZSh0aGlzLnJ1biwgdGhpcyk7XG5cbiAgICB0aGlzLnN0cmF0ZWd5ID0gc3RyYXRlZ2llcy5nZXRCZXN0U3RyYXRlZ3kodGhpcy5vcHRpb25zKTtcbiAgICB0aGlzLnNlc3Npb25NYW5hZ2VyID0gbmV3IFNlc3Npb25NYW5hZ2VyKHRoaXMub3B0aW9ucyk7XG59XG5cblJ1bk1hbmFnZXIucHJvdG90eXBlID0ge1xuICAgIC8qKlxuICAgICAqIFJldHVybnMgdGhlIHJ1biBvYmplY3QgZm9yIHRoZSAnY29ycmVjdCcgcnVuLiBUaGUgY29ycmVjdCBydW4gaXMgZGVmaW5lZCBieSB0aGUgc3RyYXRlZ3kuIFxuICAgICAqXG4gICAgICogRm9yIGV4YW1wbGUsIGlmIHRoZSBzdHJhdGVneSBpcyBgcmV1c2UtbmV2ZXJgLCB0aGUgY2FsbFxuICAgICAqIHRvIGBnZXRSdW4oKWAgYWx3YXlzIHJldHVybnMgYSBuZXdseSBjcmVhdGVkIHJ1bjsgaWYgdGhlIHN0cmF0ZWd5IGlzIGByZXVzZS1wZXItc2Vzc2lvbmAsXG4gICAgICogYGdldFJ1bigpYCByZXR1cm5zIHRoZSBydW4gY3VycmVudGx5IHJlZmVyZW5jZWQgaW4gdGhlIGJyb3dzZXIgY29va2llLCBhbmQgaWYgdGhlcmUgaXMgbm9uZSwgY3JlYXRlcyBhIG5ldyBydW4uIFxuICAgICAqIFNlZSBbUnVuIE1hbmFnZXIgU3RyYXRlZ2llc10oLi4vc3RyYXRlZ2llcy8pIGZvciBtb3JlIG9uIHN0cmF0ZWdpZXMuXG4gICAgICpcbiAgICAgKiAgKipFeGFtcGxlKipcbiAgICAgKlxuICAgICAqICAgICAgcm0uZ2V0UnVuKCkudGhlbihmdW5jdGlvbiAocnVuKSB7XG4gICAgICogICAgICAgICAgLy8gdXNlIHRoZSBydW4gb2JqZWN0XG4gICAgICogICAgICAgICAgdmFyIHRoaXNSdW5JZCA9IHJ1bi5pZDtcbiAgICAgKlxuICAgICAqICAgICAgICAgIC8vIHVzZSB0aGUgUnVuIFNlcnZpY2Ugb2JqZWN0XG4gICAgICogICAgICAgICAgcm0ucnVuLmRvKCdydW5Nb2RlbCcpO1xuICAgICAqICAgICAgfSk7XG4gICAgICpcbiAgICAgKiAgICAgIHJtLmdldFJ1bihbJ3NhbXBsZV9pbnQnXSkudGhlbihmdW5jdGlvbiAocnVuKSB7XG4gICAgICogICAgICAgICAvLyBhbiBvYmplY3Qgd2hvc2UgZmllbGRzIGFyZSB0aGUgbmFtZSA6IHZhbHVlIHBhaXJzIG9mIHRoZSB2YXJpYWJsZXMgcGFzc2VkIHRvIGdldFJ1bigpXG4gICAgICogICAgICAgICBjb25zb2xlLmxvZyhydW4udmFyaWFibGVzKTtcbiAgICAgKiAgICAgICAgIC8vIHRoZSB2YWx1ZSBvZiBzYW1wbGVfaW50XG4gICAgICogICAgICAgICBjb25zb2xlLmxvZyhydW4udmFyaWFibGVzLnNhbXBsZV9pbnQpOyBcbiAgICAgKiAgICAgIH0pO1xuICAgICAqXG4gICAgICogQHBhcmFtIHtBcnJheX0gdmFyaWFibGVzIChPcHRpb25hbCkgVGhlIHJ1biBvYmplY3QgaXMgcG9wdWxhdGVkIHdpdGggdGhlIHByb3ZpZGVkIG1vZGVsIHZhcmlhYmxlcywgaWYgcHJvdmlkZWQuIE5vdGU6IGBnZXRSdW4oKWAgZG9lcyBub3QgdGhyb3cgYW4gZXJyb3IgaWYgeW91IHRyeSB0byBnZXQgYSB2YXJpYWJsZSB3aGljaCBkb2Vzbid0IGV4aXN0LiBJbnN0ZWFkLCB0aGUgdmFyaWFibGVzIGxpc3QgaXMgZW1wdHksIGFuZCBhbnkgZXJyb3JzIGFyZSBsb2dnZWQgdG8gdGhlIGNvbnNvbGUuXG4gICAgICogQHBhcmFtIHtPYmplY3R9IG9wdGlvbnMgKE9wdGlvbmFsKSBDb25maWd1cmF0aW9uIG9wdGlvbnM7IHBhc3NlZCBvbiB0byBbUnVuU2VydmljZSNjcmVhdGVdKC4uL3J1bi1hcGktc2VydmljZS8jY3JlYXRlKSBpZiB0aGUgc3RyYXRlZ3kgZG9lcyBjcmVhdGUgYSBuZXcgcnVuLlxuICAgICAqIEByZXR1cm4geyRwcm9taXNlfSBQcm9taXNlIHRvIGNvbXBsZXRlIHRoZSBjYWxsLlxuICAgICAqL1xuICAgIGdldFJ1bjogZnVuY3Rpb24gKHZhcmlhYmxlcywgb3B0aW9ucykge1xuICAgICAgICB2YXIgbWUgPSB0aGlzO1xuICAgICAgICB2YXIgc2Vzc2lvblN0b3JlID0gdGhpcy5zZXNzaW9uTWFuYWdlci5nZXRTdG9yZSgpO1xuXG4gICAgICAgIHZhciBzZXNzaW9uQ29udGVudHMgPSBzZXNzaW9uU3RvcmUuZ2V0KHNlc3Npb25LZXlGcm9tT3B0aW9ucyh0aGlzLm9wdGlvbnMsIG1lLnJ1bikpO1xuICAgICAgICB2YXIgcnVuU2Vzc2lvbiA9IEpTT04ucGFyc2Uoc2Vzc2lvbkNvbnRlbnRzIHx8ICd7fScpO1xuICAgICAgICBcbiAgICAgICAgaWYgKHJ1blNlc3Npb24ucnVuSWQpIHtcbiAgICAgICAgICAgIC8vRXBpSlMgPCAyLjIgdXNlZCBydW5JZCBhcyBrZXksIHNvIG1haW50YWluIGNvbXB0YWliaWxpdHkuIFJlbW92ZSBhdCBzb21lIGZ1dHVyZSBkYXRlIChTdW1tZXIgYDE3PylcbiAgICAgICAgICAgIHJ1blNlc3Npb24uaWQgPSBydW5TZXNzaW9uLnJ1bklkO1xuICAgICAgICB9XG5cbiAgICAgICAgdmFyIGF1dGhTZXNzaW9uID0gdGhpcy5zZXNzaW9uTWFuYWdlci5nZXRTZXNzaW9uKCk7XG4gICAgICAgIGlmICh0aGlzLnN0cmF0ZWd5LnJlcXVpcmVzQXV0aCAmJiB1dGlsLmlzRW1wdHkoYXV0aFNlc3Npb24pKSB7XG4gICAgICAgICAgICBjb25zb2xlLmVycm9yKCdObyB1c2VyLXNlc3Npb24gYXZhaWxhYmxlJywgdGhpcy5vcHRpb25zLnN0cmF0ZWd5LCAncmVxdWlyZXMgYXV0aGVudGljYXRpb24uJyk7XG4gICAgICAgICAgICByZXR1cm4gJC5EZWZlcnJlZCgpLnJlamVjdCgnTm8gdXNlci1zZXNzaW9uIGF2YWlsYWJsZScpLnByb21pc2UoKTtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gdGhpcy5zdHJhdGVneVxuICAgICAgICAgICAgICAgIC5nZXRSdW4odGhpcy5ydW4sIGF1dGhTZXNzaW9uLCBydW5TZXNzaW9uLCBvcHRpb25zKS50aGVuKGZ1bmN0aW9uIChydW4pIHtcbiAgICAgICAgICAgICAgICAgICAgaWYgKHJ1biAmJiBydW4uaWQpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIG1lLnJ1bi51cGRhdGVDb25maWcoeyBmaWx0ZXI6IHJ1bi5pZCB9KTtcbiAgICAgICAgICAgICAgICAgICAgICAgIHZhciBzZXNzaW9uS2V5ID0gc2Vzc2lvbktleUZyb21PcHRpb25zKG1lLm9wdGlvbnMsIG1lLnJ1bik7XG4gICAgICAgICAgICAgICAgICAgICAgICBzZXRSdW5JblNlc3Npb24oc2Vzc2lvbktleSwgcnVuLCBtZS5zZXNzaW9uTWFuYWdlcik7XG5cbiAgICAgICAgICAgICAgICAgICAgICAgIGlmICh2YXJpYWJsZXMgJiYgdmFyaWFibGVzLmxlbmd0aCkge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybiBtZS5ydW4udmFyaWFibGVzKCkucXVlcnkodmFyaWFibGVzKS50aGVuKGZ1bmN0aW9uIChyZXN1bHRzKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJ1bi52YXJpYWJsZXMgPSByZXN1bHRzO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICByZXR1cm4gcnVuO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0pLmNhdGNoKGZ1bmN0aW9uIChlcnIpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcnVuLnZhcmlhYmxlcyA9IHt9O1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb25zb2xlLmVycm9yKGVycik7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybiBydW47XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIHJ1bjtcbiAgICAgICAgICAgICAgICB9KTtcbiAgICB9LFxuXG4gICAgLyoqXG4gICAgICogUmV0dXJucyB0aGUgcnVuIG9iamVjdCBmb3IgYSAncmVzZXQnIHJ1bi4gVGhlIGRlZmluaXRpb24gb2YgYSByZXNldCBpcyBkZWZpbmVkIGJ5IHRoZSBzdHJhdGVneSwgYnV0IHR5cGljYWxseSBtZWFucyBmb3JjaW5nIHRoZSBjcmVhdGlvbiBvZiBhIG5ldyBydW4uIEZvciBleGFtcGxlLCBgcmVzZXQoKWAgZm9yIHRoZSBkZWZhdWx0IHN0cmF0ZWdpZXMgYHJldXNlLXBlci1zZXNzaW9uYCBhbmQgYHJldXNlLWxhc3QtaW5pdGlhbGl6ZWRgIGJvdGggY3JlYXRlIG5ldyBydW5zLlxuICAgICAqXG4gICAgICogICoqRXhhbXBsZSoqXG4gICAgICpcbiAgICAgKiAgICAgIHJtLnJlc2V0KCkudGhlbihmdW5jdGlvbiAocnVuKSB7XG4gICAgICogICAgICAgICAgLy8gdXNlIHRoZSAobmV3KSBydW4gb2JqZWN0XG4gICAgICogICAgICAgICAgdmFyIHRoaXNSdW5JZCA9IHJ1bi5pZDtcbiAgICAgKlxuICAgICAqICAgICAgICAgIC8vIHVzZSB0aGUgUnVuIFNlcnZpY2Ugb2JqZWN0XG4gICAgICogICAgICAgICAgcm0ucnVuLmRvKCdydW5Nb2RlbCcpO1xuICAgICAqICAgICAgfSk7XG4gICAgICpcbiAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAqIEBwYXJhbSB7T2JqZWN0fSBvcHRpb25zIChPcHRpb25hbCkgQ29uZmlndXJhdGlvbiBvcHRpb25zOyBwYXNzZWQgb24gdG8gW1J1blNlcnZpY2UjY3JlYXRlXSguLi9ydW4tYXBpLXNlcnZpY2UvI2NyZWF0ZSkuXG4gICAgICogQHJldHVybiB7UHJvbWlzZX1cbiAgICAgKi9cbiAgICByZXNldDogZnVuY3Rpb24gKG9wdGlvbnMpIHtcbiAgICAgICAgdmFyIG1lID0gdGhpcztcbiAgICAgICAgdmFyIGF1dGhTZXNzaW9uID0gdGhpcy5zZXNzaW9uTWFuYWdlci5nZXRTZXNzaW9uKCk7XG4gICAgICAgIGlmICh0aGlzLnN0cmF0ZWd5LnJlcXVpcmVzQXV0aCAmJiB1dGlsLmlzRW1wdHkoYXV0aFNlc3Npb24pKSB7XG4gICAgICAgICAgICBjb25zb2xlLmVycm9yKCdObyB1c2VyLXNlc3Npb24gYXZhaWxhYmxlJywgdGhpcy5vcHRpb25zLnN0cmF0ZWd5LCAncmVxdWlyZXMgYXV0aGVudGljYXRpb24uJyk7XG4gICAgICAgICAgICByZXR1cm4gJC5EZWZlcnJlZCgpLnJlamVjdCgnTm8gdXNlci1zZXNzaW9uIGF2YWlsYWJsZScpLnByb21pc2UoKTtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gdGhpcy5zdHJhdGVneS5yZXNldCh0aGlzLnJ1biwgYXV0aFNlc3Npb24sIG9wdGlvbnMpLnRoZW4oZnVuY3Rpb24gKHJ1bikge1xuICAgICAgICAgICAgaWYgKHJ1biAmJiBydW4uaWQpIHtcbiAgICAgICAgICAgICAgICBtZS5ydW4udXBkYXRlQ29uZmlnKHsgZmlsdGVyOiBydW4uaWQgfSk7XG4gICAgICAgICAgICAgICAgdmFyIHNlc3Npb25LZXkgPSBzZXNzaW9uS2V5RnJvbU9wdGlvbnMobWUub3B0aW9ucywgbWUucnVuKTtcbiAgICAgICAgICAgICAgICBzZXRSdW5JblNlc3Npb24oc2Vzc2lvbktleSwgcnVuLmlkLCBtZS5zZXNzaW9uTWFuYWdlcik7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICByZXR1cm4gcnVuO1xuICAgICAgICB9KTtcbiAgICB9XG59O1xuXG5SdW5NYW5hZ2VyLnN0cmF0ZWdpZXMgPSBzdHJhdGVnaWVzO1xubW9kdWxlLmV4cG9ydHMgPSBSdW5NYW5hZ2VyO1xuIiwiJ3VzZSBzdHJpY3QnO1xuXG52YXIgQmFzZSA9IHJlcXVpcmUoJy4vbm9uZS1zdHJhdGVneScpO1xudmFyIGNsYXNzRnJvbSA9IHJlcXVpcmUoJy4uLy4uL3V0aWwvaW5oZXJpdCcpO1xuXG4vKipcbiogIyMgQ29uZGl0aW9uYWwgQ3JlYXRpb24gU3RyYXRlZ3lcbipcbiogVGhpcyBzdHJhdGVneSB3aWxsIHRyeSB0byBnZXQgdGhlIHJ1biBzdG9yZWQgaW4gdGhlIGNvb2tpZSBhbmRcbiogZXZhbHVhdGUgaWYgaXQgbmVlZHMgdG8gY3JlYXRlIGEgbmV3IHJ1biBieSBjYWxsaW5nIHRoZSBgY29uZGl0aW9uYCBmdW5jdGlvbi5cbiovXG5cbnZhciBTdHJhdGVneSA9IGNsYXNzRnJvbShCYXNlLCB7XG4gICAgY29uc3RydWN0b3I6IGZ1bmN0aW9uIFN0cmF0ZWd5KGNvbmRpdGlvbikge1xuICAgICAgICBpZiAoY29uZGl0aW9uID09IG51bGwpIHsgLy9lc2xpbnQtZGlzYWJsZS1saW5lXG4gICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ0NvbmRpdGlvbmFsIHN0cmF0ZWd5IG5lZWRzIGEgY29uZGl0aW9uIHRvIGNyZWF0ZSBhIHJ1bicpO1xuICAgICAgICB9XG4gICAgICAgIHRoaXMuY29uZGl0aW9uID0gdHlwZW9mIGNvbmRpdGlvbiAhPT0gJ2Z1bmN0aW9uJyA/IGZ1bmN0aW9uICgpIHsgcmV0dXJuIGNvbmRpdGlvbjsgfSA6IGNvbmRpdGlvbjtcbiAgICB9LFxuXG4gICAgLyoqXG4gICAgICogR2V0cyBhIG5ldyAnY29ycmVjdCcgcnVuLCBvciB1cGRhdGVzIHRoZSBleGlzdGluZyBvbmUgKHRoZSBkZWZpbml0aW9uIG9mICdjb3JyZWN0JyBkZXBlbmRzIG9uIHN0cmF0ZWd5IGltcGxlbWVudGF0aW9uKS5cbiAgICAgKiBAcGFyYW0gIHtSdW5TZXJ2aWNlfSBydW5TZXJ2aWNlIEEgUnVuIFNlcnZpY2UgaW5zdGFuY2UgZm9yIHRoZSBjdXJyZW50IHJ1biwgYXMgZGV0ZXJtaW5lZCBieSB0aGUgUnVuIE1hbmFnZXIuXG4gICAgICogQHBhcmFtICB7T2JqZWN0fSB1c2VyU2Vzc2lvbiBJbmZvcm1hdGlvbiBhYm91dCB0aGUgY3VycmVudCB1c2VyIHNlc3Npb24uIFNlZSBbQXV0aE1hbmFnZXIjZ2V0Q3VycmVudFVzZXJTZXNzaW9uSW5mb10oLi4vYXV0aC1tYW5hZ2VyLyNnZXRjdXJyZW50dXNlcnNlc3Npb25pbmZvKSBmb3IgZm9ybWF0LlxuICAgICAqIEBwYXJhbSAge09iamVjdH0gb3B0aW9ucyAoT3B0aW9uYWwpIFNlZSBbUnVuU2VydmljZSNjcmVhdGVdKC4uL3J1bi1hcGktc2VydmljZS8jY3JlYXRlKSBmb3Igc3VwcG9ydGVkIG9wdGlvbnMuXG4gICAgICogQHJldHVybiB7UHJvbWlzZX0gICAgICAgICAgICAgXG4gICAgICovXG4gICAgcmVzZXQ6IGZ1bmN0aW9uIChydW5TZXJ2aWNlLCB1c2VyU2Vzc2lvbiwgb3B0aW9ucykge1xuICAgICAgICB2YXIgZ3JvdXAgPSB1c2VyU2Vzc2lvbiAmJiB1c2VyU2Vzc2lvbi5ncm91cE5hbWU7XG4gICAgICAgIHZhciBvcHQgPSAkLmV4dGVuZCh7XG4gICAgICAgICAgICBzY29wZTogeyBncm91cDogZ3JvdXAgfVxuICAgICAgICB9LCBydW5TZXJ2aWNlLmdldEN1cnJlbnRDb25maWcoKSk7XG5cbiAgICAgICAgcmV0dXJuIHJ1blNlcnZpY2VcbiAgICAgICAgICAgICAgICAuY3JlYXRlKG9wdCwgb3B0aW9ucylcbiAgICAgICAgICAgICAgICAudGhlbihmdW5jdGlvbiAocnVuKSB7XG4gICAgICAgICAgICAgICAgICAgIHJ1bi5mcmVzaGx5Q3JlYXRlZCA9IHRydWU7XG4gICAgICAgICAgICAgICAgICAgIHJldHVybiBydW47XG4gICAgICAgICAgICAgICAgfSk7XG4gICAgfSxcblxuICAgIC8qKlxuICAgICAqIEdldHMgdGhlICdjb3JyZWN0JyBydW4gKHRoZSBkZWZpbml0aW9uIG9mICdjb3JyZWN0JyBkZXBlbmRzIG9uIHN0cmF0ZWd5IGltcGxlbWVudGF0aW9uKS5cbiAgICAgKiBAcGFyYW0gIHtSdW5TZXJ2aWNlfSBydW5TZXJ2aWNlIEEgUnVuIFNlcnZpY2UgaW5zdGFuY2UgZm9yIHRoZSBjdXJyZW50IHJ1biwgYXMgZGV0ZXJtaW5lZCBieSB0aGUgUnVuIE1hbmFnZXIuXG4gICAgICogQHBhcmFtICB7T2JqZWN0fSB1c2VyU2Vzc2lvbiBJbmZvcm1hdGlvbiBhYm91dCB0aGUgY3VycmVudCB1c2VyIHNlc3Npb24uIFNlZSBbQXV0aE1hbmFnZXIjZ2V0Q3VycmVudFVzZXJTZXNzaW9uSW5mb10oLi4vYXV0aC1tYW5hZ2VyLyNnZXRjdXJyZW50dXNlcnNlc3Npb25pbmZvKSBmb3IgZm9ybWF0LlxuICAgICAqIEBwYXJhbSAge09iamVjdH0gcnVuU2Vzc2lvbiBUaGUgUnVuIE1hbmFnZXIgc3RvcmVzIHRoZSAnbGFzdCBhY2Nlc3NlZCcgcnVuIGluIGEgY29va2llIGFuZCBwYXNzZXMgaXQgYmFjayBoZXJlLlxuICAgICAqIEBwYXJhbSAge09iamVjdH0gb3B0aW9ucyAoT3B0aW9uYWwpIFNlZSBbUnVuU2VydmljZSNjcmVhdGVdKC4uL3J1bi1hcGktc2VydmljZS8jY3JlYXRlKSBmb3Igc3VwcG9ydGVkIG9wdGlvbnMuXG4gICAgICogQHJldHVybiB7UHJvbWlzZX0gICAgICAgICAgICAgXG4gICAgICovXG4gICAgZ2V0UnVuOiBmdW5jdGlvbiAocnVuU2VydmljZSwgdXNlclNlc3Npb24sIHJ1blNlc3Npb24sIG9wdGlvbnMpIHtcbiAgICAgICAgdmFyIG1lID0gdGhpcztcbiAgICAgICAgaWYgKHJ1blNlc3Npb24gJiYgcnVuU2Vzc2lvbi5pZCkge1xuICAgICAgICAgICAgcmV0dXJuIHRoaXMubG9hZEFuZENoZWNrKHJ1blNlcnZpY2UsIHVzZXJTZXNzaW9uLCBydW5TZXNzaW9uLCBvcHRpb25zKS5jYXRjaChmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIG1lLnJlc2V0KHJ1blNlcnZpY2UsIHVzZXJTZXNzaW9uLCBvcHRpb25zKTsgLy9pZiBpdCBnb3QgdGhlIHdyb25nIGNvb2tpZSBmb3IgZS5nLlxuICAgICAgICAgICAgfSk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICByZXR1cm4gdGhpcy5yZXNldChydW5TZXJ2aWNlLCB1c2VyU2Vzc2lvbiwgb3B0aW9ucyk7XG4gICAgICAgIH1cbiAgICB9LFxuXG4gICAgbG9hZEFuZENoZWNrOiBmdW5jdGlvbiAocnVuU2VydmljZSwgdXNlclNlc3Npb24sIHJ1blNlc3Npb24sIG9wdGlvbnMpIHtcbiAgICAgICAgdmFyIHNob3VsZENyZWF0ZSA9IGZhbHNlO1xuICAgICAgICB2YXIgbWUgPSB0aGlzO1xuXG4gICAgICAgIHJldHVybiBydW5TZXJ2aWNlXG4gICAgICAgICAgICAubG9hZChydW5TZXNzaW9uLmlkLCBudWxsLCB7XG4gICAgICAgICAgICAgICAgc3VjY2VzczogZnVuY3Rpb24gKHJ1biwgbXNnLCBoZWFkZXJzKSB7XG4gICAgICAgICAgICAgICAgICAgIHNob3VsZENyZWF0ZSA9IG1lLmNvbmRpdGlvbihydW4sIGhlYWRlcnMsIHVzZXJTZXNzaW9uLCBydW5TZXNzaW9uKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9KVxuICAgICAgICAgICAgLnRoZW4oZnVuY3Rpb24gKHJ1bikge1xuICAgICAgICAgICAgICAgIGlmIChzaG91bGRDcmVhdGUpIHtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIG1lLnJlc2V0KHJ1blNlcnZpY2UsIHVzZXJTZXNzaW9uLCBvcHRpb25zKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgcmV0dXJuIHJ1bjtcbiAgICAgICAgICAgIH0pO1xuICAgIH1cbn0pO1xuXG5tb2R1bGUuZXhwb3J0cyA9IFN0cmF0ZWd5O1xuIiwiLyoqXG4gKiBUaGUgYG5ldy1pZi1pbml0aWFsaXplZGAgc3RyYXRlZ3kgY3JlYXRlcyBhIG5ldyBydW4gaWYgdGhlIGN1cnJlbnQgb25lIGlzIGluIG1lbW9yeSBvciBoYXMgaXRzIGBpbml0aWFsaXplZGAgZmllbGQgc2V0IHRvIGB0cnVlYC4gVGhlIGBpbml0aWFsaXplZGAgZmllbGQgaW4gdGhlIHJ1biByZWNvcmQgaXMgYXV0b21hdGljYWxseSBzZXQgdG8gYHRydWVgIGF0IHJ1biBjcmVhdGlvbiwgYnV0IGNhbiBiZSBjaGFuZ2VkLlxuICogXG4gKiBUaGlzIHN0cmF0ZWd5IGlzIHVzZWZ1bCBpZiB5b3VyIHByb2plY3QgaXMgc3RydWN0dXJlZCBzdWNoIHRoYXQgaW1tZWRpYXRlbHkgYWZ0ZXIgYSBydW4gaXMgY3JlYXRlZCwgdGhlIG1vZGVsIGlzIGV4ZWN1dGVkIGNvbXBsZXRlbHkgKGZvciBleGFtcGxlLCBhIFZlbnNpbSBtb2RlbCBpcyBzdGVwcGVkIHRvIHRoZSBlbmQpLiBJdCBpcyBzaW1pbGFyIHRvIHRoZSBgbmV3LWlmLW1pc3NpbmdgIHN0cmF0ZWd5LCBleGNlcHQgdGhhdCBpdCBjaGVja3MgYSBmaWVsZCBvZiB0aGUgcnVuIHJlY29yZC5cbiAqIFxuICogU3BlY2lmaWNhbGx5LCB0aGUgc3RyYXRlZ3kgaXM6XG4gKlxuICogKiBDaGVjayB0aGUgYHNlc3Npb25LZXlgIGNvb2tpZS4gXG4gKiAgKiBUaGlzIGNvb2tpZSBpcyBzZXQgYnkgdGhlIFtSdW4gTWFuYWdlcl0oLi4vcnVuLW1hbmFnZXIvKSBhbmQgY29uZmlndXJhYmxlIHRocm91Z2ggaXRzIG9wdGlvbnMuXG4gKiAgKiBJZiB0aGUgY29va2llIGV4aXN0cywgY2hlY2sgd2hldGhlciB0aGUgcnVuIGlzIGluIG1lbW9yeSBvciBvbmx5IHBlcnNpc3RlZCBpbiB0aGUgZGF0YWJhc2UuIEFkZGl0aW9uYWxseSwgY2hlY2sgd2hldGhlciB0aGUgcnVuJ3MgYGluaXRpYWxpemVkYCBmaWVsZCBpcyBgdHJ1ZWAuIFxuICogICAgICAqIElmIHRoZSBydW4gaXMgaW4gbWVtb3J5LCBjcmVhdGUgYSBuZXcgcnVuLlxuICogICAgICAqIElmIHRoZSBydW4ncyBgaW5pdGlhbGl6ZWRgIGZpZWxkIGlzIGB0cnVlYCwgY3JlYXRlIGEgbmV3IHJ1bi5cbiAqICAgICAgKiBPdGhlcndpc2UsIHVzZSB0aGUgZXhpc3RpbmcgcnVuLlxuICogICogSWYgdGhlIGNvb2tpZSBkb2VzIG5vdCBleGlzdCwgY3JlYXRlIGEgbmV3IHJ1biBmb3IgdGhpcyBlbmQgdXNlci5cbiAqICBcbiAqICBAZGVwcmVjYXRlZCBDb25zaWRlciB1c2luZyBgcmV1c2UtbGFzdC1pbml0aWFsaXplZGAgaW5zdGVhZFxuICovXG5cbid1c2Ugc3RyaWN0JztcbnZhciBjbGFzc0Zyb20gPSByZXF1aXJlKCcuLi8uLi8uLi91dGlsL2luaGVyaXQnKTtcbnZhciBDb25kaXRpb25hbFN0cmF0ZWd5ID0gcmVxdWlyZSgnLi4vY29uZGl0aW9uYWwtY3JlYXRpb24tc3RyYXRlZ3knKTtcblxudmFyIF9fc3VwZXIgPSBDb25kaXRpb25hbFN0cmF0ZWd5LnByb3RvdHlwZTtcblxudmFyIFN0cmF0ZWd5ID0gY2xhc3NGcm9tKENvbmRpdGlvbmFsU3RyYXRlZ3ksIHtcbiAgICBjb25zdHJ1Y3RvcjogZnVuY3Rpb24gKG9wdGlvbnMpIHtcbiAgICAgICAgX19zdXBlci5jb25zdHJ1Y3Rvci5jYWxsKHRoaXMsIHRoaXMuY3JlYXRlSWYsIG9wdGlvbnMpO1xuICAgICAgICBjb25zb2xlLndhcm4oJ1RoaXMgc3RyYXRlZ3kgaXMgZGVwcmVjYXRlZDsgYWxsIHJ1bnMgbm93IGRlZmF1bHQgdG8gYmVpbmcgaW5pdGlhbGl6ZWQgYnkgZGVmYXVsdCBtYWtpbmcgdGhpcyByZWR1bmRhbnQuIENvbnNpZGVyIHVzaW5nIGByZXVzZS1sYXN0LWluaXRpYWxpemVkYCBpbnN0ZWFkLicpO1xuICAgIH0sXG5cbiAgICBjcmVhdGVJZjogZnVuY3Rpb24gKHJ1biwgaGVhZGVycykge1xuICAgICAgICByZXR1cm4gaGVhZGVycy5nZXRSZXNwb25zZUhlYWRlcigncHJhZ21hJykgPT09ICdwZXJzaXN0ZW50JyB8fCBydW4uaW5pdGlhbGl6ZWQ7XG4gICAgfVxufSk7XG5cbm1vZHVsZS5leHBvcnRzID0gU3RyYXRlZ3k7XG4iLCIvKipcbiAqIFRoZSBgbmV3LWlmLXBlcnNpc3RlZGAgc3RyYXRlZ3kgY3JlYXRlcyBhIG5ldyBydW4gd2hlbiB0aGUgY3VycmVudCBvbmUgYmVjb21lcyBwZXJzaXN0ZWQgKGVuZCB1c2VyIGlzIGlkbGUgZm9yIGEgc2V0IHBlcmlvZCksIGJ1dCBvdGhlcndpc2UgdXNlcyB0aGUgY3VycmVudCBvbmUuIFxuICogXG4gKiBVc2luZyB0aGlzIHN0cmF0ZWd5IG1lYW5zIHRoYXQgd2hlbiBlbmQgdXNlcnMgbmF2aWdhdGUgYmV0d2VlbiBwYWdlcyBpbiB5b3VyIHByb2plY3QsIG9yIHJlZnJlc2ggdGhlaXIgYnJvd3NlcnMsIHRoZXkgd2lsbCBzdGlsbCBiZSB3b3JraW5nIHdpdGggdGhlIHNhbWUgcnVuLiBcbiAqIFxuICogSG93ZXZlciwgaWYgdGhleSBhcmUgaWRsZSBmb3IgbG9uZ2VyIHRoYW4geW91ciBwcm9qZWN0J3MgKipNb2RlbCBTZXNzaW9uIFRpbWVvdXQqKiAoY29uZmlndXJlZCBpbiB5b3VyIHByb2plY3QncyBbU2V0dGluZ3NdKC4uLy4uLy4uL3VwZGF0aW5nX3lvdXJfc2V0dGluZ3MvKSksIHRoZW4gdGhlaXIgcnVuIGlzIHBlcnNpc3RlZDsgdGhlIG5leHQgdGltZSB0aGV5IGludGVyYWN0IHdpdGggdGhlIHByb2plY3QsIHRoZXkgd2lsbCBnZXQgYSBuZXcgcnVuLiAoU2VlIG1vcmUgYmFja2dyb3VuZCBvbiBbUnVuIFBlcnNpc3RlbmNlXSguLi8uLi8uLi9ydW5fcGVyc2lzdGVuY2UvKS4pXG4gKiBcbiAqIFRoaXMgc3RyYXRlZ3kgaXMgdXNlZnVsIGZvciBtdWx0aS1wYWdlIHByb2plY3RzIHdoZXJlIGVuZCB1c2VycyBwbGF5IHRocm91Z2ggYSBzaW11bGF0aW9uIGluIG9uZSBzaXR0aW5nLCBzdGVwcGluZyB0aHJvdWdoIHRoZSBtb2RlbCBzZXF1ZW50aWFsbHkgKGZvciBleGFtcGxlLCBhIFZlbnNpbSBtb2RlbCB0aGF0IHVzZXMgdGhlIGBzdGVwYCBvcGVyYXRpb24pIG9yIGNhbGxpbmcgc3BlY2lmaWMgZnVuY3Rpb25zIHVudGlsIHRoZSBtb2RlbCBpcyBcImNvbXBsZXRlLlwiIEhvd2V2ZXIsIHlvdSB3aWxsIG5lZWQgdG8gZ3VhcmFudGVlIHRoYXQgeW91ciBlbmQgdXNlcnMgd2lsbCByZW1haW4gZW5nYWdlZCB3aXRoIHRoZSBwcm9qZWN0IGZyb20gYmVnaW5uaW5nIHRvIGVuZCAmbWRhc2g7IG9yIGF0IGxlYXN0LCB0aGF0IGlmIHRoZXkgYXJlIGlkbGUgZm9yIGxvbmdlciB0aGFuIHRoZSAqKk1vZGVsIFNlc3Npb24gVGltZW91dCoqLCBpdCBpcyBva2F5IGZvciB0aGVtIHRvIHN0YXJ0IHRoZSBwcm9qZWN0IGZyb20gc2NyYXRjaCAod2l0aCBhbiB1bmluaXRpYWxpemVkIG1vZGVsKS4gXG4gKiBcbiAqIFNwZWNpZmljYWxseSwgdGhlIHN0cmF0ZWd5IGlzOlxuICpcbiAqICogQ2hlY2sgdGhlIGBzZXNzaW9uS2V5YCBjb29raWUuXG4gKiAgICogVGhpcyBjb29raWUgaXMgc2V0IGJ5IHRoZSBbUnVuIE1hbmFnZXJdKC4uL3J1bi1tYW5hZ2VyLykgYW5kIGNvbmZpZ3VyYWJsZSB0aHJvdWdoIGl0cyBvcHRpb25zLlxuICogICAqIElmIHRoZSBjb29raWUgZXhpc3RzLCBjaGVjayB3aGV0aGVyIHRoZSBydW4gaXMgaW4gbWVtb3J5IG9yIG9ubHkgcGVyc2lzdGVkIGluIHRoZSBkYXRhYmFzZS4gXG4gKiAgICAgICogSWYgdGhlIHJ1biBpcyBpbiBtZW1vcnksIHVzZSB0aGUgcnVuLlxuICogICAgICAqIElmIHRoZSBydW4gaXMgb25seSBwZXJzaXN0ZWQgKGFuZCBub3Qgc3RpbGwgaW4gbWVtb3J5KSwgY3JlYXRlIGEgbmV3IHJ1biBmb3IgdGhpcyBlbmQgdXNlci5cbiAqICAgICAgKiBJZiB0aGUgY29va2llIGRvZXMgbm90IGV4aXN0LCBjcmVhdGUgYSBuZXcgcnVuIGZvciB0aGlzIGVuZCB1c2VyLlxuICpcbiAqIEBkZXByZWNhdGVkIFRoZSBydW4tc2VydmljZSBub3cgc2V0cyBhIGhlYWRlciB0byBhdXRvbWF0aWNhbGx5IGJyaW5nIGJhY2sgcnVucyBpbnRvIG1lbW9yeVxuICovXG5cbid1c2Ugc3RyaWN0JztcbnZhciBjbGFzc0Zyb20gPSByZXF1aXJlKCcuLi8uLi8uLi91dGlsL2luaGVyaXQnKTtcbnZhciBDb25kaXRpb25hbFN0cmF0ZWd5ID0gcmVxdWlyZSgnLi4vY29uZGl0aW9uYWwtY3JlYXRpb24tc3RyYXRlZ3knKTtcblxudmFyIF9fc3VwZXIgPSBDb25kaXRpb25hbFN0cmF0ZWd5LnByb3RvdHlwZTtcblxudmFyIFN0cmF0ZWd5ID0gY2xhc3NGcm9tKENvbmRpdGlvbmFsU3RyYXRlZ3ksIHtcbiAgICBjb25zdHJ1Y3RvcjogZnVuY3Rpb24gKG9wdGlvbnMpIHtcbiAgICAgICAgX19zdXBlci5jb25zdHJ1Y3Rvci5jYWxsKHRoaXMsIHRoaXMuY3JlYXRlSWYsIG9wdGlvbnMpO1xuICAgICAgICBjb25zb2xlLndhcm4oJ1RoaXMgc3RyYXRlZ3kgaXMgZGVwcmVjYXRlZDsgdGhlIHJ1bi1zZXJ2aWNlIG5vdyBzZXRzIGEgaGVhZGVyIHRvIGF1dG9tYXRpY2FsbHkgYnJpbmcgYmFjayBydW5zIGludG8gbWVtb3J5Jyk7XG4gICAgfSxcblxuICAgIGNyZWF0ZUlmOiBmdW5jdGlvbiAocnVuLCBoZWFkZXJzKSB7XG4gICAgICAgIHJldHVybiBoZWFkZXJzLmdldFJlc3BvbnNlSGVhZGVyKCdwcmFnbWEnKSA9PT0gJ3BlcnNpc3RlbnQnO1xuICAgIH1cbn0pO1xuXG5tb2R1bGUuZXhwb3J0cyA9IFN0cmF0ZWd5O1xuIiwiLyoqXG4gKiAjIyMgV29ya2luZyB3aXRoIFJ1biBTdHJhdGVnaWVzXG4gKlxuICogWW91IGNhbiBhY2Nlc3MgYSBsaXN0IG9mIGF2YWlsYWJsZSBzdHJhdGVnaWVzIHVzaW5nIGBGLm1hbmFnZXIuUnVuTWFuYWdlci5zdHJhdGVnaWVzLmxpc3RgLiBZb3UgY2FuIGFsc28gYXNrIGZvciBhIHBhcnRpY3VsYXIgc3RyYXRlZ3kgYnkgbmFtZS5cbiAqXG4gKiBJZiB5b3UgZGVjaWRlIHRvIFtjcmVhdGUgeW91ciBvd24gcnVuIHN0cmF0ZWd5XSgjY3JlYXRlLXlvdXItb3duKSwgeW91IGNhbiByZWdpc3RlciB5b3VyIHN0cmF0ZWd5LiBSZWdpc3RlcmluZyB5b3VyIHN0cmF0ZWd5IG1lYW5zIHRoYXQ6XG4gKlxuICogKiBZb3UgY2FuIHBhc3MgdGhlIHN0cmF0ZWd5IGJ5IG5hbWUgdG8gYSBSdW4gTWFuYWdlciAoYXMgb3Bwb3NlZCB0byBwYXNzaW5nIHRoZSBzdHJhdGVneSBmdW5jdGlvbik6IGBuZXcgRi5tYW5hZ2VyLlJ1bk1hbmFnZXIoeyBzdHJhdGVneTogJ215bmV3bmFtZSd9KWAuXG4gKiAqIFlvdSBjYW4gcGFzcyBjb25maWd1cmF0aW9uIG9wdGlvbnMgdG8geW91ciBzdHJhdGVneS5cbiAqICogWW91IGNhbiBzcGVjaWZ5IHdoZXRoZXIgb3Igbm90IHlvdXIgc3RyYXRlZ3kgcmVxdWlyZXMgYXV0aG9yaXphdGlvbiAoYSB2YWxpZCB1c2VyIHNlc3Npb24pIHRvIHdvcmsuXG4gKi9cblxuXG52YXIgbGlzdCA9IHtcbiAgICAnY29uZGl0aW9uYWwtY3JlYXRpb24nOiByZXF1aXJlKCcuL2NvbmRpdGlvbmFsLWNyZWF0aW9uLXN0cmF0ZWd5JyksXG4gICAgJ25ldy1pZi1pbml0aWFsaXplZCc6IHJlcXVpcmUoJy4vZGVwcmVjYXRlZC9uZXctaWYtaW5pdGlhbGl6ZWQtc3RyYXRlZ3knKSwgLy9kZXByZWNhdGVkXG4gICAgJ25ldy1pZi1wZXJzaXN0ZWQnOiByZXF1aXJlKCcuL2RlcHJlY2F0ZWQvbmV3LWlmLXBlcnNpc3RlZC1zdHJhdGVneScpLCAvL2RlcHJlY2F0ZWRcblxuICAgIG5vbmU6IHJlcXVpcmUoJy4vbm9uZS1zdHJhdGVneScpLFxuXG4gICAgbXVsdGlwbGF5ZXI6IHJlcXVpcmUoJy4vbXVsdGlwbGF5ZXItc3RyYXRlZ3knKSxcbiAgICAncmV1c2UtbmV2ZXInOiByZXF1aXJlKCcuL3JldXNlLW5ldmVyJyksXG4gICAgJ3JldXNlLXBlci1zZXNzaW9uJzogcmVxdWlyZSgnLi9yZXVzZS1wZXItc2Vzc2lvbicpLFxuICAgICdyZXVzZS1hY3Jvc3Mtc2Vzc2lvbnMnOiByZXF1aXJlKCcuL3JldXNlLWFjcm9zcy1zZXNzaW9ucycpLFxuICAgICdyZXVzZS1sYXN0LWluaXRpYWxpemVkJzogcmVxdWlyZSgnLi9yZXVzZS1sYXN0LWluaXRpYWxpemVkJyksXG59O1xuXG4vL0FkZCBiYWNrIG9sZGVyIGFsaWFzZXNcbmxpc3RbJ2Fsd2F5cy1uZXcnXSA9IGxpc3RbJ3JldXNlLW5ldmVyJ107XG5saXN0WyduZXctaWYtbWlzc2luZyddID0gbGlzdFsncmV1c2UtcGVyLXNlc3Npb24nXTtcbmxpc3RbJ3BlcnNpc3RlbnQtc2luZ2xlLXBsYXllciddID0gbGlzdFsncmV1c2UtYWNyb3NzLXNlc3Npb25zJ107XG5cblxubW9kdWxlLmV4cG9ydHMgPSB7XG4gICAgLyoqXG4gICAgICogTGlzdCBvZiBhdmFpbGFibGUgc3RyYXRlZ2llcy4gV2l0aGluIHRoaXMgb2JqZWN0LCBlYWNoIGtleSBpcyB0aGUgc3RyYXRlZ3kgbmFtZSBhbmQgdGhlIGFzc29jaWF0ZWQgdmFsdWUgaXMgdGhlIHN0cmF0ZWd5IGNvbnN0cnVjdG9yLlxuICAgICAqIEB0eXBlIHtPYmplY3R9IFxuICAgICAqL1xuICAgIGxpc3Q6IGxpc3QsXG5cbiAgICAvKipcbiAgICAgKiBHZXRzIHN0cmF0ZWd5IGJ5IG5hbWUuXG4gICAgICpcbiAgICAgKiAqKkV4YW1wbGUqKlxuICAgICAqXG4gICAgICogICAgICB2YXIgcmV1c2VTdHJhdCA9IEYubWFuYWdlci5SdW5NYW5hZ2VyLnN0cmF0ZWdpZXMuYnlOYW1lKCdyZXVzZS1hY3Jvc3Mtc2Vzc2lvbnMnKTtcbiAgICAgKiAgICAgIC8vIHNob3dzIHN0cmF0ZWd5IGZ1bmN0aW9uXG4gICAgICogICAgICBjb25zb2xlLmxvZygncmV1c2VTdHJhdCA9ICcsIHJldXNlU3RyYXQpO1xuICAgICAqICAgICAgLy8gY3JlYXRlIGEgbmV3IHJ1biBtYW5hZ2VyIHVzaW5nIHRoaXMgc3RyYXRlZ3lcbiAgICAgKiAgICAgIHZhciBybSA9IG5ldyBGLm1hbmFnZXIuUnVuTWFuYWdlcih7c3RyYXRlZ3k6IHJldXNlU3RyYXQsIHJ1bjogeyBtb2RlbDogJ21vZGVsLnZtZid9IH0pO1xuICAgICAqXG4gICAgICogKipQYXJhbWV0ZXJzKipcbiAgICAgKiBAcGFyYW0gIHtTdHJpbmd9IHN0cmF0ZWd5TmFtZSBOYW1lIG9mIHN0cmF0ZWd5IHRvIGdldC5cbiAgICAgKiBAcmV0dXJuIHtGdW5jdGlvbn0gU3RyYXRlZ3kgZnVuY3Rpb24uXG4gICAgICovXG4gICAgYnlOYW1lOiBmdW5jdGlvbiAoc3RyYXRlZ3lOYW1lKSB7XG4gICAgICAgIHJldHVybiBsaXN0W3N0cmF0ZWd5TmFtZV07XG4gICAgfSxcblxuICAgIGdldEJlc3RTdHJhdGVneTogZnVuY3Rpb24gKG9wdGlvbnMpIHtcbiAgICAgICAgdmFyIHN0cmF0ZWd5ID0gb3B0aW9ucy5zdHJhdGVneTtcbiAgICAgICAgaWYgKCFzdHJhdGVneSkge1xuICAgICAgICAgICAgaWYgKG9wdGlvbnMuc3RyYXRlZ3lPcHRpb25zICYmIG9wdGlvbnMuc3RyYXRlZ3lPcHRpb25zLmluaXRPcGVyYXRpb24pIHtcbiAgICAgICAgICAgICAgICBzdHJhdGVneSA9ICdyZXVzZS1sYXN0LWluaXRpYWxpemVkJztcbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgc3RyYXRlZ3kgPSAncmV1c2UtcGVyLXNlc3Npb24nO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG5cbiAgICAgICAgaWYgKHN0cmF0ZWd5LmdldFJ1bikge1xuICAgICAgICAgICAgcmV0dXJuIHN0cmF0ZWd5O1xuICAgICAgICB9XG4gICAgICAgIHZhciBTdHJhdGVneUN0b3IgPSB0eXBlb2Ygc3RyYXRlZ3kgPT09ICdmdW5jdGlvbicgPyBzdHJhdGVneSA6IHRoaXMuYnlOYW1lKHN0cmF0ZWd5KTtcbiAgICAgICAgaWYgKCFTdHJhdGVneUN0b3IpIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcignU3BlY2lmaWVkIHJ1biBjcmVhdGlvbiBzdHJhdGVneSB3YXMgaW52YWxpZDonLCBzdHJhdGVneSk7XG4gICAgICAgIH1cblxuICAgICAgICB2YXIgc3RyYXRlZ3lJbnN0YW5jZSA9IG5ldyBTdHJhdGVneUN0b3Iob3B0aW9ucyk7XG4gICAgICAgIGlmICghc3RyYXRlZ3lJbnN0YW5jZS5nZXRSdW4gfHwgIXN0cmF0ZWd5SW5zdGFuY2UucmVzZXQpIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcignQWxsIHN0cmF0ZWdpZXMgc2hvdWxkIGltcGxlbWVudCBhIGBnZXRSdW5gIGFuZCBgcmVzZXRgIGludGVyZmFjZScsIG9wdGlvbnMuc3RyYXRlZ3kpO1xuICAgICAgICB9XG4gICAgICAgIHN0cmF0ZWd5SW5zdGFuY2UucmVxdWlyZXNBdXRoID0gU3RyYXRlZ3lDdG9yLnJlcXVpcmVzQXV0aDtcblxuICAgICAgICByZXR1cm4gc3RyYXRlZ3lJbnN0YW5jZTtcbiAgICB9LFxuXG4gICAgLyoqXG4gICAgICogQWRkcyBhIG5ldyBzdHJhdGVneS5cbiAgICAgKlxuICAgICAqICoqRXhhbXBsZSoqXG4gICAgICpcbiAgICAgKiAgICAgIC8vIHRoaXMgXCJmYXZvcml0ZSBydW5cIiBzdHJhdGVneSBhbHdheXMgcmV0dXJucyB0aGUgc2FtZSBydW4sIG5vIG1hdHRlciB3aGF0XG4gICAgICogICAgICAvLyAobm90IGEgdXNlZnVsIHN0cmF0ZWd5LCBleGNlcHQgYXMgYW4gZXhhbXBsZSlcbiAgICAgKiAgICAgIEYubWFuYWdlci5SdW5NYW5hZ2VyLnN0cmF0ZWdpZXMucmVnaXN0ZXIoXG4gICAgICogICAgICAgICAgJ2ZhdlJ1bicsIFxuICAgICAqICAgICAgICAgIGZ1bmN0aW9uKCkgeyBcbiAgICAgKiAgICAgICAgICAgICAgcmV0dXJuIHsgZ2V0UnVuOiBmdW5jdGlvbigpIHsgcmV0dXJuICcwMDAwMDE1YTRjZDE3MDAyMDljZDBhN2QyMDdmNDRiYWMyODknOyB9LFxuICAgICAqICAgICAgICAgICAgICAgICAgICAgIHJlc2V0OiBmdW5jdGlvbigpIHsgcmV0dXJuICcwMDAwMDE1YTRjZDE3MDAyMDljZDBhN2QyMDdmNDRiYWMyODknOyB9IFxuICAgICAqICAgICAgICAgICAgICB9IFxuICAgICAqICAgICAgICAgIH0sIFxuICAgICAqICAgICAgICAgIHsgcmVxdWlyZXNBdXRoOiB0cnVlIH1cbiAgICAgKiAgICAgICk7XG4gICAgICogICAgICBcbiAgICAgKiAgICAgIHZhciBybSA9IG5ldyBGLm1hbmFnZXIuUnVuTWFuYWdlcih7c3RyYXRlZ3k6ICdmYXZSdW4nLCBydW46IHsgbW9kZWw6ICdtb2RlbC52bWYnfSB9KTtcbiAgICAgKlxuICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICogQHBhcmFtICB7U3RyaW5nfSBuYW1lIE5hbWUgZm9yIHN0cmF0ZWd5LiBUaGlzIHN0cmluZyBjYW4gdGhlbiBiZSBwYXNzZWQgdG8gYSBSdW4gTWFuYWdlciBhcyBgbmV3IEYubWFuYWdlci5SdW5NYW5hZ2VyKHsgc3RyYXRlZ3k6ICdteW5ld25hbWUnfSlgLlxuICAgICAqIEBwYXJhbSAge0Z1bmN0aW9ufSBzdHJhdGVneSBUaGUgc3RyYXRlZ3kgY29uc3RydWN0b3IuIFdpbGwgYmUgY2FsbGVkIHdpdGggYG5ld2Agb24gUnVuIE1hbmFnZXIgaW5pdGlhbGl6YXRpb24uXG4gICAgICogQHBhcmFtICB7T2JqZWN0fSBvcHRpb25zICBPcHRpb25zIGZvciBzdHJhdGVneS5cbiAgICAgKiBAcGFyYW0gIHtCb29sZWFufSBvcHRpb25zLnJlcXVpcmVzQXV0aCBTcGVjaWZ5IGlmIHRoZSBzdHJhdGVneSByZXF1aXJlcyBhIHZhbGlkIHVzZXIgc2Vzc2lvbiB0byB3b3JrLlxuICAgICAqL1xuICAgIHJlZ2lzdGVyOiBmdW5jdGlvbiAobmFtZSwgc3RyYXRlZ3ksIG9wdGlvbnMpIHtcbiAgICAgICAgc3RyYXRlZ3kub3B0aW9ucyA9IG9wdGlvbnM7XG4gICAgICAgIGxpc3RbbmFtZV0gPSBzdHJhdGVneTtcbiAgICB9XG59OyIsIi8qKlxuICogVGhlIGBtdWx0aXBsYXllcmAgc3RyYXRlZ3kgaXMgZm9yIHVzZSB3aXRoIFttdWx0aXBsYXllciB3b3JsZHNdKC4uLy4uLy4uL2dsb3NzYXJ5LyN3b3JsZCkuIEl0IGNoZWNrcyB0aGUgY3VycmVudCB3b3JsZCBmb3IgdGhpcyBlbmQgdXNlciwgYW5kIGFsd2F5cyByZXR1cm5zIHRoZSBjdXJyZW50IHJ1biBmb3IgdGhhdCB3b3JsZC4gVGhpcyBpcyBlcXVpdmFsZW50IHRvIGNhbGxpbmcgYGdldEN1cnJlbnRXb3JsZEZvclVzZXIoKWAgYW5kIHRoZW4gYGdldEN1cnJlbnRSdW5JZCgpYCBmcm9tIHRoZSBbV29ybGQgQVBJIEFkYXBhdGVyXSguLi93b3JsZC1hcGktYWRhcHRlci8pLiBJZiB5b3UgdXNlIHRoZSBbV29ybGQgTWFuYWdlcl0oLi4vd29ybGQtbWFuYWdlci8pLCB5b3UgYXJlIGF1dG9tYXRpY2FsbHkgdXNpbmcgdGhpcyBzdHJhdGVneS5cbiAqIFxuICogVXNpbmcgdGhpcyBzdHJhdGVneSBtZWFucyB0aGF0IGVuZCB1c2VycyBpbiBwcm9qZWN0cyB3aXRoIG11bHRpcGxheWVyIHdvcmxkcyBhbHdheXMgc2VlIHRoZSBtb3N0IGN1cnJlbnQgd29ybGQgYW5kIHJ1bi4gVGhpcyBlbnN1cmVzIHRoYXQgdGhleSBhcmUgaW4gc3luYyB3aXRoIHRoZSBvdGhlciBlbmQgdXNlcnMgc2hhcmluZyB0aGVpciB3b3JsZCBhbmQgcnVuLiBJbiB0dXJuLCB0aGlzIGFsbG93cyBmb3IgY29tcGV0aXRpdmUgb3IgY29sbGFib3JhdGl2ZSBtdWx0aXBsYXllciBwcm9qZWN0cy5cbiAqL1xuJ3VzZSBzdHJpY3QnO1xuXG52YXIgY2xhc3NGcm9tID0gcmVxdWlyZSgnLi4vLi4vdXRpbC9pbmhlcml0Jyk7XG5cbnZhciBJZGVudGl0eVN0cmF0ZWd5ID0gcmVxdWlyZSgnLi9ub25lLXN0cmF0ZWd5Jyk7XG52YXIgV29ybGRBcGlBZGFwdGVyID0gcmVxdWlyZSgnLi4vLi4vc2VydmljZS93b3JsZC1hcGktYWRhcHRlcicpO1xuXG52YXIgZGVmYXVsdHMgPSB7fTtcblxudmFyIFN0cmF0ZWd5ID0gY2xhc3NGcm9tKElkZW50aXR5U3RyYXRlZ3ksIHtcbiAgICBjb25zdHJ1Y3RvcjogZnVuY3Rpb24gKG9wdGlvbnMpIHtcbiAgICAgICAgdGhpcy5vcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sIGRlZmF1bHRzLCBvcHRpb25zKTtcbiAgICAgICAgdGhpcy53b3JsZEFwaSA9IG5ldyBXb3JsZEFwaUFkYXB0ZXIodGhpcy5vcHRpb25zLnJ1bik7XG4gICAgfSxcblxuICAgIHJlc2V0OiBmdW5jdGlvbiAocnVuU2VydmljZSwgc2Vzc2lvbiwgb3B0aW9ucykge1xuICAgICAgICB2YXIgY3VyVXNlcklkID0gc2Vzc2lvbi51c2VySWQ7XG4gICAgICAgIHZhciBjdXJHcm91cE5hbWUgPSBzZXNzaW9uLmdyb3VwTmFtZTtcblxuICAgICAgICByZXR1cm4gdGhpcy53b3JsZEFwaVxuICAgICAgICAgICAgLmdldEN1cnJlbnRXb3JsZEZvclVzZXIoY3VyVXNlcklkLCBjdXJHcm91cE5hbWUpXG4gICAgICAgICAgICAudGhlbihmdW5jdGlvbiAod29ybGQpIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gdGhpcy53b3JsZEFwaS5uZXdSdW5Gb3JXb3JsZCh3b3JsZC5pZCwgb3B0aW9ucykudGhlbihmdW5jdGlvbiAocnVuaWQpIHtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGlkOiBydW5pZFxuICAgICAgICAgICAgICAgICAgICB9O1xuICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgfS5iaW5kKHRoaXMpKTtcbiAgICB9LFxuXG4gICAgZ2V0UnVuOiBmdW5jdGlvbiAocnVuU2VydmljZSwgc2Vzc2lvbikge1xuICAgICAgICB2YXIgY3VyVXNlcklkID0gc2Vzc2lvbi51c2VySWQ7XG4gICAgICAgIHZhciBjdXJHcm91cE5hbWUgPSBzZXNzaW9uLmdyb3VwTmFtZTtcbiAgICAgICAgdmFyIHdvcmxkQXBpID0gdGhpcy53b3JsZEFwaTtcbiAgICAgICAgdmFyIG1vZGVsID0gdGhpcy5vcHRpb25zLm1vZGVsO1xuICAgICAgICB2YXIgbWUgPSB0aGlzO1xuICAgICAgICB2YXIgZHRkID0gJC5EZWZlcnJlZCgpO1xuXG4gICAgICAgIGlmICghY3VyVXNlcklkKSB7XG4gICAgICAgICAgICByZXR1cm4gZHRkLnJlamVjdCh7IHN0YXR1c0NvZGU6IDQwMCwgZXJyb3I6ICdXZSBuZWVkIGFuIGF1dGhlbnRpY2F0ZWQgdXNlciB0byBqb2luIGEgbXVsdGlwbGF5ZXIgd29ybGQuIChFUlI6IG5vIHVzZXJJZCBpbiBzZXNzaW9uKScgfSwgc2Vzc2lvbikucHJvbWlzZSgpO1xuICAgICAgICB9XG5cbiAgICAgICAgdmFyIGxvYWRSdW5Gcm9tV29ybGQgPSBmdW5jdGlvbiAod29ybGQpIHtcbiAgICAgICAgICAgIGlmICghd29ybGQpIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gZHRkLnJlamVjdCh7IHN0YXR1c0NvZGU6IDQwNCwgZXJyb3I6ICdUaGUgdXNlciBpcyBub3QgaW4gYW55IHdvcmxkLicgfSwgeyBvcHRpb25zOiBtZS5vcHRpb25zLCBzZXNzaW9uOiBzZXNzaW9uIH0pO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgcmV0dXJuIHdvcmxkQXBpLmdldEN1cnJlbnRSdW5JZCh7IG1vZGVsOiBtb2RlbCwgZmlsdGVyOiB3b3JsZC5pZCB9KVxuICAgICAgICAgICAgICAgIC50aGVuKGZ1bmN0aW9uIChpZCkge1xuICAgICAgICAgICAgICAgICAgICByZXR1cm4gcnVuU2VydmljZS5sb2FkKGlkKTtcbiAgICAgICAgICAgICAgICB9KVxuICAgICAgICAgICAgICAgIC50aGVuKGR0ZC5yZXNvbHZlKVxuICAgICAgICAgICAgICAgIC5mYWlsKGR0ZC5yZWplY3QpO1xuICAgICAgICB9O1xuXG4gICAgICAgIHZhciBzZXJ2ZXJFcnJvciA9IGZ1bmN0aW9uIChlcnJvcikge1xuICAgICAgICAgICAgLy8gaXMgdGhpcyBwb3NzaWJsZT9cbiAgICAgICAgICAgIHJldHVybiBkdGQucmVqZWN0KGVycm9yLCBzZXNzaW9uLCBtZS5vcHRpb25zKTtcbiAgICAgICAgfTtcblxuICAgICAgICB0aGlzLndvcmxkQXBpXG4gICAgICAgICAgICAuZ2V0Q3VycmVudFdvcmxkRm9yVXNlcihjdXJVc2VySWQsIGN1ckdyb3VwTmFtZSlcbiAgICAgICAgICAgIC50aGVuKGxvYWRSdW5Gcm9tV29ybGQpXG4gICAgICAgICAgICAuZmFpbChzZXJ2ZXJFcnJvcik7XG5cbiAgICAgICAgcmV0dXJuIGR0ZC5wcm9taXNlKCk7XG4gICAgfSxcblxufSk7XG5cbm1vZHVsZS5leHBvcnRzID0gU3RyYXRlZ3k7XG4iLCIvKipcbiAqIFRoZSBgbm9uZWAgc3RyYXRlZ3kgbmV2ZXIgcmV0dXJucyBhIHJ1biBvciB0cmllcyB0byBjcmVhdGUgYSBuZXcgcnVuLiBJdCBzaW1wbHkgcmV0dXJucyB0aGUgY29udGVudHMgb2YgdGhlIGN1cnJlbnQgW1J1biBTZXJ2aWNlIGluc3RhbmNlXSguLi9ydW4tYXBpLXNlcnZpY2UvKS5cbiAqIFxuICogVGhpcyBzdHJhdGVneSBpcyB1c2VmdWwgaWYgeW91IHdhbnQgdG8gbWFudWFsbHkgZGVjaWRlIGhvdyB0byBjcmVhdGUgeW91ciBvd24gcnVucyBhbmQgZG9uJ3Qgd2FudCBhbnkgYXV0b21hdGljIGFzc2lzdGFuY2UuXG4gKi9cblxuJ3VzZSBzdHJpY3QnO1xuXG52YXIgY2xhc3NGcm9tID0gcmVxdWlyZSgnLi4vLi4vdXRpbC9pbmhlcml0Jyk7XG52YXIgQmFzZSA9IHt9O1xuXG4vLyBJbnRlcmZhY2UgdGhhdCBhbGwgc3RyYXRlZ2llcyBuZWVkIHRvIGltcGxlbWVudFxubW9kdWxlLmV4cG9ydHMgPSBjbGFzc0Zyb20oQmFzZSwge1xuICAgIGNvbnN0cnVjdG9yOiBmdW5jdGlvbiAob3B0aW9ucykge1xuXG4gICAgfSxcblxuICAgIHJlc2V0OiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIC8vIHJldHVybiBhIG5ld2x5IGNyZWF0ZWQgcnVuXG4gICAgICAgIHJldHVybiAkLkRlZmVycmVkKCkucmVzb2x2ZSgpLnByb21pc2UoKTtcbiAgICB9LFxuXG4gICAgZ2V0UnVuOiBmdW5jdGlvbiAocnVuU2VydmljZSkge1xuICAgICAgICAvLyByZXR1cm4gYSB1c2FibGUgcnVuXG4gICAgICAgIHJldHVybiAkLkRlZmVycmVkKCkucmVzb2x2ZShydW5TZXJ2aWNlKS5wcm9taXNlKCk7XG4gICAgfVxufSk7XG4iLCIvKipcbiAqIFRoZSBgcmV1c2UtYWNyb3NzLXNlc3Npb25zYCBzdHJhdGVneSByZXR1cm5zIHRoZSBsYXRlc3QgKG1vc3QgcmVjZW50KSBydW4gZm9yIHRoaXMgdXNlciwgd2hldGhlciBpdCBpcyBpbiBtZW1vcnkgb3Igbm90LiBJZiB0aGVyZSBhcmUgbm8gcnVucyBmb3IgdGhpcyB1c2VyLCBpdCBjcmVhdGVzIGEgbmV3IG9uZS5cbiAqXG4gKiBUaGlzIHN0cmF0ZWd5IGlzIHVzZWZ1bCBpZiBlbmQgdXNlcnMgYXJlIHVzaW5nIHlvdXIgcHJvamVjdCBmb3IgYW4gZXh0ZW5kZWQgcGVyaW9kIG9mIHRpbWUsIHBvc3NpYmx5IG92ZXIgc2V2ZXJhbCBzZXNzaW9ucy4gVGhpcyBpcyBtb3N0IGNvbW1vbiBpbiBjYXNlcyB3aGVyZSBhIHVzZXIgb2YgeW91ciBwcm9qZWN0IGV4ZWN1dGVzIHRoZSBtb2RlbCBzdGVwIGJ5IHN0ZXAgKGFzIG9wcG9zZWQgdG8gYSBwcm9qZWN0IHdoZXJlIHRoZSBtb2RlbCBpcyBleGVjdXRlZCBjb21wbGV0ZWx5LCBmb3IgZXhhbXBsZSwgYSBWZW5zaW0gbW9kZWwgdGhhdCBpcyBpbW1lZGlhdGVseSBzdGVwcGVkIHRvIHRoZSBlbmQpLlxuICpcbiAqIFNwZWNpZmljYWxseSwgdGhlIHN0cmF0ZWd5IGlzOlxuICogXG4gKiAqIENoZWNrIGlmIHRoZXJlIGFyZSBhbnkgcnVucyBmb3IgdGhpcyBlbmQgdXNlci5cbiAqICAgICAqIElmIHRoZXJlIGFyZSBubyBydW5zIChlaXRoZXIgaW4gbWVtb3J5IG9yIGluIHRoZSBkYXRhYmFzZSksIGNyZWF0ZSBhIG5ldyBvbmUuXG4gKiAgICAgKiBJZiB0aGVyZSBhcmUgcnVucywgdGFrZSB0aGUgbGF0ZXN0IChtb3N0IHJlY2VudCkgb25lLlxuICpcbiAqIEBuYW1lIHBlcnNpc3RlbnQtc2luZ2xlLXBsYXllclxuICovXG5cbid1c2Ugc3RyaWN0JztcblxudmFyIGNsYXNzRnJvbSA9IHJlcXVpcmUoJy4uLy4uL3V0aWwvaW5oZXJpdCcpO1xudmFyIElkZW50aXR5U3RyYXRlZ3kgPSByZXF1aXJlKCcuL25vbmUtc3RyYXRlZ3knKTtcbnZhciBpbmplY3RGaWx0ZXJzRnJvbVNlc3Npb24gPSByZXF1aXJlKCcuLi9zdHJhdGVneS11dGlscycpLmluamVjdEZpbHRlcnNGcm9tU2Vzc2lvbjtcbnZhciBpbmplY3RTY29wZUZyb21TZXNzaW9uID0gcmVxdWlyZSgnLi4vc3RyYXRlZ3ktdXRpbHMnKS5pbmplY3RTY29wZUZyb21TZXNzaW9uO1xuXG52YXIgZGVmYXVsdHMgPSB7XG4gICAgLyoqXG4gICAgICogKE9wdGlvbmFsKSBBZGRpdGlvbmFsIGNyaXRlcmlhIHRvIHVzZSB3aGlsZSBzZWxlY3RpbmcgdGhlIGxhc3QgcnVuXG4gICAgICogQHR5cGUge09iamVjdH1cbiAgICAgKi9cbiAgICBmaWx0ZXI6IHt9LFxufTtcblxudmFyIFN0cmF0ZWd5ID0gY2xhc3NGcm9tKElkZW50aXR5U3RyYXRlZ3ksIHtcbiAgICBjb25zdHJ1Y3RvcjogZnVuY3Rpb24gU3RyYXRlZ3kob3B0aW9ucykge1xuICAgICAgICB2YXIgc3RyYXRlZ3lPcHRpb25zID0gb3B0aW9ucyA/IG9wdGlvbnMuc3RyYXRlZ3lPcHRpb25zIDoge307XG4gICAgICAgIHRoaXMub3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LCBkZWZhdWx0cywgc3RyYXRlZ3lPcHRpb25zKTtcbiAgICB9LFxuXG4gICAgcmVzZXQ6IGZ1bmN0aW9uIChydW5TZXJ2aWNlLCB1c2VyU2Vzc2lvbiwgb3B0aW9ucykge1xuICAgICAgICB2YXIgb3B0ID0gaW5qZWN0U2NvcGVGcm9tU2Vzc2lvbihydW5TZXJ2aWNlLmdldEN1cnJlbnRDb25maWcoKSwgdXNlclNlc3Npb24pO1xuICAgICAgICByZXR1cm4gcnVuU2VydmljZVxuICAgICAgICAgICAgLmNyZWF0ZShvcHQsIG9wdGlvbnMpXG4gICAgICAgICAgICAudGhlbihmdW5jdGlvbiAocnVuKSB7XG4gICAgICAgICAgICAgICAgcnVuLmZyZXNobHlDcmVhdGVkID0gdHJ1ZTtcbiAgICAgICAgICAgICAgICByZXR1cm4gcnVuO1xuICAgICAgICAgICAgfSk7XG4gICAgfSxcblxuICAgIGdldFJ1bjogZnVuY3Rpb24gKHJ1blNlcnZpY2UsIHVzZXJTZXNzaW9uLCBydW5TZXNzaW9uLCBvcHRpb25zKSB7XG4gICAgICAgIHZhciBmaWx0ZXIgPSBpbmplY3RGaWx0ZXJzRnJvbVNlc3Npb24odGhpcy5vcHRpb25zLmZpbHRlciwgdXNlclNlc3Npb24pO1xuICAgICAgICB2YXIgbWUgPSB0aGlzO1xuICAgICAgICByZXR1cm4gcnVuU2VydmljZS5xdWVyeShmaWx0ZXIsIHsgXG4gICAgICAgICAgICBzdGFydHJlY29yZDogMCxcbiAgICAgICAgICAgIGVuZHJlY29yZDogMCxcbiAgICAgICAgICAgIHNvcnQ6ICdjcmVhdGVkJywgXG4gICAgICAgICAgICBkaXJlY3Rpb246ICdkZXNjJ1xuICAgICAgICB9KS50aGVuKGZ1bmN0aW9uIChydW5zKSB7XG4gICAgICAgICAgICBpZiAoIXJ1bnMubGVuZ3RoKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIG1lLnJlc2V0KHJ1blNlcnZpY2UsIHVzZXJTZXNzaW9uLCBvcHRpb25zKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHJldHVybiBydW5zWzBdO1xuICAgICAgICB9KTtcbiAgICB9XG59KTtcblxubW9kdWxlLmV4cG9ydHMgPSBTdHJhdGVneTtcbiIsIi8qKlxuICogVGhlIGByZXVzZS1sYXN0LWluaXRpYWxpemVkYCBzdHJhdGVneSBsb29rcyBmb3IgdGhlIG1vc3QgcmVjZW50IHJ1biB0aGF0IG1hdGNoZXMgcGFydGljdWxhciBjcml0ZXJpYTsgaWYgaXQgY2Fubm90IGZpbmQgb25lLCBpdCBjcmVhdGVzIGEgbmV3IHJ1biBhbmQgaW1tZWRpYXRlbHkgZXhlY3V0ZXMgYSBzZXQgb2YgXCJpbml0aWFsaXphdGlvblwiIG9wZXJhdGlvbnMuIFxuICpcbiAqIFRoaXMgc3RyYXRlZ3kgaXMgdXNlZnVsIGlmIHlvdSBoYXZlIGEgdGltZS1iYXNlZCBtb2RlbCBhbmQgYWx3YXlzIHdhbnQgdGhlIHJ1biB5b3UncmUgb3BlcmF0aW5nIG9uIHRvIHN0YXJ0IGF0IGEgcGFydGljdWxhciBzdGVwLiBGb3IgZXhhbXBsZTpcbiAqXG4gKiAgICAgIHZhciBybSA9IG5ldyBGLm1hbmFnZXIuUnVuTWFuYWdlcih7XG4gKiAgICAgICAgICBzdHJhdGVneTogJ3JldXNlLWxhc3QtaW5pdGlhbGl6ZWQnLFxuICogICAgICAgICAgc3RyYXRlZ3lPcHRpb25zOiB7XG4gKiAgICAgICAgICAgICAgaW5pdE9wZXJhdGlvbjogW3sgc3RlcDogMTAgfV1cbiAqICAgICAgICAgIH1cbiAqICAgICAgfSk7XG4gKiBcbiAqIFRoaXMgc3RyYXRlZ3kgaXMgYWxzbyB1c2VmdWwgaWYgeW91IGhhdmUgYSBjdXN0b20gaW5pdGlhbGl6YXRpb24gZnVuY3Rpb24gaW4geW91ciBtb2RlbCwgYW5kIHdhbnQgdG8gbWFrZSBzdXJlIGl0J3MgYWx3YXlzIGV4ZWN1dGVkIGZvciBuZXcgcnVucy5cbiAqXG4gKiBTcGVjaWZpY2FsbHksIHRoZSBzdHJhdGVneSBpczpcbiAqXG4gKiAqIExvb2sgZm9yIHRoZSBtb3N0IHJlY2VudCBydW4gdGhhdCBtYXRjaGVzIHRoZSAob3B0aW9uYWwpIGBmbGFnYCBjcml0ZXJpYVxuICogKiBJZiB0aGVyZSBhcmUgbm8gcnVucyB0aGF0IG1hdGNoIHRoZSBgZmxhZ2AgY3JpdGVyaWEsIGNyZWF0ZSBhIG5ldyBydW4uIEltbWVkaWF0ZWx5IFwiaW5pdGlhbGl6ZVwiIHRoaXMgbmV3IHJ1biBieTpcbiAqICAgICAqICBDYWxsaW5nIHRoZSBtb2RlbCBvcGVyYXRpb24ocykgc3BlY2lmaWVkIGluIHRoZSBgaW5pdE9wZXJhdGlvbmAgYXJyYXkuXG4gKiAgICAgKiAgT3B0aW9uYWxseSwgc2V0dGluZyBhIGBmbGFnYCBpbiB0aGUgcnVuLlxuICpcbiAqL1xuXG4ndXNlIHN0cmljdCc7XG52YXIgY2xhc3NGcm9tID0gcmVxdWlyZSgnLi4vLi4vdXRpbC9pbmhlcml0Jyk7XG52YXIgaW5qZWN0RmlsdGVyc0Zyb21TZXNzaW9uID0gcmVxdWlyZSgnLi4vc3RyYXRlZ3ktdXRpbHMnKS5pbmplY3RGaWx0ZXJzRnJvbVNlc3Npb247XG52YXIgaW5qZWN0U2NvcGVGcm9tU2Vzc2lvbiA9IHJlcXVpcmUoJy4uL3N0cmF0ZWd5LXV0aWxzJykuaW5qZWN0U2NvcGVGcm9tU2Vzc2lvbjtcblxudmFyIEJhc2UgPSB7fTtcblxudmFyIGRlZmF1bHRzID0ge1xuICAgIC8qKlxuICAgICAqIE9wZXJhdGlvbnMgdG8gZXhlY3V0ZSBpbiB0aGUgbW9kZWwgZm9yIGluaXRpYWxpemF0aW9uIHRvIGJlIGNvbnNpZGVyZWQgY29tcGxldGUuXG4gICAgICogQHR5cGUge0FycmF5fSBDYW4gYmUgaW4gYW55IG9mIHRoZSBmb3JtYXRzIFtSdW4gU2VydmljZSdzIGBzZXJpYWwoKWBdKC4uL3J1bi1hcGktc2VydmljZS8jc2VyaWFsKSBzdXBwb3J0cy5cbiAgICAgKi9cbiAgICBpbml0T3BlcmF0aW9uOiBbXSxcblxuICAgIC8qKlxuICAgICAqIChPcHRpb25hbCkgRmxhZyB0byBzZXQgaW4gcnVuIGFmdGVyIGluaXRpYWxpemF0aW9uIG9wZXJhdGlvbnMgYXJlIHJ1bi4gWW91IHR5cGljYWxseSB3b3VsZCBub3Qgb3ZlcnJpZGUgdGhpcyB1bmxlc3MgeW91IG5lZWRlZCB0byBzZXQgYWRkaXRpb25hbCBwcm9wZXJ0aWVzIGFzIHdlbGwuXG4gICAgICogQHR5cGUge09iamVjdH1cbiAgICAgKi9cbiAgICBmbGFnOiBudWxsLFxufTtcbm1vZHVsZS5leHBvcnRzID0gY2xhc3NGcm9tKEJhc2UsIHtcbiAgICBjb25zdHJ1Y3RvcjogZnVuY3Rpb24gKG9wdGlvbnMpIHtcbiAgICAgICAgdmFyIHN0cmF0ZWd5T3B0aW9ucyA9IG9wdGlvbnMgPyBvcHRpb25zLnN0cmF0ZWd5T3B0aW9ucyA6IHt9O1xuICAgICAgICB0aGlzLm9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSwgZGVmYXVsdHMsIHN0cmF0ZWd5T3B0aW9ucyk7XG4gICAgICAgIGlmICghdGhpcy5vcHRpb25zLmluaXRPcGVyYXRpb24gfHwgIXRoaXMub3B0aW9ucy5pbml0T3BlcmF0aW9uLmxlbmd0aCkge1xuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdTcGVjaWZ5aW5nIGFuIGluaXQgZnVuY3Rpb24gaXMgcmVxdWlyZWQgZm9yIHRoaXMgc3RyYXRlZ3knKTtcbiAgICAgICAgfVxuICAgICAgICBpZiAoIXRoaXMub3B0aW9ucy5mbGFnKSB7XG4gICAgICAgICAgICB0aGlzLm9wdGlvbnMuZmxhZyA9IHtcbiAgICAgICAgICAgICAgICBpc0luaXRDb21wbGV0ZTogdHJ1ZVxuICAgICAgICAgICAgfTtcbiAgICAgICAgfVxuICAgIH0sXG5cbiAgICByZXNldDogZnVuY3Rpb24gKHJ1blNlcnZpY2UsIHVzZXJTZXNzaW9uLCBvcHRpb25zKSB7XG4gICAgICAgIHZhciBvcHQgPSBpbmplY3RTY29wZUZyb21TZXNzaW9uKHJ1blNlcnZpY2UuZ2V0Q3VycmVudENvbmZpZygpLCB1c2VyU2Vzc2lvbik7XG4gICAgICAgIHZhciBtZSA9IHRoaXM7XG4gICAgICAgIHJldHVybiBydW5TZXJ2aWNlLmNyZWF0ZShvcHQsIG9wdGlvbnMpLnRoZW4oZnVuY3Rpb24gKGNyZWF0ZVJlc3BvbnNlKSB7XG4gICAgICAgICAgICByZXR1cm4gcnVuU2VydmljZS5zZXJpYWwoW10uY29uY2F0KG1lLm9wdGlvbnMuaW5pdE9wZXJhdGlvbikpLnRoZW4oZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgICAgIHJldHVybiBjcmVhdGVSZXNwb25zZTtcbiAgICAgICAgICAgIH0pO1xuICAgICAgICB9KS50aGVuKGZ1bmN0aW9uIChjcmVhdGVSZXNwb25zZSkge1xuICAgICAgICAgICAgcmV0dXJuIHJ1blNlcnZpY2Uuc2F2ZShtZS5vcHRpb25zLmZsYWcpLnRoZW4oZnVuY3Rpb24gKHBhdGNoUmVzcG9uc2UpIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gJC5leHRlbmQodHJ1ZSwge30sIGNyZWF0ZVJlc3BvbnNlLCBwYXRjaFJlc3BvbnNlKTtcbiAgICAgICAgICAgIH0pO1xuICAgICAgICB9KTtcbiAgICB9LFxuXG4gICAgZ2V0UnVuOiBmdW5jdGlvbiAocnVuU2VydmljZSwgdXNlclNlc3Npb24sIHJ1blNlc3Npb24sIG9wdGlvbnMpIHtcbiAgICAgICAgdmFyIHNlc3Npb25GaWx0ZXIgPSBpbmplY3RGaWx0ZXJzRnJvbVNlc3Npb24odGhpcy5vcHRpb25zLmZsYWcsIHVzZXJTZXNzaW9uKTtcbiAgICAgICAgdmFyIHJ1bm9wdHMgPSBydW5TZXJ2aWNlLmdldEN1cnJlbnRDb25maWcoKTtcbiAgICAgICAgdmFyIGZpbHRlciA9ICQuZXh0ZW5kKHRydWUsIHsgdHJhc2hlZDogZmFsc2UgfSwgc2Vzc2lvbkZpbHRlciwgeyBtb2RlbDogcnVub3B0cy5tb2RlbCB9KTtcbiAgICAgICAgdmFyIG1lID0gdGhpcztcbiAgICAgICAgcmV0dXJuIHJ1blNlcnZpY2UucXVlcnkoZmlsdGVyLCB7IFxuICAgICAgICAgICAgc3RhcnRyZWNvcmQ6IDAsXG4gICAgICAgICAgICBlbmRyZWNvcmQ6IDAsXG4gICAgICAgICAgICBzb3J0OiAnY3JlYXRlZCcsIFxuICAgICAgICAgICAgZGlyZWN0aW9uOiAnZGVzYydcbiAgICAgICAgfSkudGhlbihmdW5jdGlvbiAocnVucykge1xuICAgICAgICAgICAgaWYgKCFydW5zLmxlbmd0aCkge1xuICAgICAgICAgICAgICAgIHJldHVybiBtZS5yZXNldChydW5TZXJ2aWNlLCB1c2VyU2Vzc2lvbiwgb3B0aW9ucyk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICByZXR1cm4gcnVuc1swXTtcbiAgICAgICAgfSk7XG4gICAgfVxufSk7IiwiLyoqXG4gKiBUaGUgYHJldXNlLW5ldmVyYCBzdHJhdGVneSBhbHdheXMgY3JlYXRlcyBhIG5ldyBydW4gZm9yIHRoaXMgZW5kIHVzZXIgaXJyZXNwZWN0aXZlIG9mIGN1cnJlbnQgc3RhdGUuIFRoaXMgaXMgZXF1aXZhbGVudCB0byBjYWxsaW5nIGBGLnNlcnZpY2UuUnVuLmNyZWF0ZSgpYCBmcm9tIHRoZSBbUnVuIFNlcnZpY2VdKC4uL3J1bi1hcGktc2VydmljZS8pIGV2ZXJ5IHRpbWUuIFxuICogXG4gKiBUaGlzIHN0cmF0ZWd5IG1lYW5zIHRoYXQgZXZlcnkgdGltZSB5b3VyIGVuZCB1c2VycyByZWZyZXNoIHRoZWlyIGJyb3dzZXJzLCB0aGV5IGdldCBhIG5ldyBydW4uIFxuICogXG4gKiBUaGlzIHN0cmF0ZWd5IGNhbiBiZSB1c2VmdWwgZm9yIGJhc2ljLCBzaW5nbGUtcGFnZSBwcm9qZWN0cy4gVGhpcyBzdHJhdGVneSBpcyBhbHNvIHVzZWZ1bCBmb3IgcHJvdG90eXBpbmcgb3IgcHJvamVjdCBkZXZlbG9wbWVudDogaXQgY3JlYXRlcyBhIG5ldyBydW4gZWFjaCB0aW1lIHlvdSByZWZyZXNoIHRoZSBwYWdlLCBhbmQgeW91IGNhbiBlYXNpbHkgY2hlY2sgdGhlIG91dHB1dHMgb2YgdGhlIG1vZGVsLiBIb3dldmVyLCB0eXBpY2FsbHkgeW91IHdpbGwgdXNlIG9uZSBvZiB0aGUgb3RoZXIgc3RyYXRlZ2llcyBmb3IgYSBwcm9kdWN0aW9uIHByb2plY3QuXG4gKlxuICogQG5hbWUgYWx3YXlzLW5ld1xuICovXG5cbid1c2Ugc3RyaWN0JztcblxudmFyIGNsYXNzRnJvbSA9IHJlcXVpcmUoJy4uLy4uL3V0aWwvaW5oZXJpdCcpO1xudmFyIENvbmRpdGlvbmFsU3RyYXRlZ3kgPSByZXF1aXJlKCcuL2NvbmRpdGlvbmFsLWNyZWF0aW9uLXN0cmF0ZWd5Jyk7XG5cbnZhciBfX3N1cGVyID0gQ29uZGl0aW9uYWxTdHJhdGVneS5wcm90b3R5cGU7XG5cbnZhciBTdHJhdGVneSA9IGNsYXNzRnJvbShDb25kaXRpb25hbFN0cmF0ZWd5LCB7XG4gICAgY29uc3RydWN0b3I6IGZ1bmN0aW9uIChvcHRpb25zKSB7XG4gICAgICAgIF9fc3VwZXIuY29uc3RydWN0b3IuY2FsbCh0aGlzLCB0aGlzLmNyZWF0ZUlmLCBvcHRpb25zKTtcbiAgICB9LFxuXG4gICAgY3JlYXRlSWY6IGZ1bmN0aW9uIChydW4sIGhlYWRlcnMpIHtcbiAgICAgICAgLy8gYWx3YXlzIGNyZWF0ZSBhIG5ldyBydW4hXG4gICAgICAgIHJldHVybiB0cnVlO1xuICAgIH1cbn0pO1xuXG5tb2R1bGUuZXhwb3J0cyA9IFN0cmF0ZWd5O1xuIiwiLyoqXG4gKiBUaGUgYHJldXNlLXBlci1zZXNzaW9uYCBzdHJhdGVneSBjcmVhdGVzIGEgbmV3IHJ1biB3aGVuIHRoZSBjdXJyZW50IG9uZSBpcyBub3QgaW4gdGhlIGJyb3dzZXIgY29va2llLlxuICogXG4gKiBVc2luZyB0aGlzIHN0cmF0ZWd5IG1lYW5zIHRoYXQgd2hlbiBlbmQgdXNlcnMgbmF2aWdhdGUgYmV0d2VlbiBwYWdlcyBpbiB5b3VyIHByb2plY3QsIG9yIHJlZnJlc2ggdGhlaXIgYnJvd3NlcnMsIHRoZXkgd2lsbCBzdGlsbCBiZSB3b3JraW5nIHdpdGggdGhlIHNhbWUgcnVuLiBIb3dldmVyLCBpZiBlbmQgdXNlcnMgbG9nIG91dCBhbmQgcmV0dXJuIHRvIHRoZSBwcm9qZWN0IGF0IGEgbGF0ZXIgZGF0ZSwgYSBuZXcgcnVuIGlzIGNyZWF0ZWQuXG4gKlxuICogVGhpcyBzdHJhdGVneSBpcyB1c2VmdWwgaWYgeW91ciBwcm9qZWN0IGlzIHN0cnVjdHVyZWQgc3VjaCB0aGF0IGltbWVkaWF0ZWx5IGFmdGVyIGEgcnVuIGlzIGNyZWF0ZWQsIHRoZSBtb2RlbCBpcyBleGVjdXRlZCBjb21wbGV0ZWx5IChmb3IgZXhhbXBsZSwgYSBWZW5zaW0gbW9kZWwgdGhhdCBpcyBzdGVwcGVkIHRvIHRoZSBlbmQgYXMgc29vbiBhcyBpdCBpcyBjcmVhdGVkKS4gSW4gY29udHJhc3QsIGlmIGVuZCB1c2VycyBwbGF5IHdpdGggeW91ciBwcm9qZWN0IGZvciBhbiBleHRlbmRlZCBwZXJpb2Qgb2YgdGltZSwgZXhlY3V0aW5nIHRoZSBtb2RlbCBzdGVwIGJ5IHN0ZXAsIHRoZSBgcmV1c2UtYWNyb3NzLXNlc3Npb25zYCBzdHJhdGVneSBpcyBwcm9iYWJseSBhIGJldHRlciBjaG9pY2UgKGl0IGFsbG93cyBlbmQgdXNlcnMgdG8gcGljayB1cCB3aGVyZSB0aGV5IGxlZnQgb2ZmLCByYXRoZXIgdGhhbiBzdGFydGluZyBmcm9tIHNjcmF0Y2ggZWFjaCBicm93c2VyIHNlc3Npb24pLlxuICogXG4gKiBTcGVjaWZpY2FsbHksIHRoZSBzdHJhdGVneSBpczpcbiAqXG4gKiAqIENoZWNrIHRoZSBgc2Vzc2lvbktleWAgY29va2llLlxuICogICAgICogVGhpcyBjb29raWUgaXMgc2V0IGJ5IHRoZSBbUnVuIE1hbmFnZXJdKC4uL3J1bi1tYW5hZ2VyLykgYW5kIGNvbmZpZ3VyYWJsZSB0aHJvdWdoIGl0cyBvcHRpb25zLiBcbiAqICAgICAqIElmIHRoZSBjb29raWUgZXhpc3RzLCB1c2UgdGhlIHJ1biBpZCBzdG9yZWQgdGhlcmUuIFxuICogICAgICogSWYgdGhlIGNvb2tpZSBkb2VzIG5vdCBleGlzdCwgY3JlYXRlIGEgbmV3IHJ1biBmb3IgdGhpcyBlbmQgdXNlci5cbiAqXG4gKiBAbmFtZSBuZXctaWYtbWlzc2luZ1xuICovXG5cbid1c2Ugc3RyaWN0JztcblxudmFyIGNsYXNzRnJvbSA9IHJlcXVpcmUoJy4uLy4uL3V0aWwvaW5oZXJpdCcpO1xudmFyIENvbmRpdGlvbmFsU3RyYXRlZ3kgPSByZXF1aXJlKCcuL2NvbmRpdGlvbmFsLWNyZWF0aW9uLXN0cmF0ZWd5Jyk7XG5cbnZhciBfX3N1cGVyID0gQ29uZGl0aW9uYWxTdHJhdGVneS5wcm90b3R5cGU7XG5cbi8qXG4qICBjcmVhdGUgYSBuZXcgcnVuIG9ubHkgaWYgbm90aGluZyBpcyBzdG9yZWQgaW4gdGhlIGNvb2tpZVxuKiAgdGhpcyBpcyB1c2VmdWwgZm9yIGJhc2VSdW5zLlxuKi9cbnZhciBTdHJhdGVneSA9IGNsYXNzRnJvbShDb25kaXRpb25hbFN0cmF0ZWd5LCB7XG4gICAgY29uc3RydWN0b3I6IGZ1bmN0aW9uIChvcHRpb25zKSB7XG4gICAgICAgIF9fc3VwZXIuY29uc3RydWN0b3IuY2FsbCh0aGlzLCB0aGlzLmNyZWF0ZUlmLCBvcHRpb25zKTtcbiAgICB9LFxuXG4gICAgY3JlYXRlSWY6IGZ1bmN0aW9uIChydW4sIGhlYWRlcnMpIHtcbiAgICAgICAgLy8gaWYgd2UgYXJlIGhlcmUsIGl0IG1lYW5zIHRoYXQgdGhlIHJ1biBleGlzdHMuLi4gc28gd2UgZG9uJ3QgbmVlZCBhIG5ldyBvbmVcbiAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgIH1cbn0pO1xuXG5tb2R1bGUuZXhwb3J0cyA9IFN0cmF0ZWd5O1xuIiwiLyoqXG4gKiAjIyBTYXZlZCBSdW5zIE1hbmFnZXJcbiAqXG4gKiBUaGUgU2F2ZWQgUnVucyBNYW5hZ2VyIGlzIGEgc3BlY2lmaWMgdHlwZSBvZiBbUnVuIE1hbmFnZXJdKC4uLy4uL3J1bi1tYW5hZ2VyLykgd2hpY2ggcHJvdmlkZXMgYWNjZXNzIHRvIGEgbGlzdCBvZiBydW5zIChyYXRoZXIgdGhhbiBqdXN0IG9uZSBydW4pLiBJdCBhbHNvIHByb3ZpZGVzIHV0aWxpdHkgZnVuY3Rpb25zIGZvciBkZWFsaW5nIHdpdGggbXVsdGlwbGUgcnVucyAoZS5nLiBzYXZpbmcsIGRlbGV0aW5nLCBsaXN0aW5nKS5cbiAqXG4gKiBBbiBpbnN0YW5jZSBvZiBhIFNhdmVkIFJ1bnMgTWFuYWdlciBpcyBpbmNsdWRlZCBhdXRvbWF0aWNhbGx5IGluIGV2ZXJ5IGluc3RhbmNlIG9mIGEgW1NjZW5hcmlvIE1hbmFnZXJdKC4uLyksIGFuZCBpcyBhY2Nlc3NpYmxlIGZyb20gdGhlIFNjZW5hcmlvIE1hbmFnZXIgYXQgYC5zYXZlZFJ1bnNgLiBTZWUgW21vcmUgaW5mb3JtYXRpb25dKC4uLyNwcm9wZXJ0aWVzKSBvbiB1c2luZyBgLnNhdmVkUnVuc2Agd2l0aGluIHRoZSBTY2VuYXJpbyBNYW5hZ2VyLlxuICpcbiAqL1xuJ3VzZSBzdHJpY3QnO1xuXG52YXIgUnVuU2VydmljZSA9IHJlcXVpcmUoJy4uL3NlcnZpY2UvcnVuLWFwaS1zZXJ2aWNlJyk7XG52YXIgU2Vzc2lvbk1hbmFnZXIgPSByZXF1aXJlKCcuLi9zdG9yZS9zZXNzaW9uLW1hbmFnZXInKTtcblxudmFyIGluamVjdEZpbHRlcnNGcm9tU2Vzc2lvbiA9IHJlcXVpcmUoJy4vc3RyYXRlZ3ktdXRpbHMnKS5pbmplY3RGaWx0ZXJzRnJvbVNlc3Npb247XG5cbnZhciBTYXZlZFJ1bnNNYW5hZ2VyID0gZnVuY3Rpb24gKGNvbmZpZykge1xuICAgIHZhciBkZWZhdWx0cyA9IHtcbiAgICAgICAgLyoqXG4gICAgICAgICAqIElmIHNldCwgd2lsbCBvbmx5IHB1bGwgcnVucyBmcm9tIGN1cnJlbnQgZ3JvdXAuIERlZmF1bHRzIHRvIGB0cnVlYC5cbiAgICAgICAgICogQHR5cGUge0Jvb2xlYW59XG4gICAgICAgICAqL1xuICAgICAgICBzY29wZUJ5R3JvdXA6IHRydWUsXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIElmIHNldCwgd2lsbCBvbmx5IHB1bGwgcnVucyBmcm9tIGN1cnJlbnQgdXNlci4gRGVmYXVsdHMgdG8gYHRydWVgLlxuICAgICAgICAgKlxuICAgICAgICAgKiBGb3IgbXVsdGlwbGF5ZXIgcnVuIGNvbXBhcmlzb24gcHJvamVjdHMsIHNldCB0aGlzIHRvIGZhbHNlIHNvIHRoYXQgYWxsIGVuZCB1c2VycyBpbiBhIGdyb3VwIGNhbiB2aWV3IHRoZSBzaGFyZWQgc2V0IG9mIHNhdmVkIHJ1bnMuXG4gICAgICAgICAqIEB0eXBlIHtCb29sZWFufVxuICAgICAgICAgKi9cbiAgICAgICAgc2NvcGVCeVVzZXI6IHRydWUsXG4gICAgfTtcblxuICAgIHRoaXMuc2Vzc2lvbk1hbmFnZXIgPSBuZXcgU2Vzc2lvbk1hbmFnZXIoKTtcblxuICAgIHZhciBvcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sIGRlZmF1bHRzLCBjb25maWcpO1xuICAgIGlmIChvcHRpb25zLnJ1bikge1xuICAgICAgICBpZiAob3B0aW9ucy5ydW4gaW5zdGFuY2VvZiBSdW5TZXJ2aWNlKSB7XG4gICAgICAgICAgICB0aGlzLnJ1blNlcnZpY2UgPSBvcHRpb25zLnJ1bjtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIHRoaXMucnVuU2VydmljZSA9IG5ldyBSdW5TZXJ2aWNlKG9wdGlvbnMucnVuKTtcbiAgICAgICAgfVxuICAgICAgICB0aGlzLm9wdGlvbnMgPSBvcHRpb25zO1xuICAgIH0gZWxzZSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcignTm8gcnVuIG9wdGlvbnMgcGFzc2VkIHRvIFNhdmVkUnVuc01hbmFnZXInKTtcbiAgICB9XG59O1xuXG5TYXZlZFJ1bnNNYW5hZ2VyLnByb3RvdHlwZSA9IHtcbiAgICAvKipcbiAgICAgKiBNYXJrcyBhIHJ1biBhcyBzYXZlZC4gXG4gICAgICpcbiAgICAgKiBOb3RlIHRoYXQgd2hpbGUgYW55IHJ1biBjYW4gYmUgc2F2ZWQsIG9ubHkgcnVucyB3aGljaCBhbHNvIG1hdGNoIHRoZSBjb25maWd1cmF0aW9uIG9wdGlvbnMgYHNjb3BlQnlHcm91cGAgYW5kIGBzY29wZUJ5VXNlcmAgYXJlIHJldHVybmVkIGJ5IHRoZSBgZ2V0UnVucygpYCBtZXRob2QuXG4gICAgICpcbiAgICAgKiAqKkV4YW1wbGUqKlxuICAgICAqXG4gICAgICogICAgICB2YXIgc20gPSBuZXcgRi5tYW5hZ2VyLlNjZW5hcmlvTWFuYWdlcigpO1xuICAgICAqICAgICAgc20uc2F2ZWRSdW5zLnNhdmUoJzAwMDAwMTVhNGNkMTcwMDIwOWNkMGE3ZDIwN2Y0NGJhYzI4OScpO1xuICAgICAqXG4gICAgICogQHBhcmFtICB7U3RyaW5nfFJ1blNlcnZpY2V9IHJ1biBSdW4gdG8gc2F2ZS4gUGFzcyBpbiBlaXRoZXIgdGhlIHJ1biBpZCwgYXMgYSBzdHJpbmcsIG9yIHRoZSBbUnVuIFNlcnZpY2VdKC4uLy4uL3J1bi1hcGktc2VydmljZS8pLlxuICAgICAqIEBwYXJhbSAge09iamVjdH0gb3RoZXJGaWVsZHMgKE9wdGlvbmFsKSBBbnkgb3RoZXIgbWV0YS1kYXRhIHRvIHNhdmUgd2l0aCB0aGUgcnVuLlxuICAgICAqIEByZXR1cm4ge1Byb21pc2V9XG4gICAgICovXG4gICAgc2F2ZTogZnVuY3Rpb24gKHJ1biwgb3RoZXJGaWVsZHMpIHtcbiAgICAgICAgdmFyIHBhcmFtID0gJC5leHRlbmQodHJ1ZSwge30sIG90aGVyRmllbGRzLCB7IHNhdmVkOiB0cnVlLCB0cmFzaGVkOiBmYWxzZSB9KTtcbiAgICAgICAgcmV0dXJuIHRoaXMubWFyayhydW4sIHBhcmFtKTtcbiAgICB9LFxuICAgIC8qKlxuICAgICAqIE1hcmtzIGEgcnVuIGFzIHJlbW92ZWQ7IHRoZSBpbnZlcnNlIG9mIG1hcmtpbmcgYXMgc2F2ZWQuXG4gICAgICpcbiAgICAgKiAqKkV4YW1wbGUqKlxuICAgICAqXG4gICAgICogICAgICB2YXIgc20gPSBuZXcgRi5tYW5hZ2VyLlNjZW5hcmlvTWFuYWdlcigpO1xuICAgICAqICAgICAgc20uc2F2ZWRSdW5zLnJlbW92ZSgnMDAwMDAxNWE0Y2QxNzAwMjA5Y2QwYTdkMjA3ZjQ0YmFjMjg5Jyk7XG4gICAgICpcbiAgICAgKiBAcGFyYW0gIHtTdHJpbmd8UnVuU2VydmljZX0gcnVuIFJ1biB0byByZW1vdmUuIFBhc3MgaW4gZWl0aGVyIHRoZSBydW4gaWQsIGFzIGEgc3RyaW5nLCBvciB0aGUgW1J1biBTZXJ2aWNlXSguLi8uLi9ydW4tYXBpLXNlcnZpY2UvKS5cbiAgICAgKiBAcGFyYW0gIHtPYmplY3R9IG90aGVyRmllbGRzIChPcHRpb25hbCkgYW55IG90aGVyIG1ldGEtZGF0YSB0byBzYXZlIHdpdGggdGhlIHJ1bi5cbiAgICAgKiBAcmV0dXJuIHtQcm9taXNlfVxuICAgICAqL1xuICAgIHJlbW92ZTogZnVuY3Rpb24gKHJ1biwgb3RoZXJGaWVsZHMpIHtcbiAgICAgICAgdmFyIHBhcmFtID0gJC5leHRlbmQodHJ1ZSwge30sIG90aGVyRmllbGRzLCB7IHNhdmVkOiBmYWxzZSwgdHJhc2hlZDogdHJ1ZSB9KTtcbiAgICAgICAgcmV0dXJuIHRoaXMubWFyayhydW4sIHBhcmFtKTtcbiAgICB9LFxuXG5cbiAgICAvKipcbiAgICAgKiBTZXRzIGFkZGl0aW9uYWwgZmllbGRzIG9uIGEgcnVuLiBUaGlzIGlzIGEgY29udmVuaWVuY2UgbWV0aG9kIGZvciBbUnVuU2VydmljZSNzYXZlXSguLi8uLi9ydW4tYXBpLXNlcnZpY2UvI3NhdmUpLlxuICAgICAqXG4gICAgICogKipFeGFtcGxlKipcbiAgICAgKlxuICAgICAqICAgICAgdmFyIHNtID0gbmV3IEYubWFuYWdlci5TY2VuYXJpb01hbmFnZXIoKTtcbiAgICAgKiAgICAgIHNtLnNhdmVkUnVucy5tYXJrKCcwMDAwMDE1YTRjZDE3MDAyMDljZDBhN2QyMDdmNDRiYWMyODknLCBcbiAgICAgKiAgICAgICAgICB7ICdteVJ1bk5hbWUnOiAnc2FtcGxlIHBvbGljeSBkZWNpc2lvbnMnIH0pO1xuICAgICAqXG4gICAgICogQHBhcmFtICB7U3RyaW5nfFJ1blNlcnZpY2V9IHJ1biAgUnVuIHRvIG9wZXJhdGUgb24uIFBhc3MgaW4gZWl0aGVyIHRoZSBydW4gaWQsIGFzIGEgc3RyaW5nLCBvciB0aGUgW1J1biBTZXJ2aWNlXSguLi8uLi9ydW4tYXBpLXNlcnZpY2UvKS5cbiAgICAgKiBAcGFyYW0gIHtPYmplY3R9IHRvTWFyayBGaWVsZHMgdG8gc2V0LCBhcyBuYW1lIDogdmFsdWUgcGFpcnMuXG4gICAgICogQHJldHVybiB7UHJvbWlzZX1cbiAgICAgKi9cbiAgICBtYXJrOiBmdW5jdGlvbiAocnVuLCB0b01hcmspIHtcbiAgICAgICAgdmFyIHJzO1xuICAgICAgICB2YXIgZXhpc3RpbmdPcHRpb25zID0gdGhpcy5ydW5TZXJ2aWNlLmdldEN1cnJlbnRDb25maWcoKTtcbiAgICAgICAgaWYgKHJ1biBpbnN0YW5jZW9mIFJ1blNlcnZpY2UpIHtcbiAgICAgICAgICAgIHJzID0gcnVuO1xuICAgICAgICB9IGVsc2UgaWYgKHJ1biAmJiAodHlwZW9mIHJ1biA9PT0gJ3N0cmluZycpKSB7XG4gICAgICAgICAgICBycyA9IG5ldyBSdW5TZXJ2aWNlKCQuZXh0ZW5kKHRydWUsIHt9LCBleGlzdGluZ09wdGlvbnMsIHsgaWQ6IHJ1biwgYXV0b1Jlc3RvcmU6IGZhbHNlIH0pKTtcbiAgICAgICAgfSBlbHNlIGlmICgkLmlzQXJyYXkocnVuKSkge1xuICAgICAgICAgICAgdmFyIG1lID0gdGhpcztcbiAgICAgICAgICAgIHZhciBwcm9tcyA9IHJ1bi5tYXAoZnVuY3Rpb24gKHIpIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gbWUubWFyayhyLCB0b01hcmspO1xuICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICByZXR1cm4gJC53aGVuLmFwcGx5KG51bGwsIHByb21zKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcignSW52YWxpZCBydW4gb2JqZWN0IHByb3ZpZGVkJyk7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIHJzLnNhdmUodG9NYXJrKTtcbiAgICB9LFxuXG4gICAgLyoqXG4gICAgICogUmV0dXJucyBhIGxpc3Qgb2Ygc2F2ZWQgcnVucy5cbiAgICAgKlxuICAgICAqICoqRXhhbXBsZSoqXG4gICAgICpcbiAgICAgKiAgICAgIHZhciBzbSA9IG5ldyBGLm1hbmFnZXIuU2NlbmFyaW9NYW5hZ2VyKCk7XG4gICAgICogICAgICBzbS5zYXZlZFJ1bnMuZ2V0UnVucygpLnRoZW4oZnVuY3Rpb24gKHJ1bnMpIHtcbiAgICAgKiAgICAgICAgICBmb3IgKHZhciBpPTA7IGk8cnVucy5sZW5ndGg7IGkrKykge1xuICAgICAqICAgICAgICAgICAgICBjb25zb2xlLmxvZygncnVuIGlkIG9mIHNhdmVkIHJ1bjogJywgcnVuc1tpXS5pZCk7XG4gICAgICogICAgICAgICAgfVxuICAgICAqICAgICAgfSk7XG4gICAgICpcbiAgICAgKiBAcGFyYW0gIHtBcnJheX0gdmFyaWFibGVzIChPcHRpb25hbCkgSWYgcHJvdmlkZWQsIGluIHRoZSByZXR1cm5lZCBsaXN0IG9mIHJ1bnMsIGVhY2ggcnVuIHdpbGwgaGF2ZSBhIGAudmFyaWFibGVzYCBwcm9wZXJ0eSB3aXRoIHRoZXNlIHNldC5cbiAgICAgKiBAcGFyYW0gIHtPYmplY3R9IGZpbHRlciAgICAoT3B0aW9uYWwpIEFueSBmaWx0ZXJzIHRvIGFwcGx5IHdoaWxlIGZldGNoaW5nIHRoZSBydW4uIFNlZSBbUnVuU2VydmljZSNmaWx0ZXJdKC4uLy4uL3J1bi1hcGktc2VydmljZS8jZmlsdGVyKSBmb3IgZGV0YWlscy5cbiAgICAgKiBAcGFyYW0gIHtPYmplY3R9IG1vZGlmaWVycyAoT3B0aW9uYWwpIFVzZSBmb3IgcGFnaW5nL3NvcnRpbmcgZXRjLiBTZWUgW1J1blNlcnZpY2UjZmlsdGVyXSguLi8uLi9ydW4tYXBpLXNlcnZpY2UvI2ZpbHRlcikgZm9yIGRldGFpbHMuXG4gICAgICogQHJldHVybiB7UHJvbWlzZX1cbiAgICAgKi9cbiAgICBnZXRSdW5zOiBmdW5jdGlvbiAodmFyaWFibGVzLCBmaWx0ZXIsIG1vZGlmaWVycykge1xuICAgICAgICB2YXIgc2Vzc2lvbiA9IHRoaXMuc2Vzc2lvbk1hbmFnZXIuZ2V0U2Vzc2lvbih0aGlzLnJ1blNlcnZpY2UuZ2V0Q3VycmVudENvbmZpZygpKTtcblxuICAgICAgICB2YXIgcnVub3B0cyA9IHRoaXMucnVuU2VydmljZS5nZXRDdXJyZW50Q29uZmlnKCk7XG4gICAgICAgIHZhciBzY29wZWRGaWx0ZXIgPSBpbmplY3RGaWx0ZXJzRnJvbVNlc3Npb24oJC5leHRlbmQodHJ1ZSwge30sIHtcbiAgICAgICAgICAgIHNhdmVkOiB0cnVlLCBcbiAgICAgICAgICAgIHRyYXNoZWQ6IGZhbHNlLFxuICAgICAgICAgICAgbW9kZWw6IHJ1bm9wdHMubW9kZWwsXG4gICAgICAgIH0sIGZpbHRlciksIHNlc3Npb24sIHRoaXMub3B0aW9ucyk7XG5cbiAgICAgICAgdmFyIG9wTW9kaWZpZXJzID0gJC5leHRlbmQodHJ1ZSwge30sIHtcbiAgICAgICAgICAgIHNvcnQ6ICdjcmVhdGVkJyxcbiAgICAgICAgICAgIGRpcmVjdGlvbjogJ2FzYycsXG4gICAgICAgIH0sIG1vZGlmaWVycyk7XG4gICAgICAgIGlmICh2YXJpYWJsZXMpIHtcbiAgICAgICAgICAgIG9wTW9kaWZpZXJzLmluY2x1ZGUgPSBbXS5jb25jYXQodmFyaWFibGVzKTtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gdGhpcy5ydW5TZXJ2aWNlLnF1ZXJ5KHNjb3BlZEZpbHRlciwgb3BNb2RpZmllcnMpO1xuICAgIH1cbn07XG5tb2R1bGUuZXhwb3J0cyA9IFNhdmVkUnVuc01hbmFnZXI7XG4iLCIvKipcbiogIyMgU2NlbmFyaW8gTWFuYWdlclxuKlxuKiBJbiBzb21lIHByb2plY3RzLCBvZnRlbiBjYWxsZWQgXCJ0dXJuLWJ5LXR1cm5cIiBwcm9qZWN0cywgZW5kIHVzZXJzIGFkdmFuY2UgdGhyb3VnaCB0aGUgcHJvamVjdCdzIG1vZGVsIHN0ZXAtYnktc3RlcCwgd29ya2luZyBlaXRoZXIgaW5kaXZpZHVhbGx5IG9yIHRvZ2V0aGVyIHRvIG1ha2UgZGVjaXNpb25zIGF0IGVhY2ggc3RlcC4gXG4qXG4qIEluIG90aGVyIHByb2plY3RzLCBvZnRlbiBjYWxsZWQgXCJydW4gY29tcGFyaXNvblwiIG9yIFwic2NlbmFyaW8gY29tcGFyaXNvblwiIHByb2plY3RzLCBlbmQgdXNlcnMgc2V0IHNvbWUgaW5pdGlhbCBkZWNpc2lvbnMsIHRoZW4gc2ltdWxhdGUgdGhlIG1vZGVsIHRvIGl0cyBlbmQuIFR5cGljYWxseSBlbmQgdXNlcnMgd2lsbCBkbyB0aGlzIHNldmVyYWwgdGltZXMsIGNyZWF0aW5nIHNldmVyYWwgcnVucywgYW5kIGNvbXBhcmUgdGhlIHJlc3VsdHMuIFxuKlxuKiBUaGUgU2NlbmFyaW8gTWFuYWdlciBtYWtlcyBpdCBlYXN5IHRvIGNyZWF0ZSB0aGVzZSBcInJ1biBjb21wYXJpc29uXCIgcHJvamVjdHMuIEVhY2ggU2NlbmFyaW8gTWFuYWdlciBhbGxvd3MgeW91IHRvIGNvbXBhcmUgdGhlIHJlc3VsdHMgb2Ygc2V2ZXJhbCBydW5zLiBUaGlzIGlzIG1vc3RseSB1c2VmdWwgZm9yIHRpbWUtYmFzZWQgbW9kZWxzOyBieSBkZWZhdWx0LCB5b3UgY2FuIHVzZSB0aGUgU2NlbmFyaW8gTWFuYWdlciB3aXRoIFtWZW5zaW1dKC4uLy4uLy4uL21vZGVsX2NvZGUvdmVuc2ltLyksIFtQb3dlcnNpbV0oLi4vLi4vLi4vbW9kZWxfY29kZS9wb3dlcnNpbS8pLCBhbmQgW1NpbUxhbmddKC4uLy4uLy4uL21vZGVsX2NvZGUvZm9yaW9fc2ltbGFuZykuIChZb3UgY2FuIHVzZSB0aGUgU2NlbmFyaW8gTWFuYWdlciB3aXRoIG90aGVyIGxhbmd1YWdlcyBhcyB3ZWxsLCBieSB1c2luZyB0aGUgU2NlbmFyaW8gTWFuYWdlcidzIFtjb25maWd1cmF0aW9uIG9wdGlvbnNdKCNjb25maWd1cmF0aW9uLW9wdGlvbnMpIHRvIGNoYW5nZSB0aGUgYGFkdmFuY2VPcGVyYXRpb25gLilcbipcbiogVGhlIFNjZW5hcmlvIE1hbmFnZXIgY2FuIGJlIHRob3VnaHQgb2YgYXMgYSBjb2xsZWN0aW9uIG9mIFtSdW4gTWFuYWdlcnNdKC4uL3J1bi1tYW5hZ2VyLykgd2l0aCBwcmUtY29uZmlndXJlZCBbc3RyYXRlZ2llc10oLi4vc3RyYXRlZ2llcy8pLiBKdXN0IGFzIHRoZSBSdW4gTWFuYWdlciBwcm92aWRlcyB1c2UgY2FzZSAtYmFzZWQgYWJzdHJhY3Rpb25zIGFuZCB1dGlsaXRpZXMgZm9yIG1hbmFnaW5nIHRoZSBbUnVuIFNlcnZpY2VdKC4uL3J1bi1hcGktc2VydmljZS8pLCB0aGUgU2NlbmFyaW8gTWFuYWdlciBkb2VzIHRoZSBzYW1lIGZvciB0aGUgUnVuIE1hbmFnZXIuXG4qXG4qIFRoZXJlIGFyZSB0eXBpY2FsbHkgdGhyZWUgY29tcG9uZW50cyB0byBidWlsZGluZyBhIHJ1biBjb21wYXJpc29uOlxuKlxuKiAqIEEgYGN1cnJlbnRgIHJ1biBpbiB3aGljaCB0byBtYWtlIGRlY2lzaW9uczsgdGhpcyBpcyBkZWZpbmVkIGFzIGEgcnVuIHRoYXQgaGFzbid0IGJlZW4gYWR2YW5jZWQgeWV0LCBhbmQgc28gY2FuIGJlIHVzZWQgdG8gc2V0IGluaXRpYWwgZGVjaXNpb25zLiBUaGUgY3VycmVudCBydW4gbWFpbnRhaW5zIHN0YXRlIGFjcm9zcyBkaWZmZXJlbnQgc2Vzc2lvbnMuXG4qICogQSBsaXN0IG9mIGBzYXZlZGAgcnVucywgdGhhdCBpcywgYWxsIHJ1bnMgdGhhdCB5b3Ugd2FudCB0byB1c2UgZm9yIGNvbXBhcmlzb25zLlxuKiAqIEEgYGJhc2VsaW5lYCBydW4gdG8gY29tcGFyZSBhZ2FpbnN0OyB0aGlzIGlzIGRlZmluZWQgYXMgYSBydW4gXCJhZHZhbmNlZCB0byB0aGUgZW5kXCIgb2YgeW91ciBtb2RlbCB1c2luZyBqdXN0IHRoZSBtb2RlbCBkZWZhdWx0cy4gQ29tcGFyaW5nIGFnYWluc3QgYSBiYXNlbGluZSBydW4gaXMgb3B0aW9uYWw7IHlvdSBjYW4gW2NvbmZpZ3VyZV0oI2NvbmZpZ3VyYXRpb24tb3B0aW9ucykgdGhlIFNjZW5hcmlvIE1hbmFnZXIgdG8gbm90IGluY2x1ZGUgb25lLlxuKlxuKiBUbyBzYXRpc2Z5IHRoZXNlIG5lZWRzIGEgU2NlbmFyaW8gTWFuYWdlciBpbnN0YW5jZSBoYXMgdGhyZWUgUnVuIE1hbmFnZXJzOiBbYmFzZWxpbmVdKC4vYmFzZWxpbmUvKSwgW2N1cnJlbnRdKC4vY3VycmVudC8pLCBhbmQgW3NhdmVkUnVuc10oLi9zYXZlZC8pLlxuKlxuKiAjIyMgVXNpbmcgdGhlIFNjZW5hcmlvIE1hbmFnZXIgdG8gY3JlYXRlIGEgcnVuIGNvbXBhcmlzb24gcHJvamVjdFxuKlxuKiBUbyB1c2UgdGhlIFNjZW5hcmlvIE1hbmFnZXIsIGluc3RhbnRpYXRlIGl0LCB0aGVuIGFjY2VzcyBpdHMgUnVuIE1hbmFnZXJzIGFzIG5lZWRlZCB0byBjcmVhdGUgeW91ciBwcm9qZWN0J3MgdXNlciBpbnRlcmZhY2U6XG4qXG4qICoqRXhhbXBsZSoqXG4qXG4qICAgICAgIHZhciBzbSA9IG5ldyBGLm1hbmFnZXIuU2NlbmFyaW9NYW5hZ2VyKHtcbiogICAgICAgICAgIHJ1bjoge1xuKiAgICAgICAgICAgICAgIG1vZGVsOiAnbXltb2RlbC52bWYnXG4qICAgICAgICAgICB9XG4qICAgICAgIH0pO1xuKlxuKiAgICAgICAvLyBUaGUgY3VycmVudCBpcyBhbiBpbnN0YW5jZSBvZiBhIFJ1biBNYW5hZ2VyLFxuKiAgICAgICAvLyB3aXRoIGEgc3RyYXRlZ3kgd2hpY2ggcGlja3MgdXAgdGhlIG1vc3QgcmVjZW50IHVuc2F2ZWQgcnVuLlxuKiAgICAgICAvLyBJdCBpcyB0eXBpY2FsbHkgdXNlZCB0byBzdG9yZSB0aGUgZGVjaXNpb25zIGJlaW5nIG1hZGUgYnkgdGhlIGVuZCB1c2VyLiBcbiogICAgICAgdmFyIGN1cnJlbnRSTSA9IHNtLmN1cnJlbnQ7XG4qXG4qICAgICAgIC8vIFRoZSBSdW4gTWFuYWdlciBvcGVyYXRpb24sIHdoaWNoIHJldHJpZXZlcyB0aGUgY3VycmVudCBydW4uXG4qICAgICAgIHNtLmN1cnJlbnQuZ2V0UnVuKCk7XG4qICAgICAgIC8vIFRoZSBSdW4gTWFuYWdlciBvcGVyYXRpb24sIHdoaWNoIHJlc2V0cyB0aGUgZGVjaXNpb25zIG1hZGUgb24gdGhlIGN1cnJlbnQgcnVuLlxuKiAgICAgICBzbS5jdXJyZW50LnJlc2V0KCk7XG4qICAgICAgIC8vIEEgc3BlY2lhbCBtZXRob2Qgb24gdGhlIGN1cnJlbnQgcnVuLFxuKiAgICAgICAvLyB3aGljaCBjbG9uZXMgdGhlIGN1cnJlbnQgcnVuLCB0aGVuIGFkdmFuY2VzIGFuZCBzYXZlcyB0aGlzIGNsb25lXG4qICAgICAgIC8vIChpdCBiZWNvbWVzIHBhcnQgb2YgdGhlIHNhdmVkIHJ1bnMgbGlzdCkuXG4qICAgICAgIC8vIFRoZSBjdXJyZW50IHJ1biBpcyB1bmNoYW5nZWQgYW5kIGNhbiBjb250aW51ZSB0byBiZSB1c2VkXG4qICAgICAgIC8vIHRvIHN0b3JlIGRlY2lzaW9ucyBiZWluZyBtYWRlIGJ5IHRoZSBlbmQgdXNlci5cbiogICAgICAgc20uY3VycmVudC5zYXZlQW5kQWR2YW5jZSgpO1xuKlxuKiAgICAgICAvLyBUaGUgc2F2ZWRSdW5zIGlzIGFuIGluc3RhbmNlIG9mIGEgU2F2ZWQgUnVucyBNYW5hZ2VyIFxuKiAgICAgICAvLyAoaXRzZWxmIGEgdmFyaWFudCBvZiBhIFJ1biBNYW5hZ2VyKS5cbiogICAgICAgLy8gSXQgaXMgdHlwaWNhbGx5IGRpc3BsYXllZCBpbiB0aGUgcHJvamVjdCdzIFVJIGFzIHBhcnQgb2YgYSBydW4gY29tcGFyaXNvbiB0YWJsZSBvciBjaGFydC5cbiogICAgICAgdmFyIHNhdmVkUk0gPSBzbS5zYXZlZFJ1bnM7XG4qICAgICAgIC8vIE1hcmsgYSBydW4gYXMgc2F2ZWQsIGFkZGluZyBpdCB0byB0aGUgc2V0IG9mIHNhdmVkIHJ1bnMuXG4qICAgICAgIHNtLnNhdmVkUnVucy5zYXZlKHJ1bik7XG4qICAgICAgIC8vIE1hcmsgYSBydW4gYXMgcmVtb3ZlZCwgcmVtb3ZpbmcgaXQgZnJvbSB0aGUgc2V0IG9mIHNhdmVkIHJ1bnMuXG4qICAgICAgIHNtLnNhdmVkUnVucy5yZW1vdmUocnVuKTtcbiogICAgICAgLy8gTGlzdCB0aGUgc2F2ZWQgcnVucywgb3B0aW9uYWxseSBpbmNsdWRpbmcgc29tZSBzcGVjaWZpYyBtb2RlbCB2YXJpYWJsZXMgZm9yIGVhY2guXG4qICAgICAgIHNtLnNhdmVkUnVucy5nZXRSdW5zKCk7XG4qXG4qICAgICAgIC8vIFRoZSBiYXNlbGluZSBpcyBhbiBpbnN0YW5jZSBvZiBhIFJ1biBNYW5hZ2VyLFxuKiAgICAgICAvLyB3aXRoIGEgc3RyYXRlZ3kgd2hpY2ggbG9jYXRlcyB0aGUgbW9zdCByZWNlbnQgYmFzZWxpbmUgcnVuXG4qICAgICAgIC8vICh0aGF0IGlzLCBmbGFnZ2VkIGFzIGBzYXZlZGAgYW5kIG5vdCBgdHJhc2hlZGApLCBvciBjcmVhdGVzIGEgbmV3IG9uZS5cbiogICAgICAgLy8gSXQgaXMgdHlwaWNhbGx5IGRpc3BsYXllZCBpbiB0aGUgcHJvamVjdCdzIFVJIGFzIHBhcnQgb2YgYSBydW4gY29tcGFyaXNvbiB0YWJsZSBvciBjaGFydC5cbiogICAgICAgdmFyIGJhc2VsaW5lUk0gPSBzbS5iYXNlbGluZTtcbipcbiogICAgICAgLy8gVGhlIFJ1biBNYW5hZ2VyIG9wZXJhdGlvbiwgd2hpY2ggcmV0cmlldmVzIHRoZSBiYXNlbGluZSBydW4uXG4qICAgICAgIHNtLmJhc2VsaW5lLmdldFJ1bigpO1xuKiAgICAgICAvLyBUaGUgUnVuIE1hbmFnZXIgb3BlcmF0aW9uLCB3aGljaCByZXNldHMgdGhlIGJhc2VsaW5lIHJ1bi5cbiogICAgICAgLy8gVXNlZnVsIGlmIHRoZSBtb2RlbCBoYXMgY2hhbmdlZCBzaW5jZSB0aGUgYmFzZWxpbmUgcnVuIHdhcyBjcmVhdGVkLlxuKiAgICAgICBzbS5iYXNlbGluZS5yZXNldCgpOyBcbiovXG5cbid1c2Ugc3RyaWN0JztcblxuLy8gU2VlIGludGVncmF0aW9uLXRlc3Qtc2NlbmFyaW8tbWFuYWdlciBmb3IgdXNhZ2UgZXhhbXBsZXNcbnZhciBSdW5NYW5hZ2VyID0gcmVxdWlyZSgnLi9ydW4tbWFuYWdlcicpO1xudmFyIFNhdmVkUnVuc01hbmFnZXIgPSByZXF1aXJlKCcuL3NhdmVkLXJ1bnMtbWFuYWdlcicpO1xudmFyIHN0cmF0ZWd5VXRpbHMgPSByZXF1aXJlKCcuL3N0cmF0ZWd5LXV0aWxzJyk7XG52YXIgcnV0aWwgPSByZXF1aXJlKCcuLi91dGlsL3J1bi11dGlsJyk7XG5cbnZhciBOb25lU3RyYXRlZ3kgPSByZXF1aXJlKCcuL3J1bi1zdHJhdGVnaWVzL25vbmUtc3RyYXRlZ3knKTtcblxudmFyIFN0YXRlU2VydmljZSA9IHJlcXVpcmUoJy4uL3NlcnZpY2Uvc3RhdGUtYXBpLWFkYXB0ZXInKTtcbnZhciBSdW5TZXJ2aWNlID0gcmVxdWlyZSgnLi4vc2VydmljZS9ydW4tYXBpLXNlcnZpY2UnKTtcblxudmFyIEJhc2VsaW5lU3RyYXRlZ3kgPSByZXF1aXJlKCcuL3NjZW5hcmlvLXN0cmF0ZWdpZXMvYmFzZWxpbmUtc3RyYXRlZ3knKTtcbnZhciBMYXN0VW5zYXZlZFN0cmF0ZWd5ID0gcmVxdWlyZSgnLi9zY2VuYXJpby1zdHJhdGVnaWVzL3JldXNlLWxhc3QtdW5zYXZlZCcpO1xuXG52YXIgZGVmYXVsdHMgPSB7XG4gICAgLyoqXG4gICAgICogT3BlcmF0aW9ucyB0byBwZXJmb3JtIG9uIGVhY2ggcnVuIHRvIGluZGljYXRlIHRoYXQgdGhlIHJ1biBpcyBjb21wbGV0ZS4gT3BlcmF0aW9ucyBhcmUgZXhlY3V0ZWQgW3NlcmlhbGx5XSguLi9ydW4tYXBpLXNlcnZpY2UvI3NlcmlhbCkuIERlZmF1bHRzIHRvIGNhbGxpbmcgdGhlIG1vZGVsIG9wZXJhdGlvbiBgc3RlcFRvKCdlbmQnKWAsIHdoaWNoIGFkdmFuY2VzIFZlbnNpbSwgUG93ZXJzaW0sIGFuZCBTaW1MYW5nIG1vZGVscyB0byB0aGUgZW5kLiBcbiAgICAgKiBAdHlwZSB7QXJyYXl9XG4gICAgICovXG4gICAgYWR2YW5jZU9wZXJhdGlvbjogW3sgbmFtZTogJ3N0ZXBUbycsIHBhcmFtczogWydlbmQnXSB9XSxcblxuICAgIC8qKlxuICAgICAqIEFkZGl0aW9uYWwgb3B0aW9ucyB0byBwYXNzIHRocm91Z2ggdG8gcnVuIGNyZWF0aW9uIChmb3IgZS5nLiwgYGZpbGVzYCwgZXRjLikuIERlZmF1bHRzIHRvIGVtcHR5IG9iamVjdC5cbiAgICAgKiBAdHlwZSB7T2JqZWN0fVxuICAgICAqL1xuICAgIHJ1bjoge30sXG5cbiAgICAvKipcbiAgICAgKiBXaGV0aGVyIG9yIG5vdCB0byBpbmNsdWRlIGEgYmFzZWxpbmUgcnVuIGluIHRoaXMgU2NlbmFyaW8gTWFuYWdlci4gRGVmYXVsdHMgdG8gYHRydWVgLlxuICAgICAqIEB0eXBlIHtCb29sZWFufVxuICAgICAqL1xuICAgIGluY2x1ZGVCYXNlTGluZTogdHJ1ZSxcblxuICAgIC8qKlxuICAgICAqIEFkZGl0aW9uYWwgY29uZmlndXJhdGlvbiBmb3IgdGhlIGBiYXNlbGluZWAgcnVuLiBcbiAgICAgKlxuICAgICAqICogYGJhc2VsaW5lLnJ1bk5hbWVgOiBOYW1lIG9mIHRoZSBiYXNlbGluZSBydW4uIERlZmF1bHRzIHRvICdCYXNlbGluZScuIFxuICAgICAqICogYGJhc2VsaW5lLnJ1bmA6IEFkZGl0aW9uYWwgb3B0aW9ucyB0byBwYXNzIHRocm91Z2ggdG8gcnVuIGNyZWF0aW9uLCBzcGVjaWZpY2FsbHkgZm9yIHRoZSBiYXNlbGluZSBydW4uIFRoZXNlIHdpbGwgb3ZlcnJpZGUgYW55IG9wdGlvbnMgcHJvdmlkZWQgdW5kZXIgYHJ1bmAuIERlZmF1bHRzIHRvIGVtcHR5IG9iamVjdC4gXG4gICAgICogQHR5cGUge09iamVjdH1cbiAgICAgKi9cbiAgICBiYXNlbGluZToge1xuICAgICAgICBydW5OYW1lOiAnQmFzZWxpbmUnLFxuICAgICAgICBydW46IHt9XG4gICAgfSxcblxuICAgIC8qKlxuICAgICAqIEFkZGl0aW9uYWwgY29uZmlndXJhdGlvbiBmb3IgdGhlIGBjdXJyZW50YCBydW4uIFxuICAgICAqXG4gICAgICogKiBgY3VycmVudC5ydW5gOiBBZGRpdGlvbmFsIG9wdGlvbnMgdG8gcGFzcyB0aHJvdWdoIHRvIHJ1biBjcmVhdGlvbiwgc3BlY2lmaWNhbGx5IGZvciB0aGUgY3VycmVudCBydW4uIFRoZXNlIHdpbGwgb3ZlcnJpZGUgYW55IG9wdGlvbnMgcHJvdmlkZWQgdW5kZXIgYHJ1bmAuIERlZmF1bHRzIHRvIGVtcHR5IG9iamVjdC5cbiAgICAgKiBAdHlwZSB7T2JqZWN0fVxuICAgICAqL1xuICAgIGN1cnJlbnQ6IHtcbiAgICAgICAgcnVuOiB7fVxuICAgIH0sXG5cbiAgICAvKipcbiAgICAgKiBPcHRpb25zIHRvIHBhc3MgdGhyb3VnaCB0byB0aGUgYHNhdmVkUnVuc2AgbGlzdC4gU2VlIHRoZSBbU2F2ZWQgUnVucyBNYW5hZ2VyXSguL3NhdmVkLykgZm9yIGNvbXBsZXRlIGRlc2NyaXB0aW9uIG9mIGF2YWlsYWJsZSBvcHRpb25zLiBEZWZhdWx0cyB0byBlbXB0eSBvYmplY3QuXG4gICAgICogQHR5cGUge09iamVjdH1cbiAgICAgKi9cbiAgICBzYXZlZFJ1bnM6IHt9XG59O1xuXG5mdW5jdGlvbiBjb29raWVOYW1lRnJvbU9wdGlvbnMocHJlZml4LCBjb25maWcpIHtcbiAgICB2YXIga2V5ID0gWydhY2NvdW50JywgJ3Byb2plY3QnLCAnbW9kZWwnXS5yZWR1Y2UoZnVuY3Rpb24gKGFjY3VtLCBrZXkpIHtcbiAgICAgICAgcmV0dXJuIGNvbmZpZ1trZXldID8gYWNjdW0gKyAnLScgKyBjb25maWdba2V5XSA6IGFjY3VtOyBcbiAgICB9LCBwcmVmaXgpO1xuICAgIHJldHVybiBrZXk7XG59XG5cbmZ1bmN0aW9uIFNjZW5hcmlvTWFuYWdlcihjb25maWcpIHtcbiAgICB2YXIgb3B0cyA9ICQuZXh0ZW5kKHRydWUsIHt9LCBkZWZhdWx0cywgY29uZmlnKTtcbiAgICBpZiAoY29uZmlnICYmIGNvbmZpZy5hZHZhbmNlT3BlcmF0aW9uKSB7XG4gICAgICAgIG9wdHMuYWR2YW5jZU9wZXJhdGlvbiA9IGNvbmZpZy5hZHZhbmNlT3BlcmF0aW9uOyAvL2pxdWVyeS5leHRlbmQgZG9lcyBhIHBvb3Igam9iIHRyeWluZyB0byBtZXJnZSBhcnJheXNcbiAgICB9XG5cbiAgICB2YXIgQmFzZWxpbmVTdHJhdGVneVRvVXNlID0gb3B0cy5pbmNsdWRlQmFzZUxpbmUgPyBCYXNlbGluZVN0cmF0ZWd5IDogTm9uZVN0cmF0ZWd5O1xuICAgIC8qKlxuICAgICAqIEEgW1J1biBNYW5hZ2VyXSguLi9ydW4tbWFuYWdlci8pIGluc3RhbmNlIGNvbnRhaW5pbmcgYSAnYmFzZWxpbmUnIHJ1biB0byBjb21wYXJlIGFnYWluc3Q7IHRoaXMgaXMgZGVmaW5lZCBhcyBhIHJ1biBcImFkdmFuY2VkIHRvIHRoZSBlbmRcIiBvZiB5b3VyIG1vZGVsIHVzaW5nIGp1c3QgdGhlIG1vZGVsIGRlZmF1bHRzLiBCeSBkZWZhdWx0IHRoZSBcImFkdmFuY2VcIiBvcGVyYXRpb24gaXMgYXNzdW1lZCB0byBiZSBgc3RlcFRvOiBlbmRgLCB3aGljaCB3b3JrcyBmb3IgdGltZS1iYXNlZCBtb2RlbHMgaW4gW1ZlbnNpbV0oLi4vLi4vLi4vbW9kZWxfY29kZS92ZW5zaW0vKSwgW1Bvd2Vyc2ltXSguLi8uLi8uLi9tb2RlbF9jb2RlL3Bvd2Vyc2ltLyksIGFuZCBbU2ltTGFuZ10oLi4vLi4vLi4vbW9kZWxfY29kZS9mb3Jpb19zaW1sYW5nKS4gSWYgeW91J3JlIHVzaW5nIGEgZGlmZmVyZW50IGxhbmd1YWdlLCBvciBuZWVkIHRvIGNoYW5nZSB0aGlzLCBqdXN0IHBhc3MgaW4gYSBkaWZmZXJlbnQgYGFkdmFuY2VPcGVyYXRpb25gIG9wdGlvbiB3aGlsZSBjcmVhdGluZyB0aGUgU2NlbmFyaW8gTWFuYWdlci4gVGhlIGJhc2VsaW5lIHJ1biBpcyB0eXBpY2FsbHkgZGlzcGxheWVkIGluIHRoZSBwcm9qZWN0J3MgVUkgYXMgcGFydCBvZiBhIHJ1biBjb21wYXJpc29uIHRhYmxlIG9yIGNoYXJ0LlxuICAgICAqIEByZXR1cm4ge1J1bk1hbmFnZXJ9XG4gICAgICovXG4gICAgdGhpcy5iYXNlbGluZSA9IG5ldyBSdW5NYW5hZ2VyKHtcbiAgICAgICAgc3RyYXRlZ3k6IEJhc2VsaW5lU3RyYXRlZ3lUb1VzZSxcbiAgICAgICAgc2Vzc2lvbktleTogY29va2llTmFtZUZyb21PcHRpb25zLmJpbmQobnVsbCwgJ3NtLWJhc2VsaW5lLXJ1bicpLFxuICAgICAgICBydW46IHN0cmF0ZWd5VXRpbHMubWVyZ2VSdW5PcHRpb25zKG9wdHMucnVuLCBvcHRzLmJhc2VsaW5lLnJ1biksXG4gICAgICAgIHN0cmF0ZWd5T3B0aW9uczoge1xuICAgICAgICAgICAgYmFzZWxpbmVOYW1lOiBvcHRzLmJhc2VsaW5lLnJ1bk5hbWUsXG4gICAgICAgICAgICBpbml0T3BlcmF0aW9uOiBvcHRzLmFkdmFuY2VPcGVyYXRpb25cbiAgICAgICAgfVxuICAgIH0pO1xuXG4gICAgLyoqXG4gICAgICogQSBbU2F2ZWRSdW5zTWFuYWdlcl0oLi4vc2F2ZWQtcnVucy1tYW5hZ2VyLykgaW5zdGFuY2UgY29udGFpbmluZyBhIGxpc3Qgb2Ygc2F2ZWQgcnVucywgdGhhdCBpcywgYWxsIHJ1bnMgdGhhdCB5b3Ugd2FudCB0byB1c2UgZm9yIGNvbXBhcmlzb25zLiBUaGUgc2F2ZWQgcnVucyBhcmUgdHlwaWNhbGx5IGRpc3BsYXllZCBpbiB0aGUgcHJvamVjdCdzIFVJIGFzIHBhcnQgb2YgYSBydW4gY29tcGFyaXNvbiB0YWJsZSBvciBjaGFydC5cbiAgICAgKiBAcmV0dXJuIHtTYXZlZFJ1bnNNYW5hZ2VyfVxuICAgICAqL1xuICAgIHRoaXMuc2F2ZWRSdW5zID0gbmV3IFNhdmVkUnVuc01hbmFnZXIoJC5leHRlbmQodHJ1ZSwge30sIHtcbiAgICAgICAgcnVuOiBvcHRzLnJ1bixcbiAgICB9LCBvcHRzLnNhdmVkUnVucykpO1xuXG4gICAgdmFyIG9yaWdHZXRSdW5zID0gdGhpcy5zYXZlZFJ1bnMuZ2V0UnVucztcbiAgICB2YXIgbWUgPSB0aGlzO1xuICAgIHRoaXMuc2F2ZWRSdW5zLmdldFJ1bnMgPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHZhciBhcmdzID0gQXJyYXkuYXBwbHkobnVsbCwgYXJndW1lbnRzKTtcbiAgICAgICAgcmV0dXJuIG1lLmJhc2VsaW5lLmdldFJ1bigpLnRoZW4oZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgcmV0dXJuIG9yaWdHZXRSdW5zLmFwcGx5KG1lLnNhdmVkUnVucywgYXJncyk7XG4gICAgICAgIH0pO1xuICAgIH07XG5cbiAgICAvKipcbiAgICAgKiBBIFtSdW4gTWFuYWdlcl0oLi4vcnVuLW1hbmFnZXIvKSBpbnN0YW5jZSBjb250YWluaW5nIGEgJ2N1cnJlbnQnIHJ1bjsgdGhpcyBpcyBkZWZpbmVkIGFzIGEgcnVuIHRoYXQgaGFzbid0IGJlZW4gYWR2YW5jZWQgeWV0LCBhbmQgc28gY2FuIGJlIHVzZWQgdG8gc2V0IGluaXRpYWwgZGVjaXNpb25zLiBUaGUgY3VycmVudCBydW4gaXMgdHlwaWNhbGx5IHVzZWQgdG8gc3RvcmUgdGhlIGRlY2lzaW9ucyBiZWluZyBtYWRlIGJ5IHRoZSBlbmQgdXNlci5cbiAgICAgKiBAcmV0dXJuIHtSdW5NYW5hZ2VyfVxuICAgICAqL1xuICAgIHRoaXMuY3VycmVudCA9IG5ldyBSdW5NYW5hZ2VyKHtcbiAgICAgICAgc3RyYXRlZ3k6IExhc3RVbnNhdmVkU3RyYXRlZ3ksXG4gICAgICAgIHNlc3Npb25LZXk6IGNvb2tpZU5hbWVGcm9tT3B0aW9ucy5iaW5kKG51bGwsICdzbS1jdXJyZW50LXJ1bicpLFxuICAgICAgICBydW46IHN0cmF0ZWd5VXRpbHMubWVyZ2VSdW5PcHRpb25zKG9wdHMucnVuLCBvcHRzLmN1cnJlbnQucnVuKVxuICAgIH0pO1xuXG4gICAgLyoqXG4gICAgICogQ2xvbmVzIHRoZSBjdXJyZW50IHJ1biwgYWR2YW5jZXMgdGhpcyBjbG9uZSBieSBjYWxsaW5nIHRoZSBgYWR2YW5jZU9wZXJhdGlvbmAsIGFuZCBzYXZlcyB0aGUgY2xvbmVkIHJ1biAoaXQgYmVjb21lcyBwYXJ0IG9mIHRoZSBgc2F2ZWRSdW5zYCBsaXN0KS4gQWRkaXRpb25hbGx5LCBhZGRzIGFueSBwcm92aWRlZCBtZXRhZGF0YSB0byB0aGUgY2xvbmVkIHJ1bjsgdHlwaWNhbGx5IHVzZWQgZm9yIG5hbWluZyB0aGUgcnVuLiBUaGUgY3VycmVudCBydW4gaXMgdW5jaGFuZ2VkIGFuZCBjYW4gY29udGludWUgdG8gYmUgdXNlZCB0byBzdG9yZSBkZWNpc2lvbnMgYmVpbmcgbWFkZSBieSB0aGUgZW5kIHVzZXIuXG4gICAgICpcbiAgICAgKiBBdmFpbGFibGUgb25seSBmb3IgdGhlIFNjZW5hcmlvIE1hbmFnZXIncyBgY3VycmVudGAgcHJvcGVydHkgKFJ1biBNYW5hZ2VyKS4gXG4gICAgICpcbiAgICAgKiAqKkV4YW1wbGUqKlxuICAgICAqXG4gICAgICogICAgICB2YXIgc20gPSBuZXcgRi5tYW5hZ2VyLlNjZW5hcmlvTWFuYWdlcigpO1xuICAgICAqICAgICAgc20uY3VycmVudC5zYXZlQW5kQWR2YW5jZSh7J215UnVuTmFtZSc6ICdzYW1wbGUgcG9saWN5IGRlY2lzaW9ucyd9KTtcbiAgICAgKlxuICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICogQHBhcmFtICB7T2JqZWN0fSBtZXRhZGF0YSAgIE1ldGFkYXRhIHRvIHNhdmUsIGZvciBleGFtcGxlLCB0aGUgcnVuIG5hbWUuXG4gICAgICogQHJldHVybiB7UHJvbWlzZX1cbiAgICAgKi9cbiAgICB0aGlzLmN1cnJlbnQuc2F2ZUFuZEFkdmFuY2UgPSBmdW5jdGlvbiAobWV0YWRhdGEpIHtcbiAgICAgICAgZnVuY3Rpb24gY2xvbmUocnVuKSB7XG4gICAgICAgICAgICB2YXIgc2EgPSBuZXcgU3RhdGVTZXJ2aWNlKCk7XG4gICAgICAgICAgICB2YXIgYWR2YW5jZU9wbnMgPSBydXRpbC5ub3JtYWxpemVPcGVyYXRpb25zKG9wdHMuYWR2YW5jZU9wZXJhdGlvbik7IFxuICAgICAgICAgICAgLy9ydW4gaSdtIGNsb25pbmcgc2hvdWxkbid0IGhhdmUgdGhlIGFkdmFuY2Ugb3BlcmF0aW9ucyB0aGVyZSBieSBkZWZhdWx0LCBidXQganVzdCBpbiBjYXNlXG4gICAgICAgICAgICByZXR1cm4gc2EuY2xvbmUoeyBydW5JZDogcnVuLmlkLCBleGNsdWRlOiBhZHZhbmNlT3Bucy5vcHMgfSkudGhlbihmdW5jdGlvbiAocmVzcG9uc2UpIHtcbiAgICAgICAgICAgICAgICB2YXIgcnMgPSBuZXcgUnVuU2VydmljZShtZS5jdXJyZW50LnJ1bi5nZXRDdXJyZW50Q29uZmlnKCkpO1xuICAgICAgICAgICAgICAgIHJldHVybiBycy5sb2FkKHJlc3BvbnNlLnJ1bik7XG4gICAgICAgICAgICB9KTtcbiAgICAgICAgfVxuICAgICAgICBmdW5jdGlvbiBtYXJrU2F2ZWQocnVuKSB7XG4gICAgICAgICAgICByZXR1cm4gbWUuc2F2ZWRSdW5zLnNhdmUocnVuLmlkLCBtZXRhZGF0YSkudGhlbihmdW5jdGlvbiAoc2F2ZWRSZXNwb25zZSkge1xuICAgICAgICAgICAgICAgIHJldHVybiAkLmV4dGVuZCh0cnVlLCB7fSwgcnVuLCBzYXZlZFJlc3BvbnNlKTtcbiAgICAgICAgICAgIH0pO1xuICAgICAgICB9XG4gICAgICAgIGZ1bmN0aW9uIGFkdmFuY2UocnVuKSB7XG4gICAgICAgICAgICB2YXIgcnMgPSBuZXcgUnVuU2VydmljZShydW4pO1xuICAgICAgICAgICAgcmV0dXJuIHJzLnNlcmlhbChvcHRzLmFkdmFuY2VPcGVyYXRpb24pLnRoZW4oZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgICAgIHJldHVybiBydW47XG4gICAgICAgICAgICB9KTtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gbWUuY3VycmVudFxuICAgICAgICAgICAgICAgIC5nZXRSdW4oKVxuICAgICAgICAgICAgICAgIC50aGVuKGNsb25lKVxuICAgICAgICAgICAgICAgIC50aGVuKGFkdmFuY2UpXG4gICAgICAgICAgICAgICAgLnRoZW4obWFya1NhdmVkKTtcbiAgICB9O1xufVxuXG5tb2R1bGUuZXhwb3J0cyA9IFNjZW5hcmlvTWFuYWdlcjtcbiIsIi8qKlxuICogIyMgQmFzZWxpbmVcbiAqXG4gKiBBbiBpbnN0YW5jZSBvZiBhIFtSdW4gTWFuYWdlcl0oLi4vLi4vcnVuLW1hbmFnZXIvKSB3aXRoIGEgYmFzZWxpbmUgc3RyYXRlZ3kgaXMgaW5jbHVkZWQgYXV0b21hdGljYWxseSBpbiBldmVyeSBpbnN0YW5jZSBvZiBhIFtTY2VuYXJpbyBNYW5hZ2VyXSguLi8pLCBhbmQgaXMgYWNjZXNzaWJsZSBmcm9tIHRoZSBTY2VuYXJpbyBNYW5hZ2VyIGF0IGAuYmFzZWxpbmVgLlxuICpcbiAqIEEgYmFzZWxpbmUgaXMgZGVmaW5lZCBhcyBhIHJ1biBcImFkdmFuY2VkIHRvIHRoZSBlbmRcIiB1c2luZyBqdXN0IHRoZSBtb2RlbCBkZWZhdWx0cy4gVGhlIGJhc2VsaW5lIHJ1biBpcyB0eXBpY2FsbHkgZGlzcGxheWVkIGluIHRoZSBwcm9qZWN0J3MgVUkgYXMgcGFydCBvZiBhIHJ1biBjb21wYXJpc29uIHRhYmxlIG9yIGNoYXJ0LlxuICpcbiAqIFRoZSBgYmFzZWxpbmVgIHN0cmF0ZWd5IGxvb2tzIGZvciB0aGUgbW9zdCByZWNlbnQgcnVuIG5hbWVkIGFzICdCYXNlbGluZScgKG9yIG5hbWVkIGFzIHNwZWNpZmllZCBpbiB0aGUgYGJhc2VsaW5lLnJ1bk5hbWVgIFtjb25maWd1cmF0aW9uIG9wdGlvbiBvZiB0aGUgU2NlbmFyaW8gTWFuYWdlcl0oLi4vI2NvbmZpZ3VyYXRpb24tb3B0aW9ucykpIHRoYXQgaXMgZmxhZ2dlZCBhcyBgc2F2ZWRgIGFuZCBub3QgYHRyYXNoZWRgLiBJZiB0aGUgc3RyYXRlZ3kgY2Fubm90IGZpbmQgc3VjaCBhIHJ1biwgaXQgY3JlYXRlcyBhIG5ldyBydW4gYW5kIGltbWVkaWF0ZWx5IGV4ZWN1dGVzIGEgc2V0IG9mIGluaXRpYWxpemF0aW9uIG9wZXJhdGlvbnMuIFxuICpcbiAqIENvbXBhcmluZyBhZ2FpbnN0IGEgYmFzZWxpbmUgcnVuIGlzIG9wdGlvbmFsIGluIGEgU2NlbmFyaW8gTWFuYWdlcjsgeW91IGNhbiBbY29uZmlndXJlXSguLi8jY29uZmlndXJhdGlvbi1vcHRpb25zKSB5b3VyIFNjZW5hcmlvIE1hbmFnZXIgdG8gbm90IGluY2x1ZGUgb25lLiBTZWUgW21vcmUgaW5mb3JtYXRpb25dKC4uLyNwcm9wZXJ0aWVzKSBvbiB1c2luZyBgLmJhc2VsaW5lYCB3aXRoaW4gdGhlIFNjZW5hcmlvIE1hbmFnZXIuXG4gKlxuICogU2VlIGFsc286IFthZGRpdGlvbmFsIGluZm9ybWF0aW9uIG9uIHJ1biBzdHJhdGVnaWVzXSguLi8uLi9zdHJhdGVnaWVzLykuXG4gKlxuICovXG5cbid1c2Ugc3RyaWN0JztcblxudmFyIFJldXNlaW5pdFN0cmF0ZWd5ID0gcmVxdWlyZSgnLi4vcnVuLXN0cmF0ZWdpZXMvcmV1c2UtbGFzdC1pbml0aWFsaXplZCcpO1xuXG5tb2R1bGUuZXhwb3J0cyA9IGZ1bmN0aW9uIChvcHRpb25zKSB7XG4gICAgdmFyIGRlZmF1bHRzID0ge1xuICAgICAgICBiYXNlbGluZU5hbWU6ICdCYXNlbGluZScsXG4gICAgICAgIGluaXRPcGVyYXRpb246IFt7IHN0ZXBUbzogJ2VuZCcgfV1cbiAgICB9O1xuICAgIHZhciBzdHJhdGVneU9wdGlvbnMgPSBvcHRpb25zID8gb3B0aW9ucy5zdHJhdGVneU9wdGlvbnMgOiB7fTtcbiAgICB2YXIgb3B0cyA9ICQuZXh0ZW5kKHt9LCBkZWZhdWx0cywgc3RyYXRlZ3lPcHRpb25zKTtcbiAgICByZXR1cm4gbmV3IFJldXNlaW5pdFN0cmF0ZWd5KHtcbiAgICAgICAgc3RyYXRlZ3lPcHRpb25zOiB7XG4gICAgICAgICAgICBpbml0T3BlcmF0aW9uOiBvcHRzLmluaXRPcGVyYXRpb24sXG4gICAgICAgICAgICBmbGFnOiB7XG4gICAgICAgICAgICAgICAgc2F2ZWQ6IHRydWUsXG4gICAgICAgICAgICAgICAgdHJhc2hlZDogZmFsc2UsXG4gICAgICAgICAgICAgICAgbmFtZTogb3B0cy5iYXNlbGluZU5hbWVcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgIH0pO1xufTtcbiIsIi8qKlxuICogIyMgQ3VycmVudCAocmV1c2UtbGFzdC11bnNhdmVkKVxuICpcbiAqIEFuIGluc3RhbmNlIG9mIGEgW1J1biBNYW5hZ2VyXSguLi8uLi9ydW4tbWFuYWdlci8pIHdpdGggdGhpcyBzdHJhdGVneSBpcyBpbmNsdWRlZCBhdXRvbWF0aWNhbGx5IGluIGV2ZXJ5IGluc3RhbmNlIG9mIGEgW1NjZW5hcmlvIE1hbmFnZXJdKC4uLyksIGFuZCBpcyBhY2Nlc3NpYmxlIGZyb20gdGhlIFNjZW5hcmlvIE1hbmFnZXIgYXQgYC5jdXJyZW50YC5cbiAqXG4gKiBUaGUgYHJldXNlLWxhc3QtdW5zYXZlZGAgc3RyYXRlZ3kgcmV0dXJucyB0aGUgbW9zdCByZWNlbnQgcnVuIHRoYXQgaXMgbm90IGZsYWdnZWQgYXMgYHRyYXNoZWRgIGFuZCBhbHNvIG5vdCBmbGFnZ2VkIGFzIGBzYXZlZGAuXG4gKiBcbiAqIFVzaW5nIHRoaXMgc3RyYXRlZ3kgbWVhbnMgdGhhdCBlbmQgdXNlcnMgY29udGludWUgd29ya2luZyB3aXRoIHRoZSBtb3N0IHJlY2VudCBydW4gdGhhdCBoYXMgbm90IGJlZW4gZXhwbGljaXRseSBmbGFnZ2VkIGJ5IHRoZSBwcm9qZWN0LiBIb3dldmVyLCBpZiB0aGVyZSBhcmUgbm8gcnVucyBmb3IgdGhpcyBlbmQgdXNlciwgYSBuZXcgcnVuIGlzIGNyZWF0ZWQuXG4gKiBcbiAqIFNwZWNpZmljYWxseSwgdGhlIHN0cmF0ZWd5IGlzOlxuICpcbiAqICogQ2hlY2sgdGhlIGBzYXZlZGAgYW5kIGB0cmFzaGVkYCBmaWVsZHMgb2YgdGhlIHJ1biB0byBkZXRlcm1pbmUgaWYgdGhlIHJ1biBoYXMgYmVlbiBleHBsaWNpdGx5IHNhdmVkIG9yIGV4cGxpY2l0bHkgZmxhZ2dlZCBhcyBubyBsb25nZXIgdXNlZnVsLlxuICogICAgICogUmV0dXJuIHRoZSBtb3N0IHJlY2VudCBydW4gdGhhdCBpcyBub3QgYHRyYXNoZWRgIGFuZCBhbHNvIG5vdCBgc2F2ZWRgLlxuICogICAgICogSWYgdGhlcmUgYXJlIG5vIHJ1bnMsIGNyZWF0ZSBhIG5ldyBydW4gZm9yIHRoaXMgZW5kIHVzZXIuIFxuICpcbiAqIFNlZSBbbW9yZSBpbmZvcm1hdGlvbl0oLi4vI3Byb3BlcnRpZXMpIG9uIHVzaW5nIGAuY3VycmVudGAgd2l0aGluIHRoZSBTY2VuYXJpbyBNYW5hZ2VyLlxuICpcbiAqIFNlZSBhbHNvOiBbYWRkaXRpb25hbCBpbmZvcm1hdGlvbiBvbiBydW4gc3RyYXRlZ2llc10oLi4vLi4vc3RyYXRlZ2llcy8pLlxuICovXG5cbid1c2Ugc3RyaWN0JztcbnZhciBjbGFzc0Zyb20gPSByZXF1aXJlKCcuLi8uLi91dGlsL2luaGVyaXQnKTtcbnZhciBpbmplY3RGaWx0ZXJzRnJvbVNlc3Npb24gPSByZXF1aXJlKCcuLi9zdHJhdGVneS11dGlscycpLmluamVjdEZpbHRlcnNGcm9tU2Vzc2lvbjtcbnZhciBpbmplY3RTY29wZUZyb21TZXNzaW9uID0gcmVxdWlyZSgnLi4vc3RyYXRlZ3ktdXRpbHMnKS5pbmplY3RTY29wZUZyb21TZXNzaW9uO1xuXG52YXIgQmFzZSA9IHt9O1xuXG4vL1RPRE86IE1ha2UgYSBtb3JlIGdlbmVyaWMgdmVyc2lvbiBvZiB0aGlzIGNhbGxlZCAncmV1c2UtYnktbWF0Y2hpbmctZmlsdGVyJztcbm1vZHVsZS5leHBvcnRzID0gY2xhc3NGcm9tKEJhc2UsIHtcbiAgICBjb25zdHJ1Y3RvcjogZnVuY3Rpb24gKG9wdGlvbnMpIHtcbiAgICAgICAgdmFyIHN0cmF0ZWd5T3B0aW9ucyA9IG9wdGlvbnMgPyBvcHRpb25zLnN0cmF0ZWd5T3B0aW9ucyA6IHt9O1xuICAgICAgICB0aGlzLm9wdGlvbnMgPSBzdHJhdGVneU9wdGlvbnM7XG4gICAgfSxcblxuICAgIHJlc2V0OiBmdW5jdGlvbiAocnVuU2VydmljZSwgdXNlclNlc3Npb24sIG9wdGlvbnMpIHtcbiAgICAgICAgdmFyIG9wdCA9IGluamVjdFNjb3BlRnJvbVNlc3Npb24ocnVuU2VydmljZS5nZXRDdXJyZW50Q29uZmlnKCksIHVzZXJTZXNzaW9uKTtcbiAgICAgICAgcmV0dXJuIHJ1blNlcnZpY2UuY3JlYXRlKG9wdCwgb3B0aW9ucykudGhlbihmdW5jdGlvbiAoY3JlYXRlUmVzcG9uc2UpIHtcbiAgICAgICAgICAgIHJldHVybiAkLmV4dGVuZCh0cnVlLCB7fSwgY3JlYXRlUmVzcG9uc2UsIHsgZnJlc2hseUNyZWF0ZWQ6IHRydWUgfSk7XG4gICAgICAgIH0pO1xuICAgIH0sXG5cbiAgICBnZXRSdW46IGZ1bmN0aW9uIChydW5TZXJ2aWNlLCB1c2VyU2Vzc2lvbiwgb3B0cykge1xuICAgICAgICB2YXIgcnVub3B0cyA9IHJ1blNlcnZpY2UuZ2V0Q3VycmVudENvbmZpZygpO1xuICAgICAgICB2YXIgZmlsdGVyID0gaW5qZWN0RmlsdGVyc0Zyb21TZXNzaW9uKHsgXG4gICAgICAgICAgICBzYXZlZDogZmFsc2UsXG4gICAgICAgICAgICB0cmFzaGVkOiBmYWxzZSxcbiAgICAgICAgICAgIG1vZGVsOiBydW5vcHRzLm1vZGVsLFxuICAgICAgICB9LCB1c2VyU2Vzc2lvbik7XG4gICAgICAgIHZhciBtZSA9IHRoaXM7XG4gICAgICAgIHZhciBvdXRwdXRNb2RpZmllcnMgPSB7IFxuICAgICAgICAgICAgc3RhcnRyZWNvcmQ6IDAsXG4gICAgICAgICAgICBlbmRyZWNvcmQ6IDAsXG4gICAgICAgICAgICBzb3J0OiAnY3JlYXRlZCcsIFxuICAgICAgICAgICAgZGlyZWN0aW9uOiAnZGVzYydcbiAgICAgICAgfTtcbiAgICAgICAgcmV0dXJuIHJ1blNlcnZpY2UucXVlcnkoZmlsdGVyLCBvdXRwdXRNb2RpZmllcnMpLnRoZW4oZnVuY3Rpb24gKHJ1bnMpIHtcbiAgICAgICAgICAgIGlmICghcnVucy5sZW5ndGgpIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gbWUucmVzZXQocnVuU2VydmljZSwgdXNlclNlc3Npb24pO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgcmV0dXJuIHJ1bnNbMF07XG4gICAgICAgIH0pO1xuICAgIH1cbn0sIHsgcmVxdWlyZXNBdXRoOiBmYWxzZSB9KTsiLCIndXNlIHN0cmljdCc7XG5cblxubW9kdWxlLmV4cG9ydHMgPSB7XG4gICAgcmVzZXQ6IGZ1bmN0aW9uIChwYXJhbXMsIG9wdGlvbnMsIG1hbmFnZXIpIHtcbiAgICAgICAgcmV0dXJuIG1hbmFnZXIucmVzZXQob3B0aW9ucyk7XG4gICAgfVxufTtcbiIsIid1c2Ugc3RyaWN0JztcblxudmFyIFJ1blNlcnZpY2UgPSByZXF1aXJlKCcuLi9zZXJ2aWNlL3J1bi1hcGktc2VydmljZScpO1xuXG5tb2R1bGUuZXhwb3J0cyA9IHtcbiAgICBtZXJnZVJ1bk9wdGlvbnM6IGZ1bmN0aW9uIChydW4sIG9wdGlvbnMpIHtcbiAgICAgICAgaWYgKHJ1biBpbnN0YW5jZW9mIFJ1blNlcnZpY2UpIHtcbiAgICAgICAgICAgIHJ1bi51cGRhdGVDb25maWcob3B0aW9ucyk7XG4gICAgICAgICAgICByZXR1cm4gcnVuO1xuICAgICAgICB9IFxuICAgICAgICByZXR1cm4gJC5leHRlbmQodHJ1ZSwge30sIHJ1biwgb3B0aW9ucyk7XG4gICAgfSxcblxuICAgIGluamVjdEZpbHRlcnNGcm9tU2Vzc2lvbjogZnVuY3Rpb24gKGN1cnJlbnRGaWx0ZXIsIHNlc3Npb24sIG9wdGlvbnMpIHtcbiAgICAgICAgdmFyIGRlZmF1bHRzID0ge1xuICAgICAgICAgICAgc2NvcGVCeUdyb3VwOiB0cnVlLFxuICAgICAgICAgICAgc2NvcGVCeVVzZXI6IHRydWUsXG4gICAgICAgIH07XG4gICAgICAgIHZhciBvcHRzID0gJC5leHRlbmQodHJ1ZSwge30sIGRlZmF1bHRzLCBvcHRpb25zKTtcblxuICAgICAgICB2YXIgZmlsdGVyID0gJC5leHRlbmQodHJ1ZSwge30sIGN1cnJlbnRGaWx0ZXIpO1xuICAgICAgICBpZiAob3B0cy5zY29wZUJ5R3JvdXAgJiYgc2Vzc2lvbiAmJiBzZXNzaW9uLmdyb3VwTmFtZSkge1xuICAgICAgICAgICAgZmlsdGVyWydzY29wZS5ncm91cCddID0gc2Vzc2lvbi5ncm91cE5hbWU7XG4gICAgICAgIH1cbiAgICAgICAgaWYgKG9wdHMuc2NvcGVCeVVzZXIgJiYgc2Vzc2lvbiAmJiBzZXNzaW9uLnVzZXJJZCkge1xuICAgICAgICAgICAgZmlsdGVyWyd1c2VyLmlkJ10gPSBzZXNzaW9uLnVzZXJJZDtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gZmlsdGVyO1xuICAgIH0sXG5cbiAgICBpbmplY3RTY29wZUZyb21TZXNzaW9uOiBmdW5jdGlvbiAoY3VycmVudFBhcmFtcywgc2Vzc2lvbikge1xuICAgICAgICB2YXIgZ3JvdXAgPSBzZXNzaW9uICYmIHNlc3Npb24uZ3JvdXBOYW1lO1xuICAgICAgICB2YXIgcGFyYW1zID0gJC5leHRlbmQodHJ1ZSwge30sIGN1cnJlbnRQYXJhbXMpO1xuICAgICAgICBpZiAoZ3JvdXApIHtcbiAgICAgICAgICAgICQuZXh0ZW5kKHBhcmFtcywge1xuICAgICAgICAgICAgICAgIHNjb3BlOiB7IGdyb3VwOiBncm91cCB9XG4gICAgICAgICAgICB9KTtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gcGFyYW1zO1xuICAgIH1cbn07IiwiLyoqXG4qICMjIFdvcmxkIE1hbmFnZXJcbipcbiogQXMgZGlzY3Vzc2VkIHVuZGVyIHRoZSBbV29ybGQgQVBJIEFkYXB0ZXJdKC4uL3dvcmxkLWFwaS1hZGFwdGVyLyksIGEgW3J1bl0oLi4vLi4vLi4vZ2xvc3NhcnkvI3J1bikgaXMgYSBjb2xsZWN0aW9uIG9mIGVuZCB1c2VyIGludGVyYWN0aW9ucyB3aXRoIGEgcHJvamVjdCBhbmQgaXRzIG1vZGVsLiBGb3IgYnVpbGRpbmcgbXVsdGlwbGF5ZXIgc2ltdWxhdGlvbnMgeW91IHR5cGljYWxseSB3YW50IG11bHRpcGxlIGVuZCB1c2VycyB0byBzaGFyZSB0aGUgc2FtZSBzZXQgb2YgaW50ZXJhY3Rpb25zLCBhbmQgd29yayB3aXRoaW4gYSBjb21tb24gc3RhdGUuIEVwaWNlbnRlciBhbGxvd3MgeW91IHRvIGNyZWF0ZSBcIndvcmxkc1wiIHRvIGhhbmRsZSBzdWNoIGNhc2VzLlxuKlxuKiBUaGUgV29ybGQgTWFuYWdlciBwcm92aWRlcyBhbiBlYXN5IHdheSB0byB0cmFjayBhbmQgYWNjZXNzIHRoZSBjdXJyZW50IHdvcmxkIGFuZCBydW4gZm9yIHBhcnRpY3VsYXIgZW5kIHVzZXJzLiBJdCBpcyB0eXBpY2FsbHkgdXNlZCBpbiBwYWdlcyB0aGF0IGVuZCB1c2VycyB3aWxsIGludGVyYWN0IHdpdGguIChUaGUgcmVsYXRlZCBbV29ybGQgQVBJIEFkYXB0ZXJdKC4uL3dvcmxkLWFwaS1hZGFwdGVyLykgaGFuZGxlcyBjcmVhdGluZyBtdWx0aXBsYXllciB3b3JsZHMsIGFuZCBhZGRpbmcgYW5kIHJlbW92aW5nIGVuZCB1c2VycyBhbmQgcnVucyBmcm9tIGEgd29ybGQuIEJlY2F1c2Ugb2YgdGhpcywgdHlwaWNhbGx5IHRoZSBXb3JsZCBBZGFwdGVyIGlzIHVzZWQgZm9yIGZhY2lsaXRhdG9yIHBhZ2VzIGluIHlvdXIgcHJvamVjdC4pXG4qXG4qICMjIyBVc2luZyB0aGUgV29ybGQgTWFuYWdlclxuKlxuKiBUbyB1c2UgdGhlIFdvcmxkIE1hbmFnZXIsIGluc3RhbnRpYXRlIGl0LiBUaGVuLCBtYWtlIGNhbGxzIHRvIGFueSBvZiB0aGUgbWV0aG9kcyB5b3UgbmVlZC5cbipcbiogV2hlbiB5b3UgaW5zdGFudGlhdGUgYSBXb3JsZCBNYW5hZ2VyLCB0aGUgd29ybGQncyBhY2NvdW50IGlkLCBwcm9qZWN0IGlkLCBhbmQgZ3JvdXAgYXJlIGF1dG9tYXRpY2FsbHkgdGFrZW4gZnJvbSB0aGUgc2Vzc2lvbiAodGhhbmtzIHRvIHRoZSBbQXV0aGVudGljYXRpb24gU2VydmljZV0oLi4vYXV0aC1hcGktc2VydmljZSkpLlxuKlxuKiBOb3RlIHRoYXQgdGhlIFdvcmxkIE1hbmFnZXIgZG9lcyAqbm90KiBjcmVhdGUgd29ybGRzIGF1dG9tYXRpY2FsbHkuIChUaGlzIGlzIGRpZmZlcmVudCB0aGFuIHRoZSBbUnVuIE1hbmFnZXJdKC4uL3J1bi1tYW5hZ2VyKS4pIEhvd2V2ZXIsIHlvdSBjYW4gcGFzcyBpbiBzcGVjaWZpYyBvcHRpb25zIHRvIGFueSBydW5zIGNyZWF0ZWQgYnkgdGhlIG1hbmFnZXIsIHVzaW5nIGEgYHJ1bmAgb2JqZWN0LlxuKlxuKiBUaGUgcGFyYW1ldGVycyBmb3IgY3JlYXRpbmcgYSBXb3JsZCBNYW5hZ2VyIGFyZTpcbipcbiogICAqIGBhY2NvdW50YDogVGhlICoqVGVhbSBJRCoqIGluIHRoZSBFcGljZW50ZXIgdXNlciBpbnRlcmZhY2UgZm9yIHRoaXMgcHJvamVjdC5cbiogICAqIGBwcm9qZWN0YDogVGhlICoqUHJvamVjdCBJRCoqIGZvciB0aGlzIHByb2plY3QuXG4qICAgKiBgZ3JvdXBgOiBUaGUgKipHcm91cCBOYW1lKiogZm9yIHRoaXMgd29ybGQuXG4qICAgKiBgcnVuYDogT3B0aW9ucyB0byB1c2Ugd2hlbiBjcmVhdGluZyBuZXcgcnVucyB3aXRoIHRoZSBtYW5hZ2VyLCBlLmcuIGBydW46IHsgZmlsZXM6IFsnZGF0YS54bHMnXSB9YC5cbiogICAqIGBydW4ubW9kZWxgOiBUaGUgbmFtZSBvZiB0aGUgcHJpbWFyeSBtb2RlbCBmaWxlIGZvciB0aGlzIHByb2plY3QuIFJlcXVpcmVkIGlmIHlvdSBoYXZlIG5vdCBhbHJlYWR5IHBhc3NlZCBpdCBpbiBhcyBwYXJ0IG9mIHRoZSBgb3B0aW9uc2AgcGFyYW1ldGVyIGZvciBhbiBlbmNsb3NpbmcgY2FsbC5cbipcbiogRm9yIGV4YW1wbGU6XG4qXG4qICAgICAgIHZhciB3TWdyID0gbmV3IEYubWFuYWdlci5Xb3JsZE1hbmFnZXIoe1xuKiAgICAgICAgICBhY2NvdW50OiAnYWNtZS1zaW11bGF0aW9ucycsXG4qICAgICAgICAgIHByb2plY3Q6ICdzdXBwbHktY2hhaW4tZ2FtZScsXG4qICAgICAgICAgIHJ1bjogeyBtb2RlbDogJ3N1cHBseS1jaGFpbi5weScgfSxcbiogICAgICAgICAgZ3JvdXA6ICd0ZWFtMSdcbiogICAgICAgfSk7XG4qXG4qICAgICAgIHdNZ3IuZ2V0Q3VycmVudFJ1bigpO1xuKi9cblxuJ3VzZSBzdHJpY3QnO1xuXG52YXIgV29ybGRBcGkgPSByZXF1aXJlKCcuLi9zZXJ2aWNlL3dvcmxkLWFwaS1hZGFwdGVyJyk7XG52YXIgUnVuTWFuYWdlciA9IHJlcXVpcmUoJy4vcnVuLW1hbmFnZXInKTtcbnZhciBBdXRoTWFuYWdlciA9IHJlcXVpcmUoJy4vYXV0aC1tYW5hZ2VyJyk7XG52YXIgd29ybGRBcGk7XG5cbmZ1bmN0aW9uIGJ1aWxkU3RyYXRlZ3kod29ybGRJZCwgZHRkKSB7XG5cbiAgICByZXR1cm4gZnVuY3Rpb24gQ3RvcihvcHRpb25zKSB7XG4gICAgICAgIHRoaXMub3B0aW9ucyA9IG9wdGlvbnM7XG5cbiAgICAgICAgJC5leHRlbmQodGhpcywge1xuICAgICAgICAgICAgcmVzZXQ6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ25vdCBpbXBsZW1lbnRkLiBOZWVkIGFwaSBjaGFuZ2VzJyk7XG4gICAgICAgICAgICB9LFxuXG4gICAgICAgICAgICBnZXRSdW46IGZ1bmN0aW9uIChydW5TZXJ2aWNlKSB7XG4gICAgICAgICAgICAgICAgdmFyIG1lID0gdGhpcztcbiAgICAgICAgICAgICAgICAvL2dldCBvciBjcmVhdGUhXG4gICAgICAgICAgICAgICAgLy8gTW9kZWwgaXMgcmVxdWlyZWQgaW4gdGhlIG9wdGlvbnNcbiAgICAgICAgICAgICAgICB2YXIgbW9kZWwgPSB0aGlzLm9wdGlvbnMucnVuLm1vZGVsIHx8IHRoaXMub3B0aW9ucy5tb2RlbDtcbiAgICAgICAgICAgICAgICByZXR1cm4gd29ybGRBcGkuZ2V0Q3VycmVudFJ1bklkKHsgbW9kZWw6IG1vZGVsLCBmaWx0ZXI6IHdvcmxkSWQgfSlcbiAgICAgICAgICAgICAgICAgICAgLnRoZW4oZnVuY3Rpb24gKHJ1bklkKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICByZXR1cm4gcnVuU2VydmljZS5sb2FkKHJ1bklkKTtcbiAgICAgICAgICAgICAgICAgICAgfSlcbiAgICAgICAgICAgICAgICAgICAgLnRoZW4oZnVuY3Rpb24gKHJ1bikge1xuICAgICAgICAgICAgICAgICAgICAgICAgZHRkLnJlc29sdmVXaXRoKG1lLCBbcnVuXSk7XG4gICAgICAgICAgICAgICAgICAgIH0pXG4gICAgICAgICAgICAgICAgICAgIC5mYWlsKGR0ZC5yZWplY3QpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgICk7XG4gICAgfTtcbn1cblxuXG5tb2R1bGUuZXhwb3J0cyA9IGZ1bmN0aW9uIChvcHRpb25zKSB7XG4gICAgdGhpcy5vcHRpb25zID0gb3B0aW9ucyB8fCB7IHJ1bjoge30sIHdvcmxkOiB7fSB9O1xuXG4gICAgJC5leHRlbmQodHJ1ZSwgdGhpcy5vcHRpb25zLCB0aGlzLm9wdGlvbnMucnVuKTtcbiAgICAkLmV4dGVuZCh0cnVlLCB0aGlzLm9wdGlvbnMsIHRoaXMub3B0aW9ucy53b3JsZCk7XG5cbiAgICB3b3JsZEFwaSA9IG5ldyBXb3JsZEFwaSh0aGlzLm9wdGlvbnMpO1xuICAgIHRoaXMuX2F1dGggPSBuZXcgQXV0aE1hbmFnZXIoKTtcbiAgICB2YXIgbWUgPSB0aGlzO1xuXG4gICAgdmFyIGFwaSA9IHtcblxuICAgICAgICAvKipcbiAgICAgICAgKiBSZXR1cm5zIHRoZSBjdXJyZW50IHdvcmxkIChvYmplY3QpIGFuZCBhbiBpbnN0YW5jZSBvZiB0aGUgW1dvcmxkIEFQSSBBZGFwdGVyXSguLi93b3JsZC1hcGktYWRhcHRlci8pLlxuICAgICAgICAqXG4gICAgICAgICogKipFeGFtcGxlKipcbiAgICAgICAgKlxuICAgICAgICAqICAgICAgIHdNZ3IuZ2V0Q3VycmVudFdvcmxkKClcbiAgICAgICAgKiAgICAgICAgICAgLnRoZW4oZnVuY3Rpb24od29ybGQsIHdvcmxkQWRhcHRlcikge1xuICAgICAgICAqICAgICAgICAgICAgICAgY29uc29sZS5sb2cod29ybGQuaWQpO1xuICAgICAgICAqICAgICAgICAgICAgICAgd29ybGRBZGFwdGVyLmdldEN1cnJlbnRSdW5JZCgpO1xuICAgICAgICAqICAgICAgICAgICB9KTtcbiAgICAgICAgKlxuICAgICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICAgICogQHBhcmFtIHtzdHJpbmd9IHVzZXJJZCAoT3B0aW9uYWwpIFRoZSBpZCBvZiB0aGUgdXNlciB3aG9zZSB3b3JsZCBpcyBiZWluZyBhY2Nlc3NlZC4gRGVmYXVsdHMgdG8gdGhlIHVzZXIgaW4gdGhlIGN1cnJlbnQgc2Vzc2lvbi5cbiAgICAgICAgKiBAcGFyYW0ge3N0cmluZ30gZ3JvdXBOYW1lIChPcHRpb25hbCkgVGhlIG5hbWUgb2YgdGhlIGdyb3VwIHdob3NlIHdvcmxkIGlzIGJlaW5nIGFjY2Vzc2VkLiBEZWZhdWx0cyB0byB0aGUgZ3JvdXAgZm9yIHRoZSB1c2VyIGluIHRoZSBjdXJyZW50IHNlc3Npb24uXG4gICAgICAgICogQHJldHVybiB7UHJvbWlzZX1cbiAgICAgICAgKi9cbiAgICAgICAgZ2V0Q3VycmVudFdvcmxkOiBmdW5jdGlvbiAodXNlcklkLCBncm91cE5hbWUpIHtcbiAgICAgICAgICAgIHZhciBzZXNzaW9uID0gdGhpcy5fYXV0aC5nZXRDdXJyZW50VXNlclNlc3Npb25JbmZvKCk7XG4gICAgICAgICAgICBpZiAoIXVzZXJJZCkge1xuICAgICAgICAgICAgICAgIHVzZXJJZCA9IHNlc3Npb24udXNlcklkO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgaWYgKCFncm91cE5hbWUpIHtcbiAgICAgICAgICAgICAgICBncm91cE5hbWUgPSBzZXNzaW9uLmdyb3VwTmFtZTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHJldHVybiB3b3JsZEFwaS5nZXRDdXJyZW50V29ybGRGb3JVc2VyKHVzZXJJZCwgZ3JvdXBOYW1lKTtcbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgKiBSZXR1cm5zIHRoZSBjdXJyZW50IHJ1biAob2JqZWN0KSBhbmQgYW4gaW5zdGFuY2Ugb2YgdGhlIFtSdW4gQVBJIFNlcnZpY2VdKC4uL3J1bi1hcGktc2VydmljZS8pLlxuICAgICAgICAqXG4gICAgICAgICogKipFeGFtcGxlKipcbiAgICAgICAgKlxuICAgICAgICAqICAgICAgIHdNZ3IuZ2V0Q3VycmVudFJ1bignbXlNb2RlbC5weScpXG4gICAgICAgICogICAgICAgICAgIC50aGVuKGZ1bmN0aW9uKHJ1biwgcnVuU2VydmljZSkge1xuICAgICAgICAqICAgICAgICAgICAgICAgY29uc29sZS5sb2cocnVuLmlkKTtcbiAgICAgICAgKiAgICAgICAgICAgICAgIHJ1blNlcnZpY2UuZG8oJ3N0YXJ0R2FtZScpO1xuICAgICAgICAqICAgICAgICAgICB9KTtcbiAgICAgICAgKlxuICAgICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICAgICogQHBhcmFtIHtzdHJpbmd9IG1vZGVsIChPcHRpb25hbCkgVGhlIG5hbWUgb2YgdGhlIG1vZGVsIGZpbGUuIFJlcXVpcmVkIGlmIG5vdCBhbHJlYWR5IHBhc3NlZCBpbiBhcyBgcnVuLm1vZGVsYCB3aGVuIHRoZSBXb3JsZCBNYW5hZ2VyIGlzIGNyZWF0ZWQuXG4gICAgICAgICogQHJldHVybiB7UHJvbWlzZX1cbiAgICAgICAgKi9cbiAgICAgICAgZ2V0Q3VycmVudFJ1bjogZnVuY3Rpb24gKG1vZGVsKSB7XG4gICAgICAgICAgICB2YXIgZHRkID0gJC5EZWZlcnJlZCgpO1xuICAgICAgICAgICAgdmFyIHNlc3Npb24gPSB0aGlzLl9hdXRoLmdldEN1cnJlbnRVc2VyU2Vzc2lvbkluZm8oKTtcbiAgICAgICAgICAgIHZhciBjdXJVc2VySWQgPSBzZXNzaW9uLnVzZXJJZDtcbiAgICAgICAgICAgIHZhciBjdXJHcm91cE5hbWUgPSBzZXNzaW9uLmdyb3VwTmFtZTtcblxuICAgICAgICAgICAgZnVuY3Rpb24gZ2V0QW5kUmVzdG9yZUxhdGVzdFJ1bih3b3JsZCkge1xuICAgICAgICAgICAgICAgIGlmICghd29ybGQpIHtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIGR0ZC5yZWplY3QoeyBlcnJvcjogJ1RoZSB1c2VyIGlzIG5vdCBwYXJ0IG9mIGFueSB3b3JsZCEnIH0pO1xuICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgIHZhciBjdXJyZW50V29ybGRJZCA9IHdvcmxkLmlkO1xuICAgICAgICAgICAgICAgIHZhciBydW5PcHRzID0gJC5leHRlbmQodHJ1ZSwgbWUub3B0aW9ucywgeyBtb2RlbDogbW9kZWwgfSk7XG4gICAgICAgICAgICAgICAgdmFyIHN0cmF0ZWd5ID0gYnVpbGRTdHJhdGVneShjdXJyZW50V29ybGRJZCwgZHRkKTtcbiAgICAgICAgICAgICAgICB2YXIgb3B0ID0gJC5leHRlbmQodHJ1ZSwge30sIHtcbiAgICAgICAgICAgICAgICAgICAgc3RyYXRlZ3k6IHN0cmF0ZWd5LFxuICAgICAgICAgICAgICAgICAgICBydW46IHJ1bk9wdHNcbiAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgICB2YXIgcm0gPSBuZXcgUnVuTWFuYWdlcihvcHQpO1xuICAgICAgICAgICAgICAgIHJldHVybiBybS5nZXRSdW4oKVxuICAgICAgICAgICAgICAgICAgICAudGhlbihmdW5jdGlvbiAocnVuKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBkdGQucmVzb2x2ZShydW4sIHJtLnJ1blNlcnZpY2UsIHJtKTtcbiAgICAgICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIHRoaXMuZ2V0Q3VycmVudFdvcmxkKGN1clVzZXJJZCwgY3VyR3JvdXBOYW1lKVxuICAgICAgICAgICAgICAgIC50aGVuKGdldEFuZFJlc3RvcmVMYXRlc3RSdW4pO1xuXG4gICAgICAgICAgICByZXR1cm4gZHRkLnByb21pc2UoKTtcbiAgICAgICAgfVxuICAgIH07XG5cbiAgICAkLmV4dGVuZCh0aGlzLCBhcGkpO1xufTtcbiIsIi8qKlxuICogIyMgRmlsZSBBUEkgU2VydmljZVxuICpcbiAqIFRoZSBGaWxlIEFQSSBTZXJ2aWNlIGFsbG93cyB5b3UgdG8gdXBsb2FkIGFuZCBkb3dubG9hZCBmaWxlcyBkaXJlY3RseSBvbnRvIEVwaWNlbnRlciwgYW5hbG9nb3VzIHRvIHVzaW5nIHRoZSBGaWxlIE1hbmFnZXIgVUkgaW4gRXBpY2VudGVyIGRpcmVjdGx5IG9yIFNGVFBpbmcgZmlsZXMgaW4uIEl0IGlzIGJhc2VkIG9uIHRoZSBFcGljZW50ZXIgRmlsZSBBUEkuXG4gKlxuICogICAgICAgdmFyIGZhID0gbmV3IEYuc2VydmljZS5GaWxlKHtcbiAqICAgICAgICAgIGFjY291bnQ6ICdhY21lLXNpbXVsYXRpb25zJyxcbiAqICAgICAgICAgIHByb2plY3Q6ICdzdXBwbHktY2hhaW4tZ2FtZScsXG4gKiAgICAgICB9KTtcbiAqICAgICAgIGZhLmNyZWF0ZSgndGVzdC50eHQnLCAndGhlc2UgYXJlIG15IGZpbGVjb250ZW50cycpO1xuICpcbiAqICAgICAgIC8vIGFsdGVybmF0aXZlbHksIGNyZWF0ZSBhIG5ldyBmaWxlIHVzaW5nIGEgZmlsZSB1cGxvYWRlZCB0aHJvdWdoIGEgZmlsZSBpbnB1dFxuICogICAgICAgLy8gPGlucHV0IGlkPVwiZmlsZXVwbG9hZFwiIHR5cGU9XCJmaWxlXCI+XG4gKiAgICAgICAvL1xuICogICAgICAgJCgnI2ZpbGV1cGxvYWQnKS5vbignY2hhbmdlJywgZnVuY3Rpb24gKGUpIHtcbiAqICAgICAgICAgIHZhciBmaWxlID0gZS50YXJnZXQuZmlsZXNbMF07XG4gKiAgICAgICAgICB2YXIgZGF0YSA9IG5ldyBGb3JtRGF0YSgpO1xuICogICAgICAgICAgZGF0YS5hcHBlbmQoJ2ZpbGUnLCBmaWxlLCBmaWxlLm5hbWUpO1xuICogICAgICAgICAgZmEuY3JlYXRlKGZpbGUubmFtZSwgZGF0YSk7XG4gKiAgICAgICB9KTtcbiAqL1xuXG4ndXNlIHN0cmljdCc7XG5cbnZhciBDb25maWdTZXJ2aWNlID0gcmVxdWlyZSgnLi9jb25maWd1cmF0aW9uLXNlcnZpY2UnKTtcbnZhciBUcmFuc3BvcnRGYWN0b3J5ID0gcmVxdWlyZSgnLi4vdHJhbnNwb3J0L2h0dHAtdHJhbnNwb3J0LWZhY3RvcnknKTtcbnZhciBTZXNzaW9uTWFuYWdlciA9IHJlcXVpcmUoJy4uL3N0b3JlL3Nlc3Npb24tbWFuYWdlcicpO1xuXG5tb2R1bGUuZXhwb3J0cyA9IGZ1bmN0aW9uIChjb25maWcpIHtcbiAgICB2YXIgZGVmYXVsdHMgPSB7XG4gICAgICAgIC8qKlxuICAgICAgICAgKiBGb3IgcHJvamVjdHMgdGhhdCByZXF1aXJlIGF1dGhlbnRpY2F0aW9uLCBwYXNzIGluIHRoZSB1c2VyIGFjY2VzcyB0b2tlbiAoZGVmYXVsdHMgdG8gZW1wdHkgc3RyaW5nKS4gSWYgdGhlIHVzZXIgaXMgYWxyZWFkeSBsb2dnZWQgaW4gdG8gRXBpY2VudGVyLCB0aGUgdXNlciBhY2Nlc3MgdG9rZW4gaXMgYWxyZWFkeSBzZXQgaW4gYSBjb29raWUgYW5kIGF1dG9tYXRpY2FsbHkgbG9hZGVkIGZyb20gdGhlcmUuIChTZWUgW21vcmUgYmFja2dyb3VuZCBvbiBhY2Nlc3MgdG9rZW5zXSguLi8uLi8uLi9wcm9qZWN0X2FjY2Vzcy8pKS5cbiAgICAgICAgICogQHNlZSBbQXV0aGVudGljYXRpb24gQVBJIFNlcnZpY2VdKC4uL2F1dGgtYXBpLXNlcnZpY2UvKSBmb3IgZ2V0dGluZyB0b2tlbnMuXG4gICAgICAgICAqIEB0eXBlIHtTdHJpbmd9XG4gICAgICAgICAqL1xuICAgICAgICB0b2tlbjogdW5kZWZpbmVkLFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBUaGUgYWNjb3VudCBpZC4gSW4gdGhlIEVwaWNlbnRlciBVSSwgdGhpcyBpcyB0aGUgKipUZWFtIElEKiogKGZvciB0ZWFtIHByb2plY3RzKSBvciAqKlVzZXIgSUQqKiAoZm9yIHBlcnNvbmFsIHByb2plY3RzKS4gRGVmYXVsdHMgdG8gdW5kZWZpbmVkLlxuICAgICAgICAgKiBAdHlwZSB7U3RyaW5nfVxuICAgICAgICAgKi9cbiAgICAgICAgYWNjb3VudDogdW5kZWZpbmVkLFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBUaGUgcHJvamVjdCBpZC4gRGVmYXVsdHMgdG8gdW5kZWZpbmVkLlxuICAgICAgICAgKiBAdHlwZSB7U3RyaW5nfVxuICAgICAgICAgKi9cbiAgICAgICAgcHJvamVjdDogdW5kZWZpbmVkLFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBUaGUgZm9sZGVyIHR5cGUuICBPbmUgb2YgYG1vZGVsYCB8IGBzdGF0aWNgIHwgYG5vZGVgLlxuICAgICAgICAgKiBAdHlwZSB7U3RyaW5nfVxuICAgICAgICAgKi9cbiAgICAgICAgZm9sZGVyVHlwZTogJ3N0YXRpYycsXG5cblxuICAgICAgICAvKipcbiAgICAgICAgICogT3B0aW9ucyB0byBwYXNzIG9uIHRvIHRoZSB1bmRlcmx5aW5nIHRyYW5zcG9ydCBsYXllci4gQWxsIGpxdWVyeS5hamF4IG9wdGlvbnMgYXQgaHR0cDovL2FwaS5qcXVlcnkuY29tL2pRdWVyeS5hamF4LyBhcmUgYXZhaWxhYmxlLiBEZWZhdWx0cyB0byBlbXB0eSBvYmplY3QuXG4gICAgICAgICAqIEB0eXBlIHtPYmplY3R9XG4gICAgICAgICAqL1xuICAgICAgICB0cmFuc3BvcnQ6IHt9XG4gICAgfTtcblxuICAgIHRoaXMuc2Vzc2lvbk1hbmFnZXIgPSBuZXcgU2Vzc2lvbk1hbmFnZXIoKTtcbiAgICB2YXIgc2VydmljZU9wdGlvbnMgPSB0aGlzLnNlc3Npb25NYW5hZ2VyLmdldE1lcmdlZE9wdGlvbnMoZGVmYXVsdHMsIGNvbmZpZyk7XG4gICAgdmFyIHVybENvbmZpZyA9IG5ldyBDb25maWdTZXJ2aWNlKHNlcnZpY2VPcHRpb25zKS5nZXQoJ3NlcnZlcicpO1xuICAgIGlmIChzZXJ2aWNlT3B0aW9ucy5hY2NvdW50KSB7XG4gICAgICAgIHVybENvbmZpZy5hY2NvdW50UGF0aCA9IHNlcnZpY2VPcHRpb25zLmFjY291bnQ7XG4gICAgfVxuICAgIGlmIChzZXJ2aWNlT3B0aW9ucy5wcm9qZWN0KSB7XG4gICAgICAgIHVybENvbmZpZy5wcm9qZWN0UGF0aCA9IHNlcnZpY2VPcHRpb25zLnByb2plY3Q7XG4gICAgfVxuXG4gICAgdmFyIGh0dHBPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sIHNlcnZpY2VPcHRpb25zLnRyYW5zcG9ydCwge1xuICAgICAgICB1cmw6IHVybENvbmZpZy5nZXRBUElQYXRoKCdmaWxlJylcbiAgICB9KTtcblxuICAgIGlmIChzZXJ2aWNlT3B0aW9ucy50b2tlbikge1xuICAgICAgICBodHRwT3B0aW9ucy5oZWFkZXJzID0ge1xuICAgICAgICAgICAgQXV0aG9yaXphdGlvbjogJ0JlYXJlciAnICsgc2VydmljZU9wdGlvbnMudG9rZW5cbiAgICAgICAgfTtcbiAgICB9XG4gICAgdmFyIGh0dHAgPSBuZXcgVHJhbnNwb3J0RmFjdG9yeShodHRwT3B0aW9ucyk7XG5cbiAgICBmdW5jdGlvbiB1cGxvYWRCb2R5KGZpbGVOYW1lLCBjb250ZW50cykge1xuICAgICAgICB2YXIgYm91bmRhcnkgPSAnLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tN2RhMjRmMmU1MDA0Nic7XG5cbiAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICAgIGJvZHk6ICctLScgKyBib3VuZGFyeSArICdcXHJcXG4nICtcbiAgICAgICAgICAgICAgICAgICAgJ0NvbnRlbnQtRGlzcG9zaXRpb246IGZvcm0tZGF0YTsgbmFtZT1cImZpbGVcIjsnICtcbiAgICAgICAgICAgICAgICAgICAgJ2ZpbGVuYW1lPVwiJyArIGZpbGVOYW1lICsgJ1wiXFxyXFxuJyArXG4gICAgICAgICAgICAgICAgICAgICdDb250ZW50LXR5cGU6IHRleHQvaHRtbFxcclxcblxcclxcbicgK1xuICAgICAgICAgICAgICAgICAgICBjb250ZW50cyArICdcXHJcXG4nICtcbiAgICAgICAgICAgICAgICAgICAgJy0tJyArIGJvdW5kYXJ5ICsgJy0tJyxcbiAgICAgICAgICAgIGJvdW5kYXJ5OiBib3VuZGFyeVxuICAgICAgICB9O1xuICAgIH1cblxuICAgIGZ1bmN0aW9uIHVwbG9hZEZpbGVPcHRpb25zKGZpbGVQYXRoLCBjb250ZW50cywgb3B0aW9ucykge1xuICAgICAgICBmaWxlUGF0aCA9IGZpbGVQYXRoLnNwbGl0KCcvJyk7XG4gICAgICAgIHZhciBmaWxlTmFtZSA9IGZpbGVQYXRoLnBvcCgpO1xuICAgICAgICBmaWxlUGF0aCA9IGZpbGVQYXRoLmpvaW4oJy8nKTtcbiAgICAgICAgdmFyIHBhdGggPSBzZXJ2aWNlT3B0aW9ucy5mb2xkZXJUeXBlICsgJy8nICsgZmlsZVBhdGg7XG5cbiAgICAgICAgdmFyIGV4dHJhUGFyYW1zID0ge307XG4gICAgICAgIGlmIChjb250ZW50cyBpbnN0YW5jZW9mIEZvcm1EYXRhKSB7XG4gICAgICAgICAgICBleHRyYVBhcmFtcyA9IHtcbiAgICAgICAgICAgICAgICBkYXRhOiBjb250ZW50cyxcbiAgICAgICAgICAgICAgICBwcm9jZXNzRGF0YTogZmFsc2UsXG4gICAgICAgICAgICAgICAgY29udGVudFR5cGU6IGZhbHNlLFxuICAgICAgICAgICAgfTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIHZhciB1cGxvYWQgPSB1cGxvYWRCb2R5KGZpbGVOYW1lLCBjb250ZW50cyk7XG4gICAgICAgICAgICBleHRyYVBhcmFtcyA9IHtcbiAgICAgICAgICAgICAgICBkYXRhOiB1cGxvYWQuYm9keSxcbiAgICAgICAgICAgICAgICBjb250ZW50VHlwZTogJ211bHRpcGFydC9mb3JtLWRhdGE7IGJvdW5kYXJ5PScgKyB1cGxvYWQuYm91bmRhcnlcbiAgICAgICAgICAgIH07XG4gICAgICAgIH1cblxuICAgICAgICByZXR1cm4gJC5leHRlbmQodHJ1ZSwge30sIHNlcnZpY2VPcHRpb25zLCBvcHRpb25zLCB7XG4gICAgICAgICAgICB1cmw6IHVybENvbmZpZy5nZXRBUElQYXRoKCdmaWxlJykgKyBwYXRoLFxuICAgICAgICB9LCBleHRyYVBhcmFtcyk7XG4gICAgfVxuXG4gICAgdmFyIHB1YmxpY0FzeW5jQVBJID0ge1xuICAgICAgICAvKipcbiAgICAgICAgICogR2V0IGEgZGlyZWN0b3J5IGxpc3RpbmcsIG9yIGNvbnRlbnRzIG9mIGEgZmlsZS5cbiAgICAgICAgICogQHBhcmFtIHtTdHJpbmd9IGZpbGVQYXRoICBQYXRoIHRvIHRoZSBmaWxlXG4gICAgICAgICAqIEBwYXJhbSB7T2JqZWN0fSBvcHRpb25zIChPcHRpb25hbCkgT3ZlcnJpZGVzIGZvciBjb25maWd1cmF0aW9uIG9wdGlvbnMuXG4gICAgICAgICAqIEByZXR1cm4ge1Byb21pc2V9XG4gICAgICAgICAqL1xuICAgICAgICBnZXRDb250ZW50czogZnVuY3Rpb24gKGZpbGVQYXRoLCBvcHRpb25zKSB7XG4gICAgICAgICAgICB2YXIgcGF0aCA9IHNlcnZpY2VPcHRpb25zLmZvbGRlclR5cGUgKyAnLycgKyBmaWxlUGF0aDtcbiAgICAgICAgICAgIHZhciBodHRwT3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LCBzZXJ2aWNlT3B0aW9ucywgb3B0aW9ucywge1xuICAgICAgICAgICAgICAgIHVybDogdXJsQ29uZmlnLmdldEFQSVBhdGgoJ2ZpbGUnKSArIHBhdGhcbiAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgcmV0dXJuIGh0dHAuZ2V0KCcnLCBodHRwT3B0aW9ucyk7XG4gICAgICAgIH0sXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIFJlcGxhY2VzIHRoZSBmaWxlIGF0IHRoZSBnaXZlbiBmaWxlIHBhdGguXG4gICAgICAgICAqIEBwYXJhbSAge1N0cmluZ30gZmlsZVBhdGggUGF0aCB0byB0aGUgZmlsZVxuICAgICAgICAgKiBAcGFyYW0gIHtTdHJpbmcgfCBGb3JtRGF0YSB9IGNvbnRlbnRzIENvbnRlbnRzIHRvIHdyaXRlIHRvIGZpbGVcbiAgICAgICAgICogQHBhcmFtICB7T2JqZWN0fSBvcHRpb25zICAoT3B0aW9uYWwpIE92ZXJyaWRlcyBmb3IgY29uZmlndXJhdGlvbiBvcHRpb25zXG4gICAgICAgICAqIEByZXR1cm4ge1Byb21pc2V9XG4gICAgICAgICAqL1xuICAgICAgICByZXBsYWNlOiBmdW5jdGlvbiAoZmlsZVBhdGgsIGNvbnRlbnRzLCBvcHRpb25zKSB7XG4gICAgICAgICAgICB2YXIgaHR0cE9wdGlvbnMgPSB1cGxvYWRGaWxlT3B0aW9ucyhmaWxlUGF0aCwgY29udGVudHMsIG9wdGlvbnMpO1xuICAgICAgICAgICAgcmV0dXJuIGh0dHAucHV0KGh0dHBPcHRpb25zLmRhdGEsIGh0dHBPcHRpb25zKTtcbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgICogQ3JlYXRlcyBhIGZpbGUgaW4gdGhlIGdpdmVuIGZpbGUgcGF0aC5cbiAgICAgICAgICogQHBhcmFtICB7U3RyaW5nfSBmaWxlUGF0aCBQYXRoIHRvIHRoZSBmaWxlXG4gICAgICAgICAqIEBwYXJhbSAge1N0cmluZyB8IEZvcm1EYXRhIH0gY29udGVudHMgQ29udGVudHMgdG8gd3JpdGUgdG8gZmlsZVxuICAgICAgICAgKiBAcGFyYW0gIHtCb29sZWFufSByZXBsYWNlRXhpc3RpbmcgUmVwbGFjZSBmaWxlIGlmIGl0IGFscmVhZHkgZXhpc3RzOyBkZWZhdWx0cyB0byBmYWxzZVxuICAgICAgICAgKiBAcGFyYW0gIHtPYmplY3R9IG9wdGlvbnMgKE9wdGlvbmFsKSBPdmVycmlkZXMgZm9yIGNvbmZpZ3VyYXRpb24gb3B0aW9uc1xuICAgICAgICAgKiBAcmV0dXJuIHtQcm9taXNlfVxuICAgICAgICAgKi9cbiAgICAgICAgY3JlYXRlOiBmdW5jdGlvbiAoZmlsZVBhdGgsIGNvbnRlbnRzLCByZXBsYWNlRXhpc3RpbmcsIG9wdGlvbnMpIHtcbiAgICAgICAgICAgIHZhciBodHRwT3B0aW9ucyA9IHVwbG9hZEZpbGVPcHRpb25zKGZpbGVQYXRoLCBjb250ZW50cywgb3B0aW9ucyk7XG4gICAgICAgICAgICB2YXIgcHJvbSA9IGh0dHAucG9zdChodHRwT3B0aW9ucy5kYXRhLCBodHRwT3B0aW9ucyk7XG4gICAgICAgICAgICB2YXIgbWUgPSB0aGlzO1xuICAgICAgICAgICAgaWYgKHJlcGxhY2VFeGlzdGluZyA9PT0gdHJ1ZSkge1xuICAgICAgICAgICAgICAgIHByb20gPSBwcm9tLnRoZW4obnVsbCwgZnVuY3Rpb24gKHhocikge1xuICAgICAgICAgICAgICAgICAgICB2YXIgY29uZmxpY3RTdGF0dXMgPSA0MDk7XG4gICAgICAgICAgICAgICAgICAgIGlmICh4aHIuc3RhdHVzID09PSBjb25mbGljdFN0YXR1cykge1xuICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIG1lLnJlcGxhY2UoZmlsZVBhdGgsIGNvbnRlbnRzLCBvcHRpb25zKTtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgcmV0dXJuIHByb207XG4gICAgICAgIH0sXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIFJlbW92ZXMgdGhlIGZpbGUuXG4gICAgICAgICAqIEBwYXJhbSAge1N0cmluZ30gZmlsZVBhdGggUGF0aCB0byB0aGUgZmlsZVxuICAgICAgICAgKiBAcGFyYW0gIHtPYmplY3R9IG9wdGlvbnMgIChPcHRpb25hbCkgT3ZlcnJpZGVzIGZvciBjb25maWd1cmF0aW9uIG9wdGlvbnNcbiAgICAgICAgICogQHJldHVybiB7UHJvbWlzZX1cbiAgICAgICAgICovXG4gICAgICAgIHJlbW92ZTogZnVuY3Rpb24gKGZpbGVQYXRoLCBvcHRpb25zKSB7XG4gICAgICAgICAgICB2YXIgcGF0aCA9IHNlcnZpY2VPcHRpb25zLmZvbGRlclR5cGUgKyAnLycgKyBmaWxlUGF0aDtcbiAgICAgICAgICAgIHZhciBodHRwT3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LCBzZXJ2aWNlT3B0aW9ucywgb3B0aW9ucywge1xuICAgICAgICAgICAgICAgIHVybDogdXJsQ29uZmlnLmdldEFQSVBhdGgoJ2ZpbGUnKSArIHBhdGhcbiAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgcmV0dXJuIGh0dHAuZGVsZXRlKG51bGwsIGh0dHBPcHRpb25zKTtcbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgICogUmVuYW1lcyB0aGUgZmlsZS5cbiAgICAgICAgICogQHBhcmFtICB7U3RyaW5nfSBmaWxlUGF0aCBQYXRoIHRvIHRoZSBmaWxlXG4gICAgICAgICAqIEBwYXJhbSAge1N0cmluZ30gbmV3TmFtZSAgTmV3IG5hbWUgb2YgZmlsZVxuICAgICAgICAgKiBAcGFyYW0gIHtPYmplY3R9IG9wdGlvbnMgIChPcHRpb25hbCkgT3ZlcnJpZGVzIGZvciBjb25maWd1cmF0aW9uIG9wdGlvbnNcbiAgICAgICAgICogQHJldHVybiB7UHJvbWlzZX1cbiAgICAgICAgICovXG4gICAgICAgIHJlbmFtZTogZnVuY3Rpb24gKGZpbGVQYXRoLCBuZXdOYW1lLCBvcHRpb25zKSB7XG4gICAgICAgICAgICB2YXIgcGF0aCA9IHNlcnZpY2VPcHRpb25zLmZvbGRlclR5cGUgKyAnLycgKyBmaWxlUGF0aDtcbiAgICAgICAgICAgIHZhciBodHRwT3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LCBzZXJ2aWNlT3B0aW9ucywgb3B0aW9ucywge1xuICAgICAgICAgICAgICAgIHVybDogdXJsQ29uZmlnLmdldEFQSVBhdGgoJ2ZpbGUnKSArIHBhdGhcbiAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgcmV0dXJuIGh0dHAucGF0Y2goeyBuYW1lOiBuZXdOYW1lIH0sIGh0dHBPcHRpb25zKTtcbiAgICAgICAgfVxuICAgIH07XG5cbiAgICAkLmV4dGVuZCh0aGlzLCBwdWJsaWNBc3luY0FQSSk7XG59O1xuIiwiLyoqXG4gKiAjIyBBc3NldCBBUEkgQWRhcHRlclxuICpcbiAqIFRoZSBBc3NldCBBUEkgQWRhcHRlciBhbGxvd3MgeW91IHRvIHN0b3JlIGFzc2V0cyAtLSByZXNvdXJjZXMgb3IgZmlsZXMgb2YgYW55IGtpbmQgLS0gdXNlZCBieSBhIHByb2plY3Qgd2l0aCBhIHNjb3BlIHRoYXQgaXMgc3BlY2lmaWMgdG8gcHJvamVjdCwgZ3JvdXAsIG9yIGVuZCB1c2VyLlxuICpcbiAqIEFzc2V0cyBhcmUgdXNlZCB3aXRoIFt0ZWFtIHByb2plY3RzXSguLi8uLi8uLi9wcm9qZWN0X2FkbWluLyN0ZWFtKS4gT25lIGNvbW1vbiB1c2UgY2FzZSBpcyBoYXZpbmcgZW5kIHVzZXJzIGluIGEgW2dyb3VwXSguLi8uLi8uLi9nbG9zc2FyeS8jZ3JvdXBzKSBvciBpbiBhIFttdWx0aXBsYXllciB3b3JsZF0oLi4vLi4vLi4vZ2xvc3NhcnkvI3dvcmxkKSB1cGxvYWQgZGF0YSAtLSB2aWRlb3MgY3JlYXRlZCBkdXJpbmcgZ2FtZSBwbGF5LCBwcm9maWxlIHBpY3R1cmVzIGZvciBjdXN0b21pemluZyB0aGVpciBleHBlcmllbmNlLCBldGMuIC0tIGFzIHBhcnQgb2YgcGxheWluZyB0aHJvdWdoIHRoZSBwcm9qZWN0LlxuICpcbiAqIFJlc291cmNlcyBjcmVhdGVkIHVzaW5nIHRoZSBBc3NldCBBZGFwdGVyIGFyZSBzY29wZWQ6XG4gKlxuICogICogUHJvamVjdCBhc3NldHMgYXJlIHdyaXRhYmxlIG9ubHkgYnkgW3RlYW0gbWVtYmVyc10oLi4vLi4vLi4vZ2xvc3NhcnkvI3RlYW0pLCB0aGF0IGlzLCBFcGljZW50ZXIgYXV0aG9ycy5cbiAqICAqIEdyb3VwIGFzc2V0cyBhcmUgd3JpdGFibGUgYnkgYW55b25lIHdpdGggYWNjZXNzIHRvIHRoZSBwcm9qZWN0IHRoYXQgaXMgcGFydCBvZiB0aGF0IHBhcnRpY3VsYXIgW2dyb3VwXSguLi8uLi8uLi9nbG9zc2FyeS8jZ3JvdXBzKS4gVGhpcyBpbmNsdWRlcyBhbGwgW3RlYW0gbWVtYmVyc10oLi4vLi4vLi4vZ2xvc3NhcnkvI3RlYW0pIChFcGljZW50ZXIgYXV0aG9ycykgYW5kIGFueSBbZW5kIHVzZXJzXSguLi8uLi8uLi9nbG9zc2FyeS8jdXNlcnMpIHdobyBhcmUgbWVtYmVycyBvZiB0aGUgZ3JvdXAgLS0gYm90aCBmYWNpbGl0YXRvcnMgYW5kIHN0YW5kYXJkIGVuZCB1c2Vycy5cbiAqICAqIFVzZXIgYXNzZXRzIGFyZSB3cml0YWJsZSBieSB0aGUgc3BlY2lmaWMgZW5kIHVzZXIsIGFuZCBieSB0aGUgZmFjaWxpdGF0b3Igb2YgdGhlIGdyb3VwLlxuICogICogQWxsIGFzc2V0cyBhcmUgcmVhZGFibGUgYnkgYW55b25lIHdpdGggdGhlIGV4YWN0IFVSSS5cbiAqXG4gKiBUbyB1c2UgdGhlIEFzc2V0IEFkYXB0ZXIsIGluc3RhbnRpYXRlIGl0IGFuZCB0aGVuIGFjY2VzcyB0aGUgbWV0aG9kcyBwcm92aWRlZC4gSW5zdGFudGlhdGluZyByZXF1aXJlcyB0aGUgYWNjb3VudCBpZCAoKipUZWFtIElEKiogaW4gdGhlIEVwaWNlbnRlciB1c2VyIGludGVyZmFjZSkgYW5kIHByb2plY3QgaWQgKCoqUHJvamVjdCBJRCoqKS4gVGhlIGdyb3VwIG5hbWUgaXMgcmVxdWlyZWQgZm9yIGFzc2V0cyB3aXRoIGEgZ3JvdXAgc2NvcGUsIGFuZCB0aGUgZ3JvdXAgbmFtZSBhbmQgdXNlcklkIGFyZSByZXF1aXJlZCBmb3IgYXNzZXRzIHdpdGggYSB1c2VyIHNjb3BlLiBJZiBub3QgaW5jbHVkZWQsIHRoZXkgYXJlIHRha2VuIGZyb20gdGhlIGxvZ2dlZCBpbiB1c2VyJ3Mgc2Vzc2lvbiBpbmZvcm1hdGlvbiBpZiBuZWVkZWQuXG4gKlxuICogV2hlbiBjcmVhdGluZyBhbiBhc3NldCwgeW91IGNhbiBwYXNzIGluIHRleHQgKGVuY29kZWQgZGF0YSkgdG8gdGhlIGBjcmVhdGUoKWAgY2FsbC4gQWx0ZXJuYXRpdmVseSwgeW91IGNhbiBtYWtlIHRoZSBgY3JlYXRlKClgIGNhbGwgYXMgcGFydCBvZiBhbiBIVE1MIGZvcm0gYW5kIHBhc3MgaW4gYSBmaWxlIHVwbG9hZGVkIHZpYSB0aGUgZm9ybS5cbiAqXG4gKiAgICAgICAvLyBpbnN0YW50aWF0ZSB0aGUgQXNzZXQgQWRhcHRlclxuICogICAgICAgdmFyIGFhID0gbmV3IEYuc2VydmljZS5Bc3NldCh7XG4gKiAgICAgICAgICBhY2NvdW50OiAnYWNtZS1zaW11bGF0aW9ucycsXG4gKiAgICAgICAgICBwcm9qZWN0OiAnc3VwcGx5LWNoYWluLWdhbWUnLFxuICogICAgICAgICAgZ3JvdXA6ICd0ZWFtMScsXG4gKiAgICAgICAgICB1c2VySWQ6ICcxMjM0NSdcbiAqICAgICAgIH0pO1xuICpcbiAqICAgICAgIC8vIGNyZWF0ZSBhIG5ldyBhc3NldCB1c2luZyBlbmNvZGVkIHRleHRcbiAqICAgICAgIGFhLmNyZWF0ZSgndGVzdC50eHQnLCB7XG4gKiAgICAgICAgICAgZW5jb2Rpbmc6ICdCQVNFXzY0JyxcbiAqICAgICAgICAgICBkYXRhOiAnVkdocGN5QnBjeUJoSUhSbGMzUWdabWxzWlM0PScsXG4gKiAgICAgICAgICAgY29udGVudFR5cGU6ICd0ZXh0L3BsYWluJ1xuICogICAgICAgfSwgeyBzY29wZTogJ3VzZXInIH0pO1xuICpcbiAqICAgICAgIC8vIGFsdGVybmF0aXZlbHksIGNyZWF0ZSBhIG5ldyBhc3NldCB1c2luZyBhIGZpbGUgdXBsb2FkZWQgdGhyb3VnaCBhIGZvcm1cbiAqICAgICAgIC8vIHRoaXMgc2FtcGxlIGNvZGUgZ29lcyB3aXRoIGFuIGh0bWwgZm9ybSB0aGF0IGxvb2tzIGxpa2UgdGhpczpcbiAqICAgICAgIC8vXG4gKiAgICAgICAvLyA8Zm9ybSBpZD1cInVwbG9hZC1maWxlXCI+XG4gKiAgICAgICAvLyAgIDxpbnB1dCBpZD1cImZpbGVcIiB0eXBlPVwiZmlsZVwiPlxuICogICAgICAgLy8gICA8aW5wdXQgaWQ9XCJmaWxlbmFtZVwiIHR5cGU9XCJ0ZXh0XCIgdmFsdWU9XCJteUZpbGUudHh0XCI+XG4gKiAgICAgICAvLyAgIDxidXR0b24gdHlwZT1cInN1Ym1pdFwiPlVwbG9hZCBteUZpbGU8L2J1dHRvbj5cbiAqICAgICAgIC8vIDwvZm9ybT5cbiAqICAgICAgIC8vXG4gKiAgICAgICAkKCcjdXBsb2FkLWZpbGUnKS5vbignc3VibWl0JywgZnVuY3Rpb24gKGUpIHtcbiAqICAgICAgICAgIGUucHJldmVudERlZmF1bHQoKTtcbiAqICAgICAgICAgIHZhciBmaWxlbmFtZSA9ICQoJyNmaWxlbmFtZScpLnZhbCgpO1xuICogICAgICAgICAgdmFyIGRhdGEgPSBuZXcgRm9ybURhdGEoKTtcbiAqICAgICAgICAgIHZhciBpbnB1dENvbnRyb2wgPSAkKCcjZmlsZScpWzBdO1xuICogICAgICAgICAgZGF0YS5hcHBlbmQoJ2ZpbGUnLCBpbnB1dENvbnRyb2wuZmlsZXNbMF0sIGZpbGVuYW1lKTtcbiAqXG4gKiAgICAgICAgICBhYS5jcmVhdGUoZmlsZW5hbWUsIGRhdGEsIHsgc2NvcGU6ICd1c2VyJyB9KTtcbiAqICAgICAgIH0pO1xuICpcbiAqL1xuXG4ndXNlIHN0cmljdCc7XG5cbnZhciBDb25maWdTZXJ2aWNlID0gcmVxdWlyZSgnLi9jb25maWd1cmF0aW9uLXNlcnZpY2UnKTtcbnZhciBUcmFuc3BvcnRGYWN0b3J5ID0gcmVxdWlyZSgnLi4vdHJhbnNwb3J0L2h0dHAtdHJhbnNwb3J0LWZhY3RvcnknKTtcbnZhciBfcGljayA9IHJlcXVpcmUoJy4uL3V0aWwvb2JqZWN0LXV0aWwnKS5fcGljaztcbnZhciBTZXNzaW9uTWFuYWdlciA9IHJlcXVpcmUoJy4uL3N0b3JlL3Nlc3Npb24tbWFuYWdlcicpO1xuXG52YXIgYXBpRW5kcG9pbnQgPSAnYXNzZXQnO1xuXG5tb2R1bGUuZXhwb3J0cyA9IGZ1bmN0aW9uIChjb25maWcpIHtcbiAgICB2YXIgZGVmYXVsdHMgPSB7XG4gICAgICAgIC8qKlxuICAgICAgICAgKiBGb3IgcHJvamVjdHMgdGhhdCByZXF1aXJlIGF1dGhlbnRpY2F0aW9uLCBwYXNzIGluIHRoZSB1c2VyIGFjY2VzcyB0b2tlbiAoZGVmYXVsdHMgdG8gZW1wdHkgc3RyaW5nKS4gSWYgdGhlIHVzZXIgaXMgYWxyZWFkeSBsb2dnZWQgaW4gdG8gRXBpY2VudGVyLCB0aGUgdXNlciBhY2Nlc3MgdG9rZW4gaXMgYWxyZWFkeSBzZXQgaW4gYSBjb29raWUgYW5kIGF1dG9tYXRpY2FsbHkgbG9hZGVkIGZyb20gdGhlcmUuIChTZWUgW21vcmUgYmFja2dyb3VuZCBvbiBhY2Nlc3MgdG9rZW5zXSguLi8uLi8uLi9wcm9qZWN0X2FjY2Vzcy8pKS5cbiAgICAgICAgICogQHNlZSBbQXV0aGVudGljYXRpb24gQVBJIFNlcnZpY2VdKC4uL2F1dGgtYXBpLXNlcnZpY2UvKSBmb3IgZ2V0dGluZyB0b2tlbnMuXG4gICAgICAgICAqIEB0eXBlIHtTdHJpbmd9XG4gICAgICAgICAqL1xuICAgICAgICB0b2tlbjogdW5kZWZpbmVkLFxuICAgICAgICAvKipcbiAgICAgICAgICogVGhlIGFjY291bnQgaWQuIEluIHRoZSBFcGljZW50ZXIgVUksIHRoaXMgaXMgdGhlICoqVGVhbSBJRCoqIChmb3IgdGVhbSBwcm9qZWN0cykuIElmIGxlZnQgdW5kZWZpbmVkLCB0YWtlbiBmcm9tIHRoZSBVUkwuXG4gICAgICAgICAqIEB0eXBlIHtTdHJpbmd9XG4gICAgICAgICAqL1xuICAgICAgICBhY2NvdW50OiB1bmRlZmluZWQsXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBUaGUgcHJvamVjdCBpZC4gSWYgbGVmdCB1bmRlZmluZWQsIHRha2VuIGZyb20gdGhlIFVSTC5cbiAgICAgICAgICogQHR5cGUge1N0cmluZ31cbiAgICAgICAgICovXG4gICAgICAgIHByb2plY3Q6IHVuZGVmaW5lZCxcbiAgICAgICAgLyoqXG4gICAgICAgICAqIFRoZSBncm91cCBuYW1lLiBEZWZhdWx0cyB0byBzZXNzaW9uJ3MgYGdyb3VwTmFtZWAuXG4gICAgICAgICAqIEB0eXBlIHtTdHJpbmd9XG4gICAgICAgICAqL1xuICAgICAgICBncm91cDogdW5kZWZpbmVkLFxuICAgICAgICAvKipcbiAgICAgICAgICogVGhlIHVzZXIgaWQuIERlZmF1bHRzIHRvIHNlc3Npb24ncyBgdXNlcklkYC5cbiAgICAgICAgICogQHR5cGUge1N0cmluZ31cbiAgICAgICAgICovXG4gICAgICAgIHVzZXJJZDogdW5kZWZpbmVkLFxuICAgICAgICAvKipcbiAgICAgICAgICogVGhlIHNjb3BlIGZvciB0aGUgYXNzZXQuIFZhbGlkIHZhbHVlcyBhcmU6IGB1c2VyYCwgYGdyb3VwYCwgYW5kIGBwcm9qZWN0YC4gU2VlIGFib3ZlIGZvciB0aGUgcmVxdWlyZWQgcGVybWlzc2lvbnMgdG8gd3JpdGUgdG8gZWFjaCBzY29wZS4gRGVmYXVsdHMgdG8gYHVzZXJgLCBtZWFuaW5nIHRoZSBjdXJyZW50IGVuZCB1c2VyIG9yIGEgZmFjaWxpdGF0b3IgaW4gdGhlIGVuZCB1c2VyJ3MgZ3JvdXAgY2FuIGVkaXQgdGhlIGFzc2V0LlxuICAgICAgICAgKiBAdHlwZSB7U3RyaW5nfVxuICAgICAgICAgKi9cbiAgICAgICAgc2NvcGU6ICd1c2VyJyxcbiAgICAgICAgLyoqXG4gICAgICAgICAqIERldGVybWluZXMgaWYgYSByZXF1ZXN0IHRvIGxpc3QgdGhlIGFzc2V0cyBpbiBhIHNjb3BlIGluY2x1ZGVzIHRoZSBjb21wbGV0ZSBVUkwgZm9yIGVhY2ggYXNzZXQgKGB0cnVlYCksIG9yIG9ubHkgdGhlIGZpbGUgbmFtZXMgb2YgdGhlIGFzc2V0cyAoYGZhbHNlYCkuIERlZmF1bHRzIHRvIGB0cnVlYC5cbiAgICAgICAgICogQHR5cGUge2Jvb2xlYW59XG4gICAgICAgICAqL1xuICAgICAgICBmdWxsVXJsOiB0cnVlLFxuICAgICAgICAvKipcbiAgICAgICAgICogVGhlIHRyYW5zcG9ydCBvYmplY3QgY29udGFpbnMgdGhlIG9wdGlvbnMgcGFzc2VkIHRvIHRoZSBYSFIgcmVxdWVzdC5cbiAgICAgICAgICogQHR5cGUge29iamVjdH1cbiAgICAgICAgICovXG4gICAgICAgIHRyYW5zcG9ydDoge1xuICAgICAgICAgICAgcHJvY2Vzc0RhdGE6IGZhbHNlXG4gICAgICAgIH1cbiAgICB9O1xuICAgIHRoaXMuc2Vzc2lvbk1hbmFnZXIgPSBuZXcgU2Vzc2lvbk1hbmFnZXIoKTtcbiAgICB2YXIgc2VydmljZU9wdGlvbnMgPSB0aGlzLnNlc3Npb25NYW5hZ2VyLmdldE1lcmdlZE9wdGlvbnMoZGVmYXVsdHMsIGNvbmZpZyk7XG4gICAgdmFyIHVybENvbmZpZyA9IG5ldyBDb25maWdTZXJ2aWNlKHNlcnZpY2VPcHRpb25zKS5nZXQoJ3NlcnZlcicpO1xuXG4gICAgaWYgKCFzZXJ2aWNlT3B0aW9ucy5hY2NvdW50KSB7XG4gICAgICAgIHNlcnZpY2VPcHRpb25zLmFjY291bnQgPSB1cmxDb25maWcuYWNjb3VudFBhdGg7XG4gICAgfVxuXG4gICAgaWYgKCFzZXJ2aWNlT3B0aW9ucy5wcm9qZWN0KSB7XG4gICAgICAgIHNlcnZpY2VPcHRpb25zLnByb2plY3QgPSB1cmxDb25maWcucHJvamVjdFBhdGg7XG4gICAgfVxuXG4gICAgdmFyIHRyYW5zcG9ydE9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSwgc2VydmljZU9wdGlvbnMudHJhbnNwb3J0LCB7XG4gICAgICAgIHVybDogdXJsQ29uZmlnLmdldEFQSVBhdGgoYXBpRW5kcG9pbnQpXG4gICAgfSk7XG5cbiAgICBpZiAoc2VydmljZU9wdGlvbnMudG9rZW4pIHtcbiAgICAgICAgdHJhbnNwb3J0T3B0aW9ucy5oZWFkZXJzID0ge1xuICAgICAgICAgICAgQXV0aG9yaXphdGlvbjogJ0JlYXJlciAnICsgc2VydmljZU9wdGlvbnMudG9rZW5cbiAgICAgICAgfTtcbiAgICB9XG5cbiAgICB2YXIgaHR0cCA9IG5ldyBUcmFuc3BvcnRGYWN0b3J5KHRyYW5zcG9ydE9wdGlvbnMpO1xuXG4gICAgdmFyIGFzc2V0QXBpUGFyYW1zID0gWydlbmNvZGluZycsICdkYXRhJywgJ2NvbnRlbnRUeXBlJ107XG4gICAgdmFyIHNjb3BlQ29uZmlnID0ge1xuICAgICAgICB1c2VyOiBbJ3Njb3BlJywgJ2FjY291bnQnLCAncHJvamVjdCcsICdncm91cCcsICd1c2VySWQnXSxcbiAgICAgICAgZ3JvdXA6IFsnc2NvcGUnLCAnYWNjb3VudCcsICdwcm9qZWN0JywgJ2dyb3VwJ10sXG4gICAgICAgIHByb2plY3Q6IFsnc2NvcGUnLCAnYWNjb3VudCcsICdwcm9qZWN0J10sXG4gICAgfTtcblxuICAgIHZhciB2YWxpZGF0ZUZpbGVuYW1lID0gZnVuY3Rpb24gKGZpbGVuYW1lKSB7XG4gICAgICAgIGlmICghZmlsZW5hbWUpIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcignZmlsZW5hbWUgaXMgbmVlZGVkLicpO1xuICAgICAgICB9XG4gICAgfTtcblxuICAgIHZhciB2YWxpZGF0ZVVybFBhcmFtcyA9IGZ1bmN0aW9uIChvcHRpb25zKSB7XG4gICAgICAgIHZhciBwYXJ0S2V5cyA9IHNjb3BlQ29uZmlnW29wdGlvbnMuc2NvcGVdO1xuICAgICAgICBpZiAoIXBhcnRLZXlzKSB7XG4gICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ3Njb3BlIHBhcmFtZXRlciBpcyBuZWVkZWQuJyk7XG4gICAgICAgIH1cblxuICAgICAgICAkLmVhY2gocGFydEtleXMsIGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIGlmICghb3B0aW9uc1t0aGlzXSkge1xuICAgICAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcih0aGlzICsgJyBwYXJhbWV0ZXIgaXMgbmVlZGVkLicpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9KTtcbiAgICB9O1xuXG4gICAgdmFyIGJ1aWxkVXJsID0gZnVuY3Rpb24gKGZpbGVuYW1lLCBvcHRpb25zKSB7XG4gICAgICAgIHZhbGlkYXRlVXJsUGFyYW1zKG9wdGlvbnMpO1xuICAgICAgICB2YXIgcGFydEtleXMgPSBzY29wZUNvbmZpZ1tvcHRpb25zLnNjb3BlXTtcbiAgICAgICAgdmFyIHBhcnRzID0gJC5tYXAocGFydEtleXMsIGZ1bmN0aW9uIChrZXkpIHtcbiAgICAgICAgICAgIHJldHVybiBvcHRpb25zW2tleV07XG4gICAgICAgIH0pO1xuICAgICAgICBpZiAoZmlsZW5hbWUpIHtcbiAgICAgICAgICAgIC8vIFRoaXMgcHJldmVudHMgYWRkaW5nIGEgdHJhaWxpbmcgLyBpbiB0aGUgVVJMIGFzIHRoZSBBc3NldCBBUElcbiAgICAgICAgICAgIC8vIGRvZXMgbm90IHdvcmsgY29ycmVjdGx5IHdpdGggaXRcbiAgICAgICAgICAgIGZpbGVuYW1lID0gJy8nICsgZmlsZW5hbWU7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIHVybENvbmZpZy5nZXRBUElQYXRoKGFwaUVuZHBvaW50KSArIHBhcnRzLmpvaW4oJy8nKSArIGZpbGVuYW1lO1xuICAgIH07XG5cbiAgICAvLyBQcml2YXRlIGZ1bmN0aW9uLCBhbGwgcmVxdWVzdHMgZm9sbG93IGEgbW9yZSBvciBsZXNzIHNhbWUgYXBwcm9hY2ggdG9cbiAgICAvLyB1c2UgdGhlIEFzc2V0IEFQSSBhbmQgdGhlIGRpZmZlcmVuY2UgaXMgdGhlIEhUVFAgdmVyYlxuICAgIC8vXG4gICAgLy8gQHBhcmFtIHtzdHJpbmd9IG1ldGhvZGAgKFJlcXVpcmVkKSBIVFRQIHZlcmJcbiAgICAvLyBAcGFyYW0ge3N0cmluZ30gZmlsZW5hbWVgIChSZXF1aXJlZCkgTmFtZSBvZiB0aGUgZmlsZSB0byBkZWxldGUvcmVwbGFjZS9jcmVhdGVcbiAgICAvLyBAcGFyYW0ge29iamVjdH0gcGFyYW1zYCAoT3B0aW9uYWwpIEJvZHkgcGFyYW1ldGVycyB0byBzZW5kIHRvIHRoZSBBc3NldCBBUElcbiAgICAvLyBAcGFyYW0ge29iamVjdH0gb3B0aW9uc2AgKE9wdGlvbmFsKSBPcHRpb25zIG9iamVjdCB0byBvdmVycmlkZSBnbG9iYWwgb3B0aW9ucy5cbiAgICB2YXIgdXBsb2FkID0gZnVuY3Rpb24gKG1ldGhvZCwgZmlsZW5hbWUsIHBhcmFtcywgb3B0aW9ucykge1xuICAgICAgICB2YWxpZGF0ZUZpbGVuYW1lKGZpbGVuYW1lKTtcbiAgICAgICAgLy8gbWFrZSBzdXJlIHRoZSBwYXJhbWV0ZXIgaXMgY2xlYW5cbiAgICAgICAgbWV0aG9kID0gbWV0aG9kLnRvTG93ZXJDYXNlKCk7XG4gICAgICAgIHZhciBjb250ZW50VHlwZSA9IHBhcmFtcyBpbnN0YW5jZW9mIEZvcm1EYXRhID09PSB0cnVlID8gZmFsc2UgOiAnYXBwbGljYXRpb24vanNvbic7XG4gICAgICAgIGlmIChjb250ZW50VHlwZSA9PT0gJ2FwcGxpY2F0aW9uL2pzb24nKSB7XG4gICAgICAgICAgICAvLyB3aGl0ZWxpc3QgdGhlIGZpZWxkcyB0aGF0IHdlIGFjdHVhbGx5IGNhbiBzZW5kIHRvIHRoZSBhcGlcbiAgICAgICAgICAgIHBhcmFtcyA9IF9waWNrKHBhcmFtcywgYXNzZXRBcGlQYXJhbXMpO1xuICAgICAgICB9IGVsc2UgeyAvLyBlbHNlIHdlJ3JlIHNlbmRpbmcgZm9ybSBkYXRhIHdoaWNoIGdvZXMgZGlyZWN0bHkgaW4gcmVxdWVzdCBib2R5XG4gICAgICAgICAgICAvLyBGb3IgbXVsdGlwYXJ0L2Zvcm0tZGF0YSB1cGxvYWRzIHRoZSBmaWxlbmFtZSBpcyBub3Qgc2V0IGluIHRoZSBVUkwsXG4gICAgICAgICAgICAvLyBpdCdzIGdldHRpbmcgcGlja2VkIGJ5IHRoZSBGb3JtRGF0YSBmaWVsZCBmaWxlbmFtZS5cbiAgICAgICAgICAgIGZpbGVuYW1lID0gbWV0aG9kID09PSAncG9zdCcgfHwgbWV0aG9kID09PSAncHV0JyA/ICcnIDogZmlsZW5hbWU7XG4gICAgICAgIH1cbiAgICAgICAgdmFyIHVybE9wdGlvbnMgPSAkLmV4dGVuZCh7fSwgc2VydmljZU9wdGlvbnMsIG9wdGlvbnMpO1xuICAgICAgICB2YXIgdXJsID0gYnVpbGRVcmwoZmlsZW5hbWUsIHVybE9wdGlvbnMpO1xuICAgICAgICB2YXIgY3JlYXRlT3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LCB1cmxPcHRpb25zLCB7IHVybDogdXJsLCBjb250ZW50VHlwZTogY29udGVudFR5cGUgfSk7XG5cbiAgICAgICAgcmV0dXJuIGh0dHBbbWV0aG9kXShwYXJhbXMsIGNyZWF0ZU9wdGlvbnMpO1xuICAgIH07XG5cbiAgICB2YXIgcHVibGljQVBJID0ge1xuICAgICAgICAvKipcbiAgICAgICAgKiBDcmVhdGVzIGEgZmlsZSBpbiB0aGUgQXNzZXQgQVBJLiBUaGUgc2VydmVyIHJldHVybnMgYW4gZXJyb3IgKHN0YXR1cyBjb2RlIGA0MDlgLCBjb25mbGljdCkgaWYgdGhlIGZpbGUgYWxyZWFkeSBleGlzdHMsIHNvXG4gICAgICAgICogY2hlY2sgZmlyc3Qgd2l0aCBhIGBsaXN0KClgIG9yIGEgYGdldCgpYC5cbiAgICAgICAgKlxuICAgICAgICAqICAqKkV4YW1wbGUqKlxuICAgICAgICAqXG4gICAgICAgICogICAgICAgdmFyIGFhID0gbmV3IEYuc2VydmljZS5Bc3NldCh7XG4gICAgICAgICogICAgICAgICAgYWNjb3VudDogJ2FjbWUtc2ltdWxhdGlvbnMnLFxuICAgICAgICAqICAgICAgICAgIHByb2plY3Q6ICdzdXBwbHktY2hhaW4tZ2FtZScsXG4gICAgICAgICogICAgICAgICAgZ3JvdXA6ICd0ZWFtMScsXG4gICAgICAgICogICAgICAgICAgdXNlcklkOiAnJ1xuICAgICAgICAqICAgICAgIH0pO1xuICAgICAgICAqXG4gICAgICAgICogICAgICAgLy8gY3JlYXRlIGEgbmV3IGFzc2V0IHVzaW5nIGVuY29kZWQgdGV4dFxuICAgICAgICAqICAgICAgIGFhLmNyZWF0ZSgndGVzdC50eHQnLCB7XG4gICAgICAgICogICAgICAgICAgIGVuY29kaW5nOiAnQkFTRV82NCcsXG4gICAgICAgICogICAgICAgICAgIGRhdGE6ICdWR2hwY3lCcGN5QmhJSFJsYzNRZ1ptbHNaUzQ9JyxcbiAgICAgICAgKiAgICAgICAgICAgY29udGVudFR5cGU6ICd0ZXh0L3BsYWluJ1xuICAgICAgICAqICAgICAgIH0sIHsgc2NvcGU6ICd1c2VyJyB9KTtcbiAgICAgICAgKlxuICAgICAgICAqICAgICAgIC8vIGFsdGVybmF0aXZlbHksIGNyZWF0ZSBhIG5ldyBhc3NldCB1c2luZyBhIGZpbGUgdXBsb2FkZWQgdGhyb3VnaCBhIGZvcm1cbiAgICAgICAgKiAgICAgICAvLyB0aGlzIHNhbXBsZSBjb2RlIGdvZXMgd2l0aCBhbiBodG1sIGZvcm0gdGhhdCBsb29rcyBsaWtlIHRoaXM6XG4gICAgICAgICogICAgICAgLy9cbiAgICAgICAgKiAgICAgICAvLyA8Zm9ybSBpZD1cInVwbG9hZC1maWxlXCI+XG4gICAgICAgICogICAgICAgLy8gICA8aW5wdXQgaWQ9XCJmaWxlXCIgdHlwZT1cImZpbGVcIj5cbiAgICAgICAgKiAgICAgICAvLyAgIDxpbnB1dCBpZD1cImZpbGVuYW1lXCIgdHlwZT1cInRleHRcIiB2YWx1ZT1cIm15RmlsZS50eHRcIj5cbiAgICAgICAgKiAgICAgICAvLyAgIDxidXR0b24gdHlwZT1cInN1Ym1pdFwiPlVwbG9hZCBteUZpbGU8L2J1dHRvbj5cbiAgICAgICAgKiAgICAgICAvLyA8L2Zvcm0+XG4gICAgICAgICogICAgICAgLy9cbiAgICAgICAgKiAgICAgICAkKCcjdXBsb2FkLWZpbGUnKS5vbignc3VibWl0JywgZnVuY3Rpb24gKGUpIHtcbiAgICAgICAgKiAgICAgICAgICBlLnByZXZlbnREZWZhdWx0KCk7XG4gICAgICAgICogICAgICAgICAgdmFyIGZpbGVuYW1lID0gJCgnI2ZpbGVuYW1lJykudmFsKCk7XG4gICAgICAgICogICAgICAgICAgdmFyIGRhdGEgPSBuZXcgRm9ybURhdGEoKTtcbiAgICAgICAgKiAgICAgICAgICB2YXIgaW5wdXRDb250cm9sID0gJCgnI2ZpbGUnKVswXTtcbiAgICAgICAgKiAgICAgICAgICBkYXRhLmFwcGVuZCgnZmlsZScsIGlucHV0Q29udHJvbC5maWxlc1swXSwgZmlsZW5hbWUpO1xuICAgICAgICAqXG4gICAgICAgICogICAgICAgICAgYWEuY3JlYXRlKGZpbGVuYW1lLCBkYXRhLCB7IHNjb3BlOiAndXNlcicgfSk7XG4gICAgICAgICogICAgICAgfSk7XG4gICAgICAgICpcbiAgICAgICAgKlxuICAgICAgICAqICAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAqIEBwYXJhbSB7c3RyaW5nfSBmaWxlbmFtZSAoUmVxdWlyZWQpIE5hbWUgb2YgdGhlIGZpbGUgdG8gY3JlYXRlLlxuICAgICAgICAqIEBwYXJhbSB7b2JqZWN0fSBwYXJhbXMgKE9wdGlvbmFsKSBCb2R5IHBhcmFtZXRlcnMgdG8gc2VuZCB0byB0aGUgQXNzZXQgQVBJLiBSZXF1aXJlZCBpZiB0aGUgYG9wdGlvbnMudHJhbnNwb3J0LmNvbnRlbnRUeXBlYCBpcyBgYXBwbGljYXRpb24vanNvbmAsIG90aGVyd2lzZSBpZ25vcmVkLlxuICAgICAgICAqIEBwYXJhbSB7c3RyaW5nfSBwYXJhbXMuZW5jb2RpbmcgRWl0aGVyIGBIRVhgIG9yIGBCQVNFXzY0YC4gUmVxdWlyZWQgaWYgYG9wdGlvbnMudHJhbnNwb3J0LmNvbnRlbnRUeXBlYCBpcyBgYXBwbGljYXRpb24vanNvbmAuXG4gICAgICAgICogQHBhcmFtIHtzdHJpbmd9IHBhcmFtcy5kYXRhIFRoZSBlbmNvZGVkIGRhdGEgZm9yIHRoZSBmaWxlLiBSZXF1aXJlZCBpZiBgb3B0aW9ucy50cmFuc3BvcnQuY29udGVudFR5cGVgIGlzIGBhcHBsaWNhdGlvbi9qc29uYC5cbiAgICAgICAgKiBAcGFyYW0ge3N0cmluZ30gcGFyYW1zLmNvbnRlbnRUeXBlIFRoZSBtaW1lIHR5cGUgb2YgdGhlIGZpbGUuIE9wdGlvbmFsLlxuICAgICAgICAqIEBwYXJhbSB7b2JqZWN0fSBvcHRpb25zIChPcHRpb25hbCkgT3B0aW9ucyBvYmplY3QgdG8gb3ZlcnJpZGUgZ2xvYmFsIG9wdGlvbnMuXG4gICAgICAgICogQHJldHVybiB7UHJvbWlzZX1cbiAgICAgICAgKi9cbiAgICAgICAgY3JlYXRlOiBmdW5jdGlvbiAoZmlsZW5hbWUsIHBhcmFtcywgb3B0aW9ucykge1xuICAgICAgICAgICAgcmV0dXJuIHVwbG9hZCgncG9zdCcsIGZpbGVuYW1lLCBwYXJhbXMsIG9wdGlvbnMpO1xuICAgICAgICB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAqIEdldHMgYSBmaWxlIGZyb20gdGhlIEFzc2V0IEFQSSwgZmV0Y2hpbmcgdGhlIGFzc2V0IGNvbnRlbnQuIChUbyBnZXQgYSBsaXN0XG4gICAgICAgICogb2YgdGhlIGFzc2V0cyBpbiBhIHNjb3BlLCB1c2UgYGxpc3QoKWAuKVxuICAgICAgICAqXG4gICAgICAgICogICoqUGFyYW1ldGVycyoqXG4gICAgICAgICogQHBhcmFtIHtzdHJpbmd9IGZpbGVuYW1lIChSZXF1aXJlZCkgTmFtZSBvZiB0aGUgZmlsZSB0byByZXRyaWV2ZS5cbiAgICAgICAgKiBAcGFyYW0ge29iamVjdH0gb3B0aW9ucyAoT3B0aW9uYWwpIE9wdGlvbnMgb2JqZWN0IHRvIG92ZXJyaWRlIGdsb2JhbCBvcHRpb25zLlxuICAgICAgICAqIEByZXR1cm4ge1Byb21pc2V9XG4gICAgICAgICovXG4gICAgICAgIGdldDogZnVuY3Rpb24gKGZpbGVuYW1lLCBvcHRpb25zKSB7XG4gICAgICAgICAgICB2YXIgZ2V0U2VydmljZU9wdGlvbnMgPSBfcGljayhzZXJ2aWNlT3B0aW9ucywgWydzY29wZScsICdhY2NvdW50JywgJ3Byb2plY3QnLCAnZ3JvdXAnLCAndXNlcklkJ10pO1xuICAgICAgICAgICAgdmFyIHVybE9wdGlvbnMgPSAkLmV4dGVuZCh7fSwgZ2V0U2VydmljZU9wdGlvbnMsIG9wdGlvbnMpO1xuICAgICAgICAgICAgdmFyIHVybCA9IGJ1aWxkVXJsKGZpbGVuYW1lLCB1cmxPcHRpb25zKTtcbiAgICAgICAgICAgIHZhciBnZXRPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sIHVybE9wdGlvbnMsIHsgdXJsOiB1cmwgfSk7XG5cbiAgICAgICAgICAgIHJldHVybiBodHRwLmdldCh7fSwgZ2V0T3B0aW9ucyk7XG4gICAgICAgIH0sXG5cbiAgICAgICAgLyoqXG4gICAgICAgICogR2V0cyB0aGUgbGlzdCBvZiB0aGUgYXNzZXRzIGluIGEgc2NvcGUuXG4gICAgICAgICpcbiAgICAgICAgKiAqKkV4YW1wbGUqKlxuICAgICAgICAqXG4gICAgICAgICogICAgICAgYWEubGlzdCh7IGZ1bGxVcmw6IHRydWUgfSkudGhlbihmdW5jdGlvbihmaWxlTGlzdCl7XG4gICAgICAgICogICAgICAgICAgIGNvbnNvbGUubG9nKCdhcnJheSBvZiBmaWxlcyA9ICcsIGZpbGVMaXN0KTtcbiAgICAgICAgKiAgICAgICB9KTtcbiAgICAgICAgKlxuICAgICAgICAqICAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAqIEBwYXJhbSB7b2JqZWN0fSBvcHRpb25zIChPcHRpb25hbCkgT3B0aW9ucyBvYmplY3QgdG8gb3ZlcnJpZGUgZ2xvYmFsIG9wdGlvbnMuXG4gICAgICAgICogQHBhcmFtIHtzdHJpbmd9IG9wdGlvbnMuc2NvcGUgKE9wdGlvbmFsKSBUaGUgc2NvcGUgKGB1c2VyYCwgYGdyb3VwYCwgYHByb2plY3RgKS5cbiAgICAgICAgKiBAcGFyYW0ge2Jvb2xlYW59IG9wdGlvbnMuZnVsbFVybCAoT3B0aW9uYWwpIERldGVybWluZXMgaWYgdGhlIGxpc3Qgb2YgYXNzZXRzIGluIGEgc2NvcGUgaW5jbHVkZXMgdGhlIGNvbXBsZXRlIFVSTCBmb3IgZWFjaCBhc3NldCAoYHRydWVgKSwgb3Igb25seSB0aGUgZmlsZSBuYW1lcyBvZiB0aGUgYXNzZXRzIChgZmFsc2VgKS5cbiAgICAgICAgKiBAcmV0dXJuIHtQcm9taXNlfVxuICAgICAgICAqL1xuICAgICAgICBsaXN0OiBmdW5jdGlvbiAob3B0aW9ucykge1xuICAgICAgICAgICAgdmFyIGR0ZCA9ICQuRGVmZXJyZWQoKTtcbiAgICAgICAgICAgIHZhciBtZSA9IHRoaXM7XG4gICAgICAgICAgICB2YXIgdXJsT3B0aW9ucyA9ICQuZXh0ZW5kKHt9LCBzZXJ2aWNlT3B0aW9ucywgb3B0aW9ucyk7XG4gICAgICAgICAgICB2YXIgdXJsID0gYnVpbGRVcmwoJycsIHVybE9wdGlvbnMpO1xuICAgICAgICAgICAgdmFyIGdldE9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSwgdXJsT3B0aW9ucywgeyB1cmw6IHVybCB9KTtcbiAgICAgICAgICAgIHZhciBmdWxsVXJsID0gZ2V0T3B0aW9ucy5mdWxsVXJsO1xuXG4gICAgICAgICAgICBpZiAoIWZ1bGxVcmwpIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gaHR0cC5nZXQoe30sIGdldE9wdGlvbnMpO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICBodHRwLmdldCh7fSwgZ2V0T3B0aW9ucylcbiAgICAgICAgICAgICAgICAudGhlbihmdW5jdGlvbiAoZmlsZXMpIHtcbiAgICAgICAgICAgICAgICAgICAgdmFyIGZ1bGxQYXRoRmlsZXMgPSAkLm1hcChmaWxlcywgZnVuY3Rpb24gKGZpbGUpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybiBidWlsZFVybChmaWxlLCB1cmxPcHRpb25zKTtcbiAgICAgICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgICAgICAgIGR0ZC5yZXNvbHZlV2l0aChtZSwgW2Z1bGxQYXRoRmlsZXNdKTtcbiAgICAgICAgICAgICAgICB9KVxuICAgICAgICAgICAgICAgIC5mYWlsKGR0ZC5yZWplY3QpO1xuXG4gICAgICAgICAgICByZXR1cm4gZHRkLnByb21pc2UoKTtcbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgKiBSZXBsYWNlcyBhbiBleGlzdGluZyBmaWxlIGluIHRoZSBBc3NldCBBUEkuXG4gICAgICAgICpcbiAgICAgICAgKiAqKkV4YW1wbGUqKlxuICAgICAgICAqXG4gICAgICAgICogICAgICAgLy8gcmVwbGFjZSBhbiBhc3NldCB1c2luZyBlbmNvZGVkIHRleHRcbiAgICAgICAgKiAgICAgICBhYS5yZXBsYWNlKCd0ZXN0LnR4dCcsIHtcbiAgICAgICAgKiAgICAgICAgICAgZW5jb2Rpbmc6ICdCQVNFXzY0JyxcbiAgICAgICAgKiAgICAgICAgICAgZGF0YTogJ1ZHaHBjeUJwY3lCaElITmxZMjl1WkNCMFpYTjBJR1pwYkdVdScsXG4gICAgICAgICogICAgICAgICAgIGNvbnRlbnRUeXBlOiAndGV4dC9wbGFpbidcbiAgICAgICAgKiAgICAgICB9LCB7IHNjb3BlOiAndXNlcicgfSk7XG4gICAgICAgICpcbiAgICAgICAgKiAgICAgICAvLyBhbHRlcm5hdGl2ZWx5LCByZXBsYWNlIGFuIGFzc2V0IHVzaW5nIGEgZmlsZSB1cGxvYWRlZCB0aHJvdWdoIGEgZm9ybVxuICAgICAgICAqICAgICAgIC8vIHRoaXMgc2FtcGxlIGNvZGUgZ29lcyB3aXRoIGFuIGh0bWwgZm9ybSB0aGF0IGxvb2tzIGxpa2UgdGhpczpcbiAgICAgICAgKiAgICAgICAvL1xuICAgICAgICAqICAgICAgIC8vIDxmb3JtIGlkPVwicmVwbGFjZS1maWxlXCI+XG4gICAgICAgICogICAgICAgLy8gICA8aW5wdXQgaWQ9XCJmaWxlXCIgdHlwZT1cImZpbGVcIj5cbiAgICAgICAgKiAgICAgICAvLyAgIDxpbnB1dCBpZD1cInJlcGxhY2UtZmlsZW5hbWVcIiB0eXBlPVwidGV4dFwiIHZhbHVlPVwibXlGaWxlLnR4dFwiPlxuICAgICAgICAqICAgICAgIC8vICAgPGJ1dHRvbiB0eXBlPVwic3VibWl0XCI+UmVwbGFjZSBteUZpbGU8L2J1dHRvbj5cbiAgICAgICAgKiAgICAgICAvLyA8L2Zvcm0+XG4gICAgICAgICogICAgICAgLy9cbiAgICAgICAgKiAgICAgICAkKCcjcmVwbGFjZS1maWxlJykub24oJ3N1Ym1pdCcsIGZ1bmN0aW9uIChlKSB7XG4gICAgICAgICogICAgICAgICAgZS5wcmV2ZW50RGVmYXVsdCgpO1xuICAgICAgICAqICAgICAgICAgIHZhciBmaWxlbmFtZSA9ICQoJyNyZXBsYWNlLWZpbGVuYW1lJykudmFsKCk7XG4gICAgICAgICogICAgICAgICAgdmFyIGRhdGEgPSBuZXcgRm9ybURhdGEoKTtcbiAgICAgICAgKiAgICAgICAgICB2YXIgaW5wdXRDb250cm9sID0gJCgnI2ZpbGUnKVswXTtcbiAgICAgICAgKiAgICAgICAgICBkYXRhLmFwcGVuZCgnZmlsZScsIGlucHV0Q29udHJvbC5maWxlc1swXSwgZmlsZW5hbWUpO1xuICAgICAgICAqXG4gICAgICAgICogICAgICAgICAgYWEucmVwbGFjZShmaWxlbmFtZSwgZGF0YSwgeyBzY29wZTogJ3VzZXInIH0pO1xuICAgICAgICAqICAgICAgIH0pO1xuICAgICAgICAqXG4gICAgICAgICogICoqUGFyYW1ldGVycyoqXG4gICAgICAgICogQHBhcmFtIHtzdHJpbmd9IGZpbGVuYW1lIChSZXF1aXJlZCkgTmFtZSBvZiB0aGUgZmlsZSBiZWluZyByZXBsYWNlZC5cbiAgICAgICAgKiBAcGFyYW0ge29iamVjdH0gcGFyYW1zIChPcHRpb25hbCkgQm9keSBwYXJhbWV0ZXJzIHRvIHNlbmQgdG8gdGhlIEFzc2V0IEFQSS4gUmVxdWlyZWQgaWYgdGhlIGBvcHRpb25zLnRyYW5zcG9ydC5jb250ZW50VHlwZWAgaXMgYGFwcGxpY2F0aW9uL2pzb25gLCBvdGhlcndpc2UgaWdub3JlZC5cbiAgICAgICAgKiBAcGFyYW0ge3N0cmluZ30gcGFyYW1zLmVuY29kaW5nIEVpdGhlciBgSEVYYCBvciBgQkFTRV82NGAuIFJlcXVpcmVkIGlmIGBvcHRpb25zLnRyYW5zcG9ydC5jb250ZW50VHlwZWAgaXMgYGFwcGxpY2F0aW9uL2pzb25gLlxuICAgICAgICAqIEBwYXJhbSB7c3RyaW5nfSBwYXJhbXMuZGF0YSBUaGUgZW5jb2RlZCBkYXRhIGZvciB0aGUgZmlsZS4gUmVxdWlyZWQgaWYgYG9wdGlvbnMudHJhbnNwb3J0LmNvbnRlbnRUeXBlYCBpcyBgYXBwbGljYXRpb24vanNvbmAuXG4gICAgICAgICogQHBhcmFtIHtzdHJpbmd9IHBhcmFtcy5jb250ZW50VHlwZSBUaGUgbWltZSB0eXBlIG9mIHRoZSBmaWxlLiBPcHRpb25hbC5cbiAgICAgICAgKiBAcGFyYW0ge29iamVjdH0gb3B0aW9ucyAoT3B0aW9uYWwpIE9wdGlvbnMgb2JqZWN0IHRvIG92ZXJyaWRlIGdsb2JhbCBvcHRpb25zLlxuICAgICAgICAqIEByZXR1cm4ge1Byb21pc2V9XG4gICAgICAgICovXG4gICAgICAgIHJlcGxhY2U6IGZ1bmN0aW9uIChmaWxlbmFtZSwgcGFyYW1zLCBvcHRpb25zKSB7XG4gICAgICAgICAgICByZXR1cm4gdXBsb2FkKCdwdXQnLCBmaWxlbmFtZSwgcGFyYW1zLCBvcHRpb25zKTtcbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgKiBEZWxldGVzIGEgZmlsZSBmcm9tIHRoZSBBc3NldCBBUEkuXG4gICAgICAgICpcbiAgICAgICAgKiAqKkV4YW1wbGUqKlxuICAgICAgICAqXG4gICAgICAgICogICAgICAgYWEuZGVsZXRlKHNhbXBsZUZpbGVOYW1lKTtcbiAgICAgICAgKlxuICAgICAgICAqICAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAqIEBwYXJhbSB7c3RyaW5nfSBmaWxlbmFtZSAoUmVxdWlyZWQpIE5hbWUgb2YgdGhlIGZpbGUgdG8gZGVsZXRlLlxuICAgICAgICAqIEBwYXJhbSB7b2JqZWN0fSBvcHRpb25zIChPcHRpb25hbCkgT3B0aW9ucyBvYmplY3QgdG8gb3ZlcnJpZGUgZ2xvYmFsIG9wdGlvbnMuXG4gICAgICAgICogQHJldHVybiB7UHJvbWlzZX1cbiAgICAgICAgKi9cbiAgICAgICAgZGVsZXRlOiBmdW5jdGlvbiAoZmlsZW5hbWUsIG9wdGlvbnMpIHtcbiAgICAgICAgICAgIHJldHVybiB1cGxvYWQoJ2RlbGV0ZScsIGZpbGVuYW1lLCB7fSwgb3B0aW9ucyk7XG4gICAgICAgIH0sXG5cbiAgICAgICAgYXNzZXRVcmw6IGZ1bmN0aW9uIChmaWxlbmFtZSwgb3B0aW9ucykge1xuICAgICAgICAgICAgdmFyIHVybE9wdGlvbnMgPSAkLmV4dGVuZCh7fSwgc2VydmljZU9wdGlvbnMsIG9wdGlvbnMpO1xuICAgICAgICAgICAgcmV0dXJuIGJ1aWxkVXJsKGZpbGVuYW1lLCB1cmxPcHRpb25zKTtcbiAgICAgICAgfVxuICAgIH07XG4gICAgJC5leHRlbmQodGhpcywgcHVibGljQVBJKTtcbn07XG4iLCIvKipcbiAqXG4gKiAjIyBBdXRoZW50aWNhdGlvbiBBUEkgU2VydmljZVxuICpcbiAqIFRoZSBBdXRoZW50aWNhdGlvbiBBUEkgU2VydmljZSBwcm92aWRlcyBhIG1ldGhvZCBmb3IgbG9nZ2luZyBpbiwgd2hpY2ggY3JlYXRlcyBhbmQgcmV0dXJucyBhIHVzZXIgYWNjZXNzIHRva2VuLlxuICpcbiAqIFVzZXIgYWNjZXNzIHRva2VucyBhcmUgcmVxdWlyZWQgZm9yIGVhY2ggY2FsbCB0byBFcGljZW50ZXIuIChTZWUgW1Byb2plY3QgQWNjZXNzXSguLi8uLi8uLi9wcm9qZWN0X2FjY2Vzcy8pIGZvciBtb3JlIGluZm9ybWF0aW9uLilcbiAqXG4gKiBJZiB5b3UgbmVlZCBhZGRpdGlvbmFsIGZ1bmN0aW9uYWxpdHkgLS0gc3VjaCBhcyB0cmFja2luZyBzZXNzaW9uIGluZm9ybWF0aW9uLCBlYXNpbHkgcmV0cmlldmluZyB0aGUgdXNlciB0b2tlbiwgb3IgZ2V0dGluZyB0aGUgZ3JvdXBzIHRvIHdoaWNoIGFuIGVuZCB1c2VyIGJlbG9uZ3MgLS0gY29uc2lkZXIgdXNpbmcgdGhlIFtBdXRob3JpemF0aW9uIE1hbmFnZXJdKC4uL2F1dGgtbWFuYWdlci8pIGluc3RlYWQuXG4gKlxuICogICAgICB2YXIgYXV0aCA9IG5ldyBGLnNlcnZpY2UuQXV0aCgpO1xuICogICAgICBhdXRoLmxvZ2luKHsgdXNlck5hbWU6ICdqc21pdGhAYWNtZXNpbXVsYXRpb25zLmNvbScsXG4gKiAgICAgICAgICAgICAgICAgIHBhc3N3b3JkOiAncGFzc3cwcmQnIH0pO1xuICovXG5cbid1c2Ugc3RyaWN0JztcblxudmFyIENvbmZpZ1NlcnZpY2UgPSByZXF1aXJlKCcuL2NvbmZpZ3VyYXRpb24tc2VydmljZScpO1xudmFyIFRyYW5zcG9ydEZhY3RvcnkgPSByZXF1aXJlKCcuLi90cmFuc3BvcnQvaHR0cC10cmFuc3BvcnQtZmFjdG9yeScpO1xuXG5tb2R1bGUuZXhwb3J0cyA9IGZ1bmN0aW9uIChjb25maWcpIHtcbiAgICB2YXIgZGVmYXVsdHMgPSB7XG4gICAgICAgIC8qKlxuICAgICAgICAgKiBFbWFpbCBvciB1c2VybmFtZSB0byB1c2UgZm9yIGxvZ2dpbmcgaW4uIERlZmF1bHRzIHRvIGVtcHR5IHN0cmluZy5cbiAgICAgICAgICogQHR5cGUge1N0cmluZ31cbiAgICAgICAgICovXG4gICAgICAgIHVzZXJOYW1lOiAnJyxcblxuICAgICAgICAvKipcbiAgICAgICAgICogUGFzc3dvcmQgZm9yIHNwZWNpZmllZCBgdXNlck5hbWVgLiBEZWZhdWx0cyB0byBlbXB0eSBzdHJpbmcuXG4gICAgICAgICAqIEB0eXBlIHtTdHJpbmd9XG4gICAgICAgICAqL1xuICAgICAgICBwYXNzd29yZDogJycsXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIFRoZSBhY2NvdW50IGlkIGZvciB0aGlzIGB1c2VyTmFtZWAuIEluIHRoZSBFcGljZW50ZXIgVUksIHRoaXMgaXMgdGhlICoqVGVhbSBJRCoqIChmb3IgdGVhbSBwcm9qZWN0cykgb3IgdGhlICoqVXNlciBJRCoqIChmb3IgcGVyc29uYWwgcHJvamVjdHMpLiBSZXF1aXJlZCBpZiB0aGUgYHVzZXJOYW1lYCBpcyBmb3IgYW4gW2VuZCB1c2VyXSguLi8uLi8uLi9nbG9zc2FyeS8jdXNlcnMpLiBEZWZhdWx0cyB0byBlbXB0eSBzdHJpbmcuXG4gICAgICAgICAqIEB0eXBlIHtTdHJpbmd9XG4gICAgICAgICAqL1xuICAgICAgICBhY2NvdW50OiAnJyxcblxuICAgICAgICAvKipcbiAgICAgICAgICogT3B0aW9ucyB0byBwYXNzIG9uIHRvIHRoZSB1bmRlcmx5aW5nIHRyYW5zcG9ydCBsYXllci4gQWxsIGpxdWVyeS5hamF4IG9wdGlvbnMgYXQgaHR0cDovL2FwaS5qcXVlcnkuY29tL2pRdWVyeS5hamF4LyBhcmUgYXZhaWxhYmxlLiBEZWZhdWx0cyB0byBlbXB0eSBvYmplY3QuXG4gICAgICAgICAqIEB0eXBlIHtPYmplY3R9XG4gICAgICAgICAqL1xuICAgICAgICB0cmFuc3BvcnQ6IHt9XG4gICAgfTtcbiAgICB2YXIgc2VydmljZU9wdGlvbnMgPSAkLmV4dGVuZCh7fSwgZGVmYXVsdHMsIGNvbmZpZyk7XG4gICAgdmFyIHVybENvbmZpZyA9IG5ldyBDb25maWdTZXJ2aWNlKHNlcnZpY2VPcHRpb25zKS5nZXQoJ3NlcnZlcicpO1xuXG4gICAgdmFyIHRyYW5zcG9ydE9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSwgc2VydmljZU9wdGlvbnMudHJhbnNwb3J0LCB7XG4gICAgICAgIHVybDogdXJsQ29uZmlnLmdldEFQSVBhdGgoJ2F1dGhlbnRpY2F0aW9uJylcbiAgICB9KTtcbiAgICB2YXIgaHR0cCA9IG5ldyBUcmFuc3BvcnRGYWN0b3J5KHRyYW5zcG9ydE9wdGlvbnMpO1xuXG4gICAgdmFyIHB1YmxpY0FQSSA9IHtcblxuICAgICAgICAvKipcbiAgICAgICAgICogTG9ncyB1c2VyIGluLCByZXR1cm5pbmcgdGhlIHVzZXIgYWNjZXNzIHRva2VuLlxuICAgICAgICAgKlxuICAgICAgICAgKiBJZiBubyBgdXNlck5hbWVgIG9yIGBwYXNzd29yZGAgd2VyZSBwcm92aWRlZCBpbiB0aGUgaW5pdGlhbCBjb25maWd1cmF0aW9uIG9wdGlvbnMsIHRoZXkgYXJlIHJlcXVpcmVkIGluIHRoZSBgb3B0aW9uc2AgaGVyZS4gSWYgbm8gYGFjY291bnRgIHdhcyBwcm92aWRlZCBpbiB0aGUgaW5pdGlhbCBjb25maWd1cmF0aW9uIG9wdGlvbnMgYW5kIHRoZSBgdXNlck5hbWVgIGlzIGZvciBhbiBbZW5kIHVzZXJdKC4uLy4uLy4uL2dsb3NzYXJ5LyN1c2VycyksIHRoZSBgYWNjb3VudGAgaXMgcmVxdWlyZWQgYXMgd2VsbC5cbiAgICAgICAgICpcbiAgICAgICAgICogKipFeGFtcGxlKipcbiAgICAgICAgICpcbiAgICAgICAgICogICAgICBhdXRoLmxvZ2luKHtcbiAgICAgICAgICogICAgICAgICAgdXNlck5hbWU6ICdqc21pdGgnLFxuICAgICAgICAgKiAgICAgICAgICBwYXNzd29yZDogJ3Bhc3N3MHJkJyxcbiAgICAgICAgICogICAgICAgICAgYWNjb3VudDogJ2FjbWUtc2ltdWxhdGlvbnMnIH0pXG4gICAgICAgICAqICAgICAgLnRoZW4oZnVuY3Rpb24gKHRva2VuKSB7XG4gICAgICAgICAqICAgICAgICAgIGNvbnNvbGUubG9nKFwidXNlciBhY2Nlc3MgdG9rZW4gaXM6IFwiLCB0b2tlbi5hY2Nlc3NfdG9rZW4pO1xuICAgICAgICAgKiAgICAgIH0pO1xuICAgICAgICAgKlxuICAgICAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAgKiBAcGFyYW0ge09iamVjdH0gb3B0aW9ucyAoT3B0aW9uYWwpIE92ZXJyaWRlcyBmb3IgY29uZmlndXJhdGlvbiBvcHRpb25zLlxuICAgICAgICAgKiBAcmV0dXJuIHtQcm9taXNlfVxuICAgICAgICAgKi9cbiAgICAgICAgbG9naW46IGZ1bmN0aW9uIChvcHRpb25zKSB7XG4gICAgICAgICAgICB2YXIgaHR0cE9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7IHN1Y2Nlc3M6ICQubm9vcCB9LCBzZXJ2aWNlT3B0aW9ucywgb3B0aW9ucyk7XG4gICAgICAgICAgICBpZiAoIWh0dHBPcHRpb25zLnVzZXJOYW1lIHx8ICFodHRwT3B0aW9ucy5wYXNzd29yZCkge1xuICAgICAgICAgICAgICAgIHZhciByZXNwID0geyBzdGF0dXM6IDQwMSwgc3RhdHVzTWVzc2FnZTogJ05vIHVzZXJuYW1lIG9yIHBhc3N3b3JkIHNwZWNpZmllZC4nIH07XG4gICAgICAgICAgICAgICAgaWYgKG9wdGlvbnMuZXJyb3IpIHtcbiAgICAgICAgICAgICAgICAgICAgb3B0aW9ucy5lcnJvci5jYWxsKHRoaXMsIHJlc3ApO1xuICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgIHJldHVybiAkLkRlZmVycmVkKCkucmVqZWN0KHJlc3ApLnByb21pc2UoKTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgdmFyIHBvc3RQYXJhbXMgPSB7XG4gICAgICAgICAgICAgICAgdXNlck5hbWU6IGh0dHBPcHRpb25zLnVzZXJOYW1lLFxuICAgICAgICAgICAgICAgIHBhc3N3b3JkOiBodHRwT3B0aW9ucy5wYXNzd29yZCxcbiAgICAgICAgICAgIH07XG4gICAgICAgICAgICBpZiAoaHR0cE9wdGlvbnMuYWNjb3VudCkge1xuICAgICAgICAgICAgICAgIC8vcGFzcyBpbiBudWxsIGZvciBhY2NvdW50IHVuZGVyIG9wdGlvbnMgaWYgeW91IGRvbid0IHdhbnQgaXQgdG8gYmUgc2VudFxuICAgICAgICAgICAgICAgIHBvc3RQYXJhbXMuYWNjb3VudCA9IGh0dHBPcHRpb25zLmFjY291bnQ7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIHJldHVybiBodHRwLnBvc3QocG9zdFBhcmFtcywgaHR0cE9wdGlvbnMpO1xuICAgICAgICB9LFxuXG4gICAgICAgIC8vIChyZXBsYWNlIHdpdGggLyogKi8gY29tbWVudCBibG9jaywgdG8gbWFrZSB2aXNpYmxlIGluIGRvY3MsIG9uY2UgdGhpcyBpcyBtb3JlIHRoYW4gYSBub29wKVxuICAgICAgICAvL1xuICAgICAgICAvLyBMb2dzIHVzZXIgb3V0IGZyb20gc3BlY2lmaWVkIGFjY291bnRzLlxuICAgICAgICAvL1xuICAgICAgICAvLyBFcGljZW50ZXIgbG9nb3V0IGlzIG5vdCBpbXBsZW1lbnRlZCB5ZXQsIHNvIGZvciBub3cgdGhpcyBpcyBhIGR1bW15IHByb21pc2UgdGhhdCBnZXRzIGF1dG9tYXRpY2FsbHkgcmVzb2x2ZWQuXG4gICAgICAgIC8vXG4gICAgICAgIC8vICoqRXhhbXBsZSoqXG4gICAgICAgIC8vXG4gICAgICAgIC8vICAgICAgYXV0aC5sb2dvdXQoKTtcbiAgICAgICAgLy9cbiAgICAgICAgLy8gKipQYXJhbWV0ZXJzKipcbiAgICAgICAgLy8gQHBhcmFtIHtPYmplY3R9IGBvcHRpb25zYCAoT3B0aW9uYWwpIE92ZXJyaWRlcyBmb3IgY29uZmlndXJhdGlvbiBvcHRpb25zLlxuICAgICAgICAvL1xuICAgICAgICBsb2dvdXQ6IGZ1bmN0aW9uIChvcHRpb25zKSB7XG4gICAgICAgICAgICB2YXIgZHRkID0gJC5EZWZlcnJlZCgpO1xuICAgICAgICAgICAgZHRkLnJlc29sdmUoKTtcbiAgICAgICAgICAgIHJldHVybiBkdGQucHJvbWlzZSgpO1xuICAgICAgICB9XG4gICAgfTtcblxuICAgICQuZXh0ZW5kKHRoaXMsIHB1YmxpY0FQSSk7XG59O1xuIiwiLyoqXG4gKiAjIyBDaGFubmVsIFNlcnZpY2VcbiAqXG4gKiBUaGUgRXBpY2VudGVyIHBsYXRmb3JtIHByb3ZpZGVzIGEgcHVzaCBjaGFubmVsLCB3aGljaCBhbGxvd3MgeW91IHRvIHB1Ymxpc2ggYW5kIHN1YnNjcmliZSB0byBtZXNzYWdlcyB3aXRoaW4gYSBbcHJvamVjdF0oLi4vLi4vLi4vZ2xvc3NhcnkvI3Byb2plY3RzKSwgW2dyb3VwXSguLi8uLi8uLi9nbG9zc2FyeS8jZ3JvdXBzKSwgb3IgW211bHRpcGxheWVyIHdvcmxkXSguLi8uLi8uLi9nbG9zc2FyeS8jd29ybGQpLiBUaGVyZSBhcmUgdHdvIG1haW4gdXNlIGNhc2VzIGZvciB0aGUgY2hhbm5lbDogZXZlbnQgbm90aWZpY2F0aW9ucyBhbmQgY2hhdCBtZXNzYWdlcy5cbiAqXG4gKiBJZiB5b3UgYXJlIGRldmVsb3Bpbmcgd2l0aCBFcGljZW50ZXIuanMsIHlvdSBzaG91bGQgdXNlIHRoZSBbRXBpY2VudGVyIENoYW5uZWwgTWFuYWdlcl0oLi4vZXBpY2VudGVyLWNoYW5uZWwtbWFuYWdlci8pIGRpcmVjdGx5LiBUaGUgRXBpY2VudGVyIENoYW5uZWwgTWFuYWdlciBkb2N1bWVudGF0aW9uIGFsc28gaGFzIG1vcmUgW2JhY2tncm91bmRdKC4uL2VwaWNlbnRlci1jaGFubmVsLW1hbmFnZXIvI2JhY2tncm91bmQpIGluZm9ybWF0aW9uIG9uIGNoYW5uZWxzIGFuZCB0aGVpciB1c2UuXG4gKlxuICogVGhlIENoYW5uZWwgU2VydmljZSBpcyBhIGJ1aWxkaW5nIGJsb2NrIGZvciB0aGlzIGZ1bmN0aW9uYWxpdHkuIEl0IGNyZWF0ZXMgYSBwdWJsaXNoLXN1YnNjcmliZSBvYmplY3QsIGFsbG93aW5nIHlvdSB0byBwdWJsaXNoIG1lc3NhZ2VzLCBzdWJzY3JpYmUgdG8gbWVzc2FnZXMsIG9yIHVuc3Vic2NyaWJlIGZyb20gbWVzc2FnZXMgZm9yIGEgZ2l2ZW4gJ3RvcGljJyBvbiBhIGAkLmNvbWV0ZGAgdHJhbnNwb3J0IGluc3RhbmNlLlxuICpcbiAqIFlvdSdsbCBuZWVkIHRvIGluY2x1ZGUgdGhlIGBlcGljZW50ZXItbXVsdGlwbGF5ZXItZGVwZW5kZW5jaWVzLmpzYCBsaWJyYXJ5IGluIGFkZGl0aW9uIHRvIHRoZSBgZXBpY2VudGVyLmpzYCBsaWJyYXJ5IGluIHlvdXIgcHJvamVjdCB0byB1c2UgdGhlIENoYW5uZWwgU2VydmljZS4gU2VlIFtJbmNsdWRpbmcgRXBpY2VudGVyLmpzXSguLi8uLi8jaW5jbHVkZSkuXG4gKlxuICogVG8gdXNlIHRoZSBDaGFubmVsIFNlcnZpY2UsIGluc3RhbnRpYXRlIGl0LCB0aGVuIG1ha2UgY2FsbHMgdG8gYW55IG9mIHRoZSBtZXRob2RzIHlvdSBuZWVkLlxuICpcbiAqICAgICAgICB2YXIgY3MgPSBuZXcgRi5zZXJ2aWNlLkNoYW5uZWwoKTtcbiAqICAgICAgICBjcy5wdWJsaXNoKCcvYWNtZS1zaW11bGF0aW9ucy9zdXBwbHktY2hhaW4tZ2FtZS9mYWxsLXNlbWluYXIvcnVuL3ZhcmlhYmxlcycsIHsgcHJpY2U6IDUwIH0pO1xuICpcbiAqIElmIHlvdSBhcmUgd29ya2luZyB0aHJvdWdoIHRoZSBbRXBpY2VudGVyIENoYW5uZWwgTWFuYWdlcl0oLi4vZXBpY2VudGVyLWNoYW5uZWwtbWFuYWdlci8pLCB3aGVuIHlvdSBhc2sgdG8gXCJnZXRcIiBhIHBhcnRpY3VsYXIgY2hhbm5lbCwgeW91IGFyZSByZWFsbHkgYXNraW5nIGZvciBhbiBpbnN0YW5jZSBvZiB0aGUgQ2hhbm5lbCBTZXJ2aWNlIHdpdGggYSB0b3BpYyBhbHJlYWR5IHNldCwgZm9yIGV4YW1wbGUgdG8gdGhlIGFwcHJvcHJpYXRlIGdyb3VwIG9yIHdvcmxkOlxuICpcbiAqICAgICAgdmFyIGNtID0gbmV3IEYubWFuYWdlci5DaGFubmVsTWFuYWdlcigpO1xuICogICAgICB2YXIgZ2MgPSBjbS5nZXRHcm91cENoYW5uZWwoKTtcbiAqICAgICAgLy8gYmVjYXVzZSB3ZSB1c2VkIGFuIEVwaWNlbnRlciBDaGFubmVsIE1hbmFnZXIgdG8gZ2V0IHRoZSBncm91cCBjaGFubmVsLFxuICogICAgICAvLyBzdWJzY3JpYmUoKSBhbmQgcHVibGlzaCgpIGhlcmUgZGVmYXVsdCB0byB0aGUgYmFzZSB0b3BpYyBmb3IgdGhlIGdyb3VwXG4gKiAgICAgIGdjLnN1YnNjcmliZSgnJywgZnVuY3Rpb24oZGF0YSkgeyBjb25zb2xlLmxvZyhkYXRhKTsgfSk7XG4gKiAgICAgIGdjLnB1Ymxpc2goJycsIHsgbWVzc2FnZTogJ2EgbmV3IG1lc3NhZ2UgdG8gdGhlIGdyb3VwJyB9KTtcbiAqXG4gKiBUaGUgcGFyYW1ldGVycyBmb3IgaW5zdGFudGlhdGluZyBhIENoYW5uZWwgU2VydmljZSBpbmNsdWRlOlxuICpcbiAqICogYG9wdGlvbnNgIFRoZSBvcHRpb25zIG9iamVjdCB0byBjb25maWd1cmUgdGhlIENoYW5uZWwgU2VydmljZS5cbiAqICogYG9wdGlvbnMuYmFzZWAgVGhlIGJhc2UgdG9waWMuIFRoaXMgaXMgYWRkZWQgYXMgYSBwcmVmaXggdG8gYWxsIGZ1cnRoZXIgdG9waWNzIHlvdSBwdWJsaXNoIG9yIHN1YnNjcmliZSB0byB3aGlsZSB3b3JraW5nIHdpdGggdGhpcyBDaGFubmVsIFNlcnZpY2UuXG4gKiAqIGBvcHRpb25zLnRvcGljUmVzb2x2ZXJgIEEgZnVuY3Rpb24gdGhhdCBwcm9jZXNzZXMgYWxsICd0b3BpY3MnIHBhc3NlZCBpbnRvIHRoZSBgcHVibGlzaGAgYW5kIGBzdWJzY3JpYmVgIG1ldGhvZHMuIFRoaXMgaXMgdXNlZnVsIGlmIHlvdSB3YW50IHRvIGltcGxlbWVudCB5b3VyIG93biBzZXJpYWxpemUgZnVuY3Rpb25zIGZvciBjb252ZXJ0aW5nIGN1c3RvbSBvYmplY3RzIHRvIHRvcGljIG5hbWVzLiBSZXR1cm5zIGEgU3RyaW5nLiBCeSBkZWZhdWx0LCBpdCBqdXN0IGVjaG9lcyB0aGUgdG9waWMuXG4gKiAqIGBvcHRpb25zLnRyYW5zcG9ydGAgVGhlIGluc3RhbmNlIG9mIGAkLmNvbWV0ZGAgdG8gaG9vayBvbnRvLiBTZWUgaHR0cDovL2RvY3MuY29tZXRkLm9yZy9yZWZlcmVuY2UvamF2YXNjcmlwdC5odG1sIGZvciBhZGRpdGlvbmFsIGJhY2tncm91bmQgb24gY29tZXRkLlxuICovXG5cbid1c2Ugc3RyaWN0JztcbnZhciBDaGFubmVsID0gZnVuY3Rpb24gKG9wdGlvbnMpIHtcbiAgICB2YXIgZGVmYXVsdHMgPSB7XG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIFRoZSBiYXNlIHRvcGljLiBUaGlzIGlzIGFkZGVkIGFzIGEgcHJlZml4IHRvIGFsbCBmdXJ0aGVyIHRvcGljcyB5b3UgcHVibGlzaCBvciBzdWJzY3JpYmUgdG8gd2hpbGUgd29ya2luZyB3aXRoIHRoaXMgQ2hhbm5lbCBTZXJ2aWNlLlxuICAgICAgICAgKiBAdHlwZSB7c3RyaW5nfVxuICAgICAgICAgKi9cbiAgICAgICAgYmFzZTogJycsXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIEEgZnVuY3Rpb24gdGhhdCBwcm9jZXNzZXMgYWxsICd0b3BpY3MnIHBhc3NlZCBpbnRvIHRoZSBgcHVibGlzaGAgYW5kIGBzdWJzY3JpYmVgIG1ldGhvZHMuIFRoaXMgaXMgdXNlZnVsIGlmIHlvdSB3YW50IHRvIGltcGxlbWVudCB5b3VyIG93biBzZXJpYWxpemUgZnVuY3Rpb25zIGZvciBjb252ZXJ0aW5nIGN1c3RvbSBvYmplY3RzIHRvIHRvcGljIG5hbWVzLiBCeSBkZWZhdWx0LCBpdCBqdXN0IGVjaG9lcyB0aGUgdG9waWMuXG4gICAgICAgICAqXG4gICAgICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICAgICAqXG4gICAgICAgICAqICogYHRvcGljYCBUb3BpYyB0byBwYXJzZS5cbiAgICAgICAgICpcbiAgICAgICAgICogKipSZXR1cm4gVmFsdWUqKlxuICAgICAgICAgKlxuICAgICAgICAgKiAqICpTdHJpbmcqOiBUaGlzIGZ1bmN0aW9uIHNob3VsZCByZXR1cm4gYSBzdHJpbmcgdG9waWMuXG4gICAgICAgICAqXG4gICAgICAgICAqIEB0eXBlIHtmdW5jdGlvbn1cbiAgICAgICAgICogQHBhcmFtIHtTdHJpbmd9IHRvcGljIHRvcGljIHRvIHJlc29sdmVcbiAgICAgICAgICogQHJldHVybiB7U3RyaW5nfVxuICAgICAgICAgKi9cbiAgICAgICAgdG9waWNSZXNvbHZlcjogZnVuY3Rpb24gKHRvcGljKSB7XG4gICAgICAgICAgICByZXR1cm4gdG9waWM7XG4gICAgICAgIH0sXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIFRoZSBpbnN0YW5jZSBvZiBgJC5jb21ldGRgIHRvIGhvb2sgb250by5cbiAgICAgICAgICogQHR5cGUge29iamVjdH1cbiAgICAgICAgICovXG4gICAgICAgIHRyYW5zcG9ydDogbnVsbFxuICAgIH07XG4gICAgdGhpcy5jaGFubmVsT3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LCBkZWZhdWx0cywgb3B0aW9ucyk7XG59O1xuXG52YXIgbWFrZU5hbWUgPSBmdW5jdGlvbiAoY2hhbm5lbE5hbWUsIHRvcGljKSB7XG4gICAgLy9SZXBsYWNlIHRyYWlsaW5nL2RvdWJsZSBzbGFzaGVzXG4gICAgdmFyIG5ld05hbWUgPSAoY2hhbm5lbE5hbWUgPyAoY2hhbm5lbE5hbWUgKyAnLycgKyB0b3BpYykgOiB0b3BpYykucmVwbGFjZSgvXFwvXFwvL2csICcvJykucmVwbGFjZSgvXFwvJC8sICcnKTtcbiAgICByZXR1cm4gbmV3TmFtZTtcbn07XG5cblxuQ2hhbm5lbC5wcm90b3R5cGUgPSAkLmV4dGVuZChDaGFubmVsLnByb3RvdHlwZSwge1xuXG4gICAgLy8gZnV0dXJlIGZ1bmN0aW9uYWxpdHk6XG4gICAgLy8gICAgICAvLyBTZXQgdGhlIGNvbnRleHQgZm9yIHRoZSBjYWxsYmFja1xuICAgIC8vICAgICAgY3Muc3Vic2NyaWJlKCdydW4nLCBmdW5jdGlvbiAoKSB7IHRoaXMuaW5uZXJIVE1MID0gJ1RyaWdnZXJlZCd9LCBkb2N1bWVudC5ib2R5KTtcbiAgICAgLy9cbiAgICAgLy8gICAgICAvLyBDb250cm9sIHRoZSBvcmRlciBvZiBvcGVyYXRpb25zIGJ5IHNldHRpbmcgdGhlIGBwcmlvcml0eWBcbiAgICAgLy8gICAgICBjcy5zdWJzY3JpYmUoJ3J1bicsIGNiLCB0aGlzLCB7cHJpb3JpdHk6IDl9KTtcbiAgICAgLy9cbiAgICAgLy8gICAgICAvLyBPbmx5IGV4ZWN1dGUgdGhlIGNhbGxiYWNrLCBgY2JgLCBpZiB0aGUgdmFsdWUgb2YgdGhlIGBwcmljZWAgdmFyaWFibGUgaXMgNTBcbiAgICAgLy8gICAgICBjcy5zdWJzY3JpYmUoJ3J1bi92YXJpYWJsZXMvcHJpY2UnLCBjYiwgdGhpcywge3ByaW9yaXR5OiAzMCwgdmFsdWU6IDUwfSk7XG4gICAgIC8vXG4gICAgIC8vICAgICAgLy8gT25seSBleGVjdXRlIHRoZSBjYWxsYmFjaywgYGNiYCwgaWYgdGhlIHZhbHVlIG9mIHRoZSBgcHJpY2VgIHZhcmlhYmxlIGlzIGdyZWF0ZXIgdGhhbiA1MFxuICAgICAvLyAgICAgIHN1YnNjcmliZSgncnVuL3ZhcmlhYmxlcy9wcmljZScsIGNiLCB0aGlzLCB7cHJpb3JpdHk6IDMwLCB2YWx1ZTogJz41MCd9KTtcbiAgICAgLy9cbiAgICAgLy8gICAgICAvLyBPbmx5IGV4ZWN1dGUgdGhlIGNhbGxiYWNrLCBgY2JgLCBpZiB0aGUgdmFsdWUgb2YgdGhlIGBwcmljZWAgdmFyaWFibGUgaXMgZXZlblxuICAgICAvLyAgICAgIHN1YnNjcmliZSgncnVuL3ZhcmlhYmxlcy9wcmljZScsIGNiLCB0aGlzLCB7cHJpb3JpdHk6IDMwLCB2YWx1ZTogZnVuY3Rpb24gKHZhbCkge3JldHVybiB2YWwgJSAyID09PSAwfX0pO1xuXG5cbiAgICAvKipcbiAgICAgKiBTdWJzY3JpYmUgdG8gY2hhbmdlcyBvbiBhIHRvcGljLlxuICAgICAqXG4gICAgICogVGhlIHRvcGljIHNob3VsZCBpbmNsdWRlIHRoZSBmdWxsIHBhdGggb2YgdGhlIGFjY291bnQgaWQgKCoqVGVhbSBJRCoqIGZvciB0ZWFtIHByb2plY3RzKSwgcHJvamVjdCBpZCwgYW5kIGdyb3VwIG5hbWUuIChJbiBtb3N0IGNhc2VzLCBpdCBpcyBzaW1wbGVyIHRvIHVzZSB0aGUgW0VwaWNlbnRlciBDaGFubmVsIE1hbmFnZXJdKC4uL2VwaWNlbnRlci1jaGFubmVsLW1hbmFnZXIvKSBpbnN0ZWFkLCBpbiB3aGljaCBjYXNlIHRoaXMgaXMgY29uZmlndXJlZCBmb3IgeW91LilcbiAgICAgKlxuICAgICAqICAqKkV4YW1wbGVzKipcbiAgICAgKlxuICAgICAqICAgICAgdmFyIGNiID0gZnVuY3Rpb24odmFsKSB7IGNvbnNvbGUubG9nKHZhbC5kYXRhKTsgfTtcbiAgICAgKlxuICAgICAqICAgICAgLy8gU3Vic2NyaWJlIHRvIGNoYW5nZXMgb24gYSB0b3AtbGV2ZWwgJ3J1bicgdG9waWNcbiAgICAgKiAgICAgIGNzLnN1YnNjcmliZSgnL2FjbWUtc2ltdWxhdGlvbnMvc3VwcGx5LWNoYWluLWdhbWUvZmFsbC1zZW1pbmFyL3J1bicsIGNiKTtcbiAgICAgKlxuICAgICAqICAgICAgLy8gU3Vic2NyaWJlIHRvIGNoYW5nZXMgb24gY2hpbGRyZW4gb2YgdGhlICdydW4nIHRvcGljLiBOb3RlIHRoaXMgd2lsbCBhbHNvIGJlIHRyaWdnZXJlZCBmb3IgY2hhbmdlcyB0byBydW4ueC55LnouXG4gICAgICogICAgICBjcy5zdWJzY3JpYmUoJy9hY21lLXNpbXVsYXRpb25zL3N1cHBseS1jaGFpbi1nYW1lL2ZhbGwtc2VtaW5hci9ydW4vKicsIGNiKTtcbiAgICAgKlxuICAgICAqICAgICAgLy8gU3Vic2NyaWJlIHRvIGNoYW5nZXMgb24gYm90aCB0aGUgdG9wLWxldmVsICdydW4nIHRvcGljIGFuZCBpdHMgY2hpbGRyZW5cbiAgICAgKiAgICAgIGNzLnN1YnNjcmliZShbJy9hY21lLXNpbXVsYXRpb25zL3N1cHBseS1jaGFpbi1nYW1lL2ZhbGwtc2VtaW5hci9ydW4nLFxuICAgICAqICAgICAgICAgICcvYWNtZS1zaW11bGF0aW9ucy9zdXBwbHktY2hhaW4tZ2FtZS9mYWxsLXNlbWluYXIvcnVuLyonXSwgY2IpO1xuICAgICAqXG4gICAgICogICAgICAvLyBTdWJzY3JpYmUgdG8gY2hhbmdlcyBvbiBhIHBhcnRpY3VsYXIgdmFyaWFibGVcbiAgICAgKiAgICAgIHN1YnNjcmliZSgnL2FjbWUtc2ltdWxhdGlvbnMvc3VwcGx5LWNoYWluLWdhbWUvZmFsbC1zZW1pbmFyL3J1bi92YXJpYWJsZXMvcHJpY2UnLCBjYik7XG4gICAgICpcbiAgICAgKlxuICAgICAqICoqUmV0dXJuIFZhbHVlKipcbiAgICAgKlxuICAgICAqICogKlN0cmluZyogUmV0dXJucyBhIHRva2VuIHlvdSBjYW4gbGF0ZXIgdXNlIHRvIHVuc3Vic2NyaWJlLlxuICAgICAqXG4gICAgICogKipQYXJhbWV0ZXJzKipcbiAgICAgKiBAcGFyYW0gIHtTdHJpbmd8QXJyYXl9ICAgdG9waWMgICAgTGlzdCBvZiB0b3BpY3MgdG8gbGlzdGVuIGZvciBjaGFuZ2VzIG9uLlxuICAgICAqIEBwYXJhbSAge0Z1bmN0aW9ufSBjYWxsYmFjayBDYWxsYmFjayBmdW5jdGlvbiB0byBleGVjdXRlLiBDYWxsYmFjayBpcyBjYWxsZWQgd2l0aCBzaWduYXR1cmUgYChldnQsIHBheWxvYWQsIG1ldGFkYXRhKWAuXG4gICAgICogQHBhcmFtICB7T2JqZWN0fSAgIGNvbnRleHQgIENvbnRleHQgaW4gd2hpY2ggdGhlIGBjYWxsYmFja2AgaXMgZXhlY3V0ZWQuXG4gICAgICogQHBhcmFtICB7T2JqZWN0fSAgIG9wdGlvbnMgIChPcHRpb25hbCkgT3ZlcnJpZGVzIGZvciBjb25maWd1cmF0aW9uIG9wdGlvbnMuXG4gICAgICogQHBhcmFtICB7TnVtYmVyfSAgIG9wdGlvbnMucHJpb3JpdHkgIFVzZWQgdG8gY29udHJvbCBvcmRlciBvZiBvcGVyYXRpb25zLiBEZWZhdWx0cyB0byAwLiBDYW4gYmUgYW55ICt2ZSBvciAtdmUgbnVtYmVyLlxuICAgICAqIEBwYXJhbSAge1N0cmluZ3xOdW1iZXJ8RnVuY3Rpb259ICAgb3B0aW9ucy52YWx1ZSBUaGUgYGNhbGxiYWNrYCBpcyBvbmx5IHRyaWdnZXJlZCBpZiB0aGlzIGNvbmRpdGlvbiBtYXRjaGVzLiBTZWUgZXhhbXBsZXMgZm9yIGRldGFpbHMuXG4gICAgICogQHJldHVybiB7c3RyaW5nfSBTdWJzY3JpcHRpb24gSURcbiAgICAgKi9cbiAgICBzdWJzY3JpYmU6IGZ1bmN0aW9uICh0b3BpYywgY2FsbGJhY2ssIGNvbnRleHQsIG9wdGlvbnMpIHtcblxuICAgICAgICB2YXIgdG9waWNzID0gW10uY29uY2F0KHRvcGljKTtcbiAgICAgICAgdmFyIG1lID0gdGhpcztcbiAgICAgICAgdmFyIHN1YnNjcmlwdGlvbklkcyA9IFtdO1xuICAgICAgICB2YXIgb3B0cyA9IG1lLmNoYW5uZWxPcHRpb25zO1xuXG4gICAgICAgIG9wdHMudHJhbnNwb3J0LmJhdGNoKGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgICQuZWFjaCh0b3BpY3MsIGZ1bmN0aW9uIChpbmRleCwgdG9waWMpIHtcbiAgICAgICAgICAgICAgICB0b3BpYyA9IG1ha2VOYW1lKG9wdHMuYmFzZSwgb3B0cy50b3BpY1Jlc29sdmVyKHRvcGljKSk7XG4gICAgICAgICAgICAgICAgc3Vic2NyaXB0aW9uSWRzLnB1c2gob3B0cy50cmFuc3BvcnQuc3Vic2NyaWJlKHRvcGljLCBjYWxsYmFjaykpO1xuICAgICAgICAgICAgfSk7XG4gICAgICAgIH0pO1xuICAgICAgICByZXR1cm4gKHN1YnNjcmlwdGlvbklkc1sxXSA/IHN1YnNjcmlwdGlvbklkcyA6IHN1YnNjcmlwdGlvbklkc1swXSk7XG4gICAgfSxcblxuICAgIC8qKlxuICAgICAqIFB1Ymxpc2ggZGF0YSB0byBhIHRvcGljLlxuICAgICAqXG4gICAgICogKipFeGFtcGxlcyoqXG4gICAgICpcbiAgICAgKiAgICAgIC8vIFNlbmQgZGF0YSB0byBhbGwgc3Vic2NyaWJlcnMgb2YgdGhlICdydW4nIHRvcGljXG4gICAgICogICAgICBjcy5wdWJsaXNoKCcvYWNtZS1zaW11bGF0aW9ucy9zdXBwbHktY2hhaW4tZ2FtZS9mYWxsLXNlbWluYXIvcnVuJywgeyBjb21wbGV0ZWQ6IGZhbHNlIH0pO1xuICAgICAqXG4gICAgICogICAgICAvLyBTZW5kIGRhdGEgdG8gYWxsIHN1YnNjcmliZXJzIG9mIHRoZSAncnVuL3ZhcmlhYmxlcycgdG9waWNcbiAgICAgKiAgICAgIGNzLnB1Ymxpc2goJy9hY21lLXNpbXVsYXRpb25zL3N1cHBseS1jaGFpbi1nYW1lL2ZhbGwtc2VtaW5hci9ydW4vdmFyaWFibGVzJywgeyBwcmljZTogNTAgfSk7XG4gICAgICpcbiAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAqXG4gICAgICogQHBhcmFtICB7U3RyaW5nfSB0b3BpYyBUb3BpYyB0byBwdWJsaXNoIHRvLlxuICAgICAqIEBwYXJhbSAgeyp9IGRhdGEgIERhdGEgdG8gcHVibGlzaCB0byB0b3BpYy5cbiAgICAgKiBAcmV0dXJuIHtBcnJheSB8IE9iamVjdH0gUmVzcG9uc2VzIHRvIHB1Ymxpc2hlZCBkYXRhXG4gICAgICpcbiAgICAgKi9cbiAgICBwdWJsaXNoOiBmdW5jdGlvbiAodG9waWMsIGRhdGEpIHtcbiAgICAgICAgdmFyIHRvcGljcyA9IFtdLmNvbmNhdCh0b3BpYyk7XG4gICAgICAgIHZhciBtZSA9IHRoaXM7XG4gICAgICAgIHZhciByZXR1cm5PYmpzID0gW107XG4gICAgICAgIHZhciBvcHRzID0gbWUuY2hhbm5lbE9wdGlvbnM7XG5cblxuICAgICAgICBvcHRzLnRyYW5zcG9ydC5iYXRjaChmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICAkLmVhY2godG9waWNzLCBmdW5jdGlvbiAoaW5kZXgsIHRvcGljKSB7XG4gICAgICAgICAgICAgICAgdG9waWMgPSBtYWtlTmFtZShvcHRzLmJhc2UsIG9wdHMudG9waWNSZXNvbHZlcih0b3BpYykpO1xuICAgICAgICAgICAgICAgIGlmICh0b3BpYy5jaGFyQXQodG9waWMubGVuZ3RoIC0gMSkgPT09ICcqJykge1xuICAgICAgICAgICAgICAgICAgICB0b3BpYyA9IHRvcGljLnJlcGxhY2UoL1xcKiskLywgJycpO1xuICAgICAgICAgICAgICAgICAgICBjb25zb2xlLndhcm4oJ1lvdSBjYW4gY2Fubm90IHB1Ymxpc2ggdG8gY2hhbm5lbHMgd2l0aCB3aWxkY2FyZHMuIFB1Ymxpc2hpbmcgdG8gJywgdG9waWMsICdpbnN0ZWFkJyk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIHJldHVybk9ianMucHVzaChvcHRzLnRyYW5zcG9ydC5wdWJsaXNoKHRvcGljLCBkYXRhKSk7XG4gICAgICAgICAgICB9KTtcbiAgICAgICAgfSk7XG4gICAgICAgIHJldHVybiAocmV0dXJuT2Jqc1sxXSA/IHJldHVybk9ianMgOiByZXR1cm5PYmpzWzBdKTtcbiAgICB9LFxuXG4gICAgLyoqXG4gICAgICogVW5zdWJzY3JpYmUgZnJvbSBjaGFuZ2VzIHRvIGEgdG9waWMuXG4gICAgICpcbiAgICAgKiAqKkV4YW1wbGUqKlxuICAgICAqXG4gICAgICogICAgICBjcy51bnN1YnNjcmliZSgnc2FtcGxlVG9rZW4nKTtcbiAgICAgKlxuICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICogQHBhcmFtICB7U3RyaW5nfSB0b2tlbiBUaGUgdG9rZW4gZm9yIHRvcGljIGlzIHJldHVybmVkIHdoZW4geW91IGluaXRpYWxseSBzdWJzY3JpYmUuIFBhc3MgaXQgaGVyZSB0byB1bnN1YnNjcmliZSBmcm9tIHRoYXQgdG9waWMuXG4gICAgICogQHJldHVybiB7T2JqZWN0fSByZWZlcmVuY2UgdG8gY3VycmVudCBpbnN0YW5jZVxuICAgICAqL1xuICAgIHVuc3Vic2NyaWJlOiBmdW5jdGlvbiAodG9rZW4pIHtcbiAgICAgICAgdGhpcy5jaGFubmVsT3B0aW9ucy50cmFuc3BvcnQudW5zdWJzY3JpYmUodG9rZW4pO1xuICAgICAgICByZXR1cm4gdGhpcztcbiAgICB9LFxuXG4gICAgLyoqXG4gICAgICogU3RhcnQgbGlzdGVuaW5nIGZvciBldmVudHMgb24gdGhpcyBpbnN0YW5jZS4gU2lnbmF0dXJlIGlzIHNhbWUgYXMgZm9yIGpRdWVyeSBFdmVudHM6IGh0dHA6Ly9hcGkuanF1ZXJ5LmNvbS9vbi8uXG4gICAgICpcbiAgICAgKiBTdXBwb3J0ZWQgZXZlbnRzIGFyZTogYGNvbm5lY3RgLCBgZGlzY29ubmVjdGAsIGBzdWJzY3JpYmVgLCBgdW5zdWJzY3JpYmVgLCBgcHVibGlzaGAsIGBlcnJvcmAuXG4gICAgICpcbiAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAqXG4gICAgICogQHBhcmFtIHtzdHJpbmd9IGV2ZW50IFRoZSBldmVudCB0eXBlLiBTZWUgbW9yZSBkZXRhaWwgYXQgalF1ZXJ5IEV2ZW50czogaHR0cDovL2FwaS5qcXVlcnkuY29tL29uLy5cbiAgICAgKi9cbiAgICBvbjogZnVuY3Rpb24gKGV2ZW50KSB7XG4gICAgICAgICQodGhpcykub24uYXBwbHkoJCh0aGlzKSwgYXJndW1lbnRzKTtcbiAgICB9LFxuXG4gICAgLyoqXG4gICAgICogU3RvcCBsaXN0ZW5pbmcgZm9yIGV2ZW50cyBvbiB0aGlzIGluc3RhbmNlLiBTaWduYXR1cmUgaXMgc2FtZSBhcyBmb3IgalF1ZXJ5IEV2ZW50czogaHR0cDovL2FwaS5qcXVlcnkuY29tL29mZi8uXG4gICAgICpcbiAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAqXG4gICAgICogQHBhcmFtIHtzdHJpbmd9IGV2ZW50IFRoZSBldmVudCB0eXBlLiBTZWUgbW9yZSBkZXRhaWwgYXQgalF1ZXJ5IEV2ZW50czogaHR0cDovL2FwaS5qcXVlcnkuY29tL29mZi8uXG4gICAgICovXG4gICAgb2ZmOiBmdW5jdGlvbiAoZXZlbnQpIHtcbiAgICAgICAgJCh0aGlzKS5vZmYuYXBwbHkoJCh0aGlzKSwgYXJndW1lbnRzKTtcbiAgICB9LFxuXG4gICAgLyoqXG4gICAgICogVHJpZ2dlciBldmVudHMgYW5kIGV4ZWN1dGUgaGFuZGxlcnMuIFNpZ25hdHVyZSBpcyBzYW1lIGFzIGZvciBqUXVlcnkgRXZlbnRzOiBodHRwOi8vYXBpLmpxdWVyeS5jb20vdHJpZ2dlci8uXG4gICAgICpcbiAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAqXG4gICAgICogQHBhcmFtIHtzdHJpbmd9IGV2ZW50IFRoZSBldmVudCB0eXBlLiBTZWUgbW9yZSBkZXRhaWwgYXQgalF1ZXJ5IEV2ZW50czogaHR0cDovL2FwaS5qcXVlcnkuY29tL3RyaWdnZXIvLlxuICAgICAqL1xuICAgIHRyaWdnZXI6IGZ1bmN0aW9uIChldmVudCkge1xuICAgICAgICAkKHRoaXMpLnRyaWdnZXIuYXBwbHkoJCh0aGlzKSwgYXJndW1lbnRzKTtcbiAgICB9XG5cbn0pO1xuXG5tb2R1bGUuZXhwb3J0cyA9IENoYW5uZWw7XG4iLCIvKipcbiAqIEBjbGFzcyBDb25maWd1cmF0aW9uU2VydmljZVxuICpcbiAqIEFsbCBzZXJ2aWNlcyB0YWtlIGluIGEgY29uZmlndXJhdGlvbiBzZXR0aW5ncyBvYmplY3QgdG8gY29uZmlndXJlIHRoZW1zZWx2ZXMuIEEgSlMgaGFzaCB7fSBpcyBhIHZhbGlkIGNvbmZpZ3VyYXRpb24gb2JqZWN0LCBidXQgb3B0aW9uYWxseSB5b3UgY2FuIHVzZSB0aGUgY29uZmlndXJhdGlvbiBzZXJ2aWNlIHRvIHRvZ2dsZSBjb25maWdzIGJhc2VkIG9uIHRoZSBlbnZpcm9ubWVudFxuICpcbiAqIEBleGFtcGxlXG4gKiAgICAgdmFyIGNzID0gcmVxdWlyZSgnY29uZmlndXJhdGlvbi1zZXJ2aWNlJykoe1xuICogICAgICAgICAgZGV2OiB7IC8vZW52aXJvbm1lbnRcbiAgICAgICAgICAgICAgICBwb3J0OiAzMDAwLFxuICAgICAgICAgICAgICAgIGhvc3Q6ICdsb2NhbGhvc3QnLFxuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIHByb2Q6IHtcbiAgICAgICAgICAgICAgICBwb3J0OiA4MDgwLFxuICAgICAgICAgICAgICAgIGhvc3Q6ICdhcGkuZm9yaW8uY29tJyxcbiAgICAgICAgICAgICAgICBsb2dMZXZlbDogJ25vbmUnXG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAgbG9nTGV2ZWw6ICdERUJVRycgLy9nbG9iYWxcbiAqICAgICB9KTtcbiAqXG4gKiAgICAgIGNzLmdldCgnbG9nTGV2ZWwnKTsgLy9yZXR1cm5zICdERUJVRydcbiAqXG4gKiAgICAgIGNzLnNldEVudignZGV2Jyk7XG4gKiAgICAgIGNzLmdldCgnbG9nTGV2ZWwnKTsgLy9yZXR1cm5zICdERUJVRydcbiAqXG4gKiAgICAgIGNzLnNldEVudigncHJvZCcpO1xuICogICAgICBjcy5nZXQoJ2xvZ0xldmVsJyk7IC8vcmV0dXJucyAnbm9uZSdcbiAqXG4gKi9cblxuJ3VzZSBzdHJpY3QnO1xudmFyIHVybFNlcnZpY2UgPSByZXF1aXJlKCcuL3VybC1jb25maWctc2VydmljZScpO1xuXG5tb2R1bGUuZXhwb3J0cyA9IGZ1bmN0aW9uIChjb25maWcpIHtcbiAgICAvL1RPRE86IEVudmlyb25tZW50c1xuICAgIHZhciBkZWZhdWx0cyA9IHtcbiAgICAgICAgbG9nTGV2ZWw6ICdOT05FJ1xuICAgIH07XG4gICAgdmFyIHNlcnZpY2VPcHRpb25zID0gJC5leHRlbmQoe30sIGRlZmF1bHRzLCBjb25maWcpO1xuICAgIHNlcnZpY2VPcHRpb25zLnNlcnZlciA9IHVybFNlcnZpY2Uoc2VydmljZU9wdGlvbnMuc2VydmVyKTtcblxuICAgIHJldHVybiB7XG5cbiAgICAgICAgZGF0YTogc2VydmljZU9wdGlvbnMsXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIFNldCB0aGUgZW52aXJvbm1lbnQga2V5IHRvIGdldCBjb25maWd1cmF0aW9uIG9wdGlvbnMgZnJvbVxuICAgICAgICAgKiBAcGFyYW0geyBzdHJpbmd9IGVudlxuICAgICAgICAgKi9cbiAgICAgICAgc2V0RW52OiBmdW5jdGlvbiAoZW52KSB7XG5cbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgICogR2V0IGNvbmZpZ3VyYXRpb24uXG4gICAgICAgICAqIEBwYXJhbSAgeyBzdHJpbmd9IHByb3BlcnR5IG9wdGlvbmFsXG4gICAgICAgICAqIEByZXR1cm4geyp9ICAgICAgICAgIFZhbHVlIG9mIHByb3BlcnR5IGlmIHNwZWNpZmllZCwgdGhlIGVudGlyZSBjb25maWcgb2JqZWN0IG90aGVyd2lzZVxuICAgICAgICAgKi9cbiAgICAgICAgZ2V0OiBmdW5jdGlvbiAocHJvcGVydHkpIHtcbiAgICAgICAgICAgIHJldHVybiBzZXJ2aWNlT3B0aW9uc1twcm9wZXJ0eV07XG4gICAgICAgIH0sXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIFNldCBjb25maWd1cmF0aW9uLlxuICAgICAgICAgKiBAcGFyYW0gIHsgc3RyaW5nfE9iamVjdH0ga2V5IGlmIGEga2V5IGlzIHByb3ZpZGVkLCBzZXQgYSBrZXkgdG8gdGhhdCB2YWx1ZS4gT3RoZXJ3aXNlIG1lcmdlIG9iamVjdCB3aXRoIGN1cnJlbnQgY29uZmlnXG4gICAgICAgICAqIEBwYXJhbSAgeyp9IHZhbHVlICB2YWx1ZSBmb3IgcHJvdmlkZWQga2V5XG4gICAgICAgICAqL1xuICAgICAgICBzZXQ6IGZ1bmN0aW9uIChrZXksIHZhbHVlKSB7XG4gICAgICAgICAgICBzZXJ2aWNlT3B0aW9uc1trZXldID0gdmFsdWU7XG4gICAgICAgIH1cbiAgICB9O1xufTtcblxuIiwiLyoqXG4gKiAjIyBEYXRhIEFQSSBTZXJ2aWNlXG4gKlxuICogVGhlIERhdGEgQVBJIFNlcnZpY2UgYWxsb3dzIHlvdSB0byBjcmVhdGUsIGFjY2VzcywgYW5kIG1hbmlwdWxhdGUgZGF0YSByZWxhdGVkIHRvIGFueSBvZiB5b3VyIHByb2plY3RzLiBEYXRhIGFyZSBvcmdhbml6ZWQgaW4gY29sbGVjdGlvbnMuIEVhY2ggY29sbGVjdGlvbiBjb250YWlucyBhIGRvY3VtZW50OyBlYWNoIGVsZW1lbnQgb2YgdGhpcyB0b3AtbGV2ZWwgZG9jdW1lbnQgaXMgYSBKU09OIG9iamVjdC4gKFNlZSBhZGRpdGlvbmFsIGluZm9ybWF0aW9uIG9uIHRoZSB1bmRlcmx5aW5nIFtEYXRhIEFQSV0oLi4vLi4vLi4vcmVzdF9hcGlzL2RhdGFfYXBpLykuKVxuICpcbiAqIEFsbCBBUEkgY2FsbHMgdGFrZSBpbiBhbiBcIm9wdGlvbnNcIiBvYmplY3QgYXMgdGhlIGxhc3QgcGFyYW1ldGVyLiBUaGUgb3B0aW9ucyBjYW4gYmUgdXNlZCB0byBleHRlbmQvb3ZlcnJpZGUgdGhlIERhdGEgQVBJIFNlcnZpY2UgZGVmYXVsdHMuIEluIHBhcnRpY3VsYXIsIHRoZXJlIGFyZSB0aHJlZSByZXF1aXJlZCBwYXJhbWV0ZXJzIHdoZW4geW91IGluc3RhbnRpYXRlIHRoZSBEYXRhIFNlcnZpY2U6XG4gKlxuICogKiBgYWNjb3VudGA6IEVwaWNlbnRlciBhY2NvdW50IGlkICgqKlRlYW0gSUQqKiBmb3IgdGVhbSBwcm9qZWN0cywgKipVc2VyIElEKiogZm9yIHBlcnNvbmFsIHByb2plY3RzKS5cbiAqICogYHByb2plY3RgOiBFcGljZW50ZXIgcHJvamVjdCBpZC5cbiAqICogYHJvb3RgOiBUaGUgdGhlIG5hbWUgb2YgdGhlIGNvbGxlY3Rpb24uIElmIHlvdSBoYXZlIG11bHRpcGxlIGNvbGxlY3Rpb25zIHdpdGhpbiBlYWNoIG9mIHlvdXIgcHJvamVjdHMsIHlvdSBjYW4gYWxzbyBwYXNzIHRoZSBjb2xsZWN0aW9uIG5hbWUgYXMgYW4gb3B0aW9uIGZvciBlYWNoIGNhbGwuXG4gKlxuICogICAgICAgdmFyIGRzID0gbmV3IEYuc2VydmljZS5EYXRhKHtcbiAqICAgICAgICAgIGFjY291bnQ6ICdhY21lLXNpbXVsYXRpb25zJyxcbiAqICAgICAgICAgIHByb2plY3Q6ICdzdXBwbHktY2hhaW4tZ2FtZScsXG4gKiAgICAgICAgICByb290OiAnc3VydmV5LXJlc3BvbnNlcycsXG4gKiAgICAgICAgICBzZXJ2ZXI6IHsgaG9zdDogJ2FwaS5mb3Jpby5jb20nIH1cbiAqICAgICAgIH0pO1xuICogICAgICAgZHMuc2F2ZUFzKCd1c2VyMScsXG4gKiAgICAgICAgICB7ICdxdWVzdGlvbjEnOiAyLCAncXVlc3Rpb24yJzogMTAsXG4gKiAgICAgICAgICAncXVlc3Rpb24zJzogZmFsc2UsICdxdWVzdGlvbjQnOiAnc29tZXRpbWVzJyB9ICk7XG4gKiAgICAgICBkcy5zYXZlQXMoJ3VzZXIyJyxcbiAqICAgICAgICAgIHsgJ3F1ZXN0aW9uMSc6IDMsICdxdWVzdGlvbjInOiA4LFxuICogICAgICAgICAgJ3F1ZXN0aW9uMyc6IHRydWUsICdxdWVzdGlvbjQnOiAnYWx3YXlzJyB9ICk7XG4gKiAgICAgICBkcy5xdWVyeSgnJyx7ICdxdWVzdGlvbjInOiB7ICckZ3QnOiA5fSB9KTtcbiAqXG4gKiBOb3RlIHRoYXQgaW4gYWRkaXRpb24gdG8gdGhlIGBhY2NvdW50YCwgYHByb2plY3RgLCBhbmQgYHJvb3RgLCB0aGUgRGF0YSBTZXJ2aWNlIHBhcmFtZXRlcnMgb3B0aW9uYWxseSBpbmNsdWRlIGEgYHNlcnZlcmAgb2JqZWN0LCB3aG9zZSBgaG9zdGAgZmllbGQgY29udGFpbnMgdGhlIFVSSSBvZiB0aGUgRm9yaW8gc2VydmVyLiBUaGlzIGlzIGF1dG9tYXRpY2FsbHkgc2V0LCBidXQgeW91IGNhbiBwYXNzIGl0IGV4cGxpY2l0bHkgaWYgZGVzaXJlZC4gSXQgaXMgbW9zdCBjb21tb25seSB1c2VkIGZvciBjbGFyaXR5IHdoZW4geW91IGFyZSBbaG9zdGluZyBhbiBFcGljZW50ZXIgcHJvamVjdCBvbiB5b3VyIG93biBzZXJ2ZXJdKC4uLy4uLy4uL2hvd190by9zZWxmX2hvc3RpbmcvKS5cbiAqL1xuXG4ndXNlIHN0cmljdCc7XG5cbnZhciBDb25maWdTZXJ2aWNlID0gcmVxdWlyZSgnLi9jb25maWd1cmF0aW9uLXNlcnZpY2UnKTtcbnZhciBxdXRpbCA9IHJlcXVpcmUoJy4uL3V0aWwvcXVlcnktdXRpbCcpO1xudmFyIFRyYW5zcG9ydEZhY3RvcnkgPSByZXF1aXJlKCcuLi90cmFuc3BvcnQvaHR0cC10cmFuc3BvcnQtZmFjdG9yeScpO1xudmFyIFNlc3Npb25NYW5hZ2VyID0gcmVxdWlyZSgnLi4vc3RvcmUvc2Vzc2lvbi1tYW5hZ2VyJyk7XG5cbm1vZHVsZS5leHBvcnRzID0gZnVuY3Rpb24gKGNvbmZpZykge1xuICAgIHZhciBkZWZhdWx0cyA9IHtcbiAgICAgICAgLyoqXG4gICAgICAgICAqIE5hbWUgb2YgY29sbGVjdGlvbi4gUmVxdWlyZWQuIERlZmF1bHRzIHRvIGAvYCwgdGhhdCBpcywgdGhlIHJvb3QgbGV2ZWwgb2YgeW91ciBwcm9qZWN0IGF0IGBmb3Jpby5jb20vYXBwL3lvdXItYWNjb3VudC1pZC95b3VyLXByb2plY3QtaWQvYCwgYnV0IG11c3QgYmUgc2V0IHRvIGEgY29sbGVjdGlvbiBuYW1lLlxuICAgICAgICAgKiBAdHlwZSB7U3RyaW5nfVxuICAgICAgICAgKi9cbiAgICAgICAgcm9vdDogJy8nLFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBUaGUgYWNjb3VudCBpZC4gSW4gdGhlIEVwaWNlbnRlciBVSSwgdGhpcyBpcyB0aGUgKipUZWFtIElEKiogKGZvciB0ZWFtIHByb2plY3RzKSBvciAqKlVzZXIgSUQqKiAoZm9yIHBlcnNvbmFsIHByb2plY3RzKS4gRGVmYXVsdHMgdG8gZW1wdHkgc3RyaW5nLiBJZiBsZWZ0IHVuZGVmaW5lZCwgdGFrZW4gZnJvbSB0aGUgVVJMLlxuICAgICAgICAgKiBAdHlwZSB7U3RyaW5nfVxuICAgICAgICAgKi9cbiAgICAgICAgYWNjb3VudDogdW5kZWZpbmVkLFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBUaGUgcHJvamVjdCBpZC4gRGVmYXVsdHMgdG8gZW1wdHkgc3RyaW5nLiBJZiBsZWZ0IHVuZGVmaW5lZCwgdGFrZW4gZnJvbSB0aGUgVVJMLlxuICAgICAgICAgKiBAdHlwZSB7U3RyaW5nfVxuICAgICAgICAgKi9cbiAgICAgICAgcHJvamVjdDogdW5kZWZpbmVkLFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBGb3Igb3BlcmF0aW9ucyB0aGF0IHJlcXVpcmUgYXV0aGVudGljYXRpb24sIHBhc3MgaW4gdGhlIHVzZXIgYWNjZXNzIHRva2VuIChkZWZhdWx0cyB0byBlbXB0eSBzdHJpbmcpLiBJZiB0aGUgdXNlciBpcyBhbHJlYWR5IGxvZ2dlZCBpbiB0byBFcGljZW50ZXIsIHRoZSB1c2VyIGFjY2VzcyB0b2tlbiBpcyBhbHJlYWR5IHNldCBpbiBhIGNvb2tpZSBhbmQgYXV0b21hdGljYWxseSBsb2FkZWQgZnJvbSB0aGVyZS4gKFNlZSBbbW9yZSBiYWNrZ3JvdW5kIG9uIGFjY2VzcyB0b2tlbnNdKC4uLy4uLy4uL3Byb2plY3RfYWNjZXNzLykpLlxuICAgICAgICAgKiBAc2VlIFtBdXRoZW50aWNhdGlvbiBBUEkgU2VydmljZV0oLi4vYXV0aC1hcGktc2VydmljZS8pIGZvciBnZXR0aW5nIHRva2Vucy5cbiAgICAgICAgICogQHR5cGUge1N0cmluZ31cbiAgICAgICAgICovXG4gICAgICAgIHRva2VuOiB1bmRlZmluZWQsXG5cbiAgICAgICAgLy9PcHRpb25zIHRvIHBhc3Mgb24gdG8gdGhlIHVuZGVybHlpbmcgdHJhbnNwb3J0IGxheWVyXG4gICAgICAgIHRyYW5zcG9ydDoge31cbiAgICB9O1xuICAgIHRoaXMuc2Vzc2lvbk1hbmFnZXIgPSBuZXcgU2Vzc2lvbk1hbmFnZXIoKTtcbiAgICB2YXIgc2VydmljZU9wdGlvbnMgPSB0aGlzLnNlc3Npb25NYW5hZ2VyLmdldE1lcmdlZE9wdGlvbnMoZGVmYXVsdHMsIGNvbmZpZyk7XG5cbiAgICB2YXIgdXJsQ29uZmlnID0gbmV3IENvbmZpZ1NlcnZpY2Uoc2VydmljZU9wdGlvbnMpLmdldCgnc2VydmVyJyk7XG4gICAgaWYgKHNlcnZpY2VPcHRpb25zLmFjY291bnQpIHtcbiAgICAgICAgdXJsQ29uZmlnLmFjY291bnRQYXRoID0gc2VydmljZU9wdGlvbnMuYWNjb3VudDtcbiAgICB9XG4gICAgaWYgKHNlcnZpY2VPcHRpb25zLnByb2plY3QpIHtcbiAgICAgICAgdXJsQ29uZmlnLnByb2plY3RQYXRoID0gc2VydmljZU9wdGlvbnMucHJvamVjdDtcbiAgICB9XG5cbiAgICB2YXIgZ2V0VVJMID0gZnVuY3Rpb24gKGtleSwgcm9vdCkge1xuICAgICAgICBpZiAoIXJvb3QpIHtcbiAgICAgICAgICAgIHJvb3QgPSBzZXJ2aWNlT3B0aW9ucy5yb290O1xuICAgICAgICB9XG4gICAgICAgIHZhciB1cmwgPSB1cmxDb25maWcuZ2V0QVBJUGF0aCgnZGF0YScpICsgcXV0aWwuYWRkVHJhaWxpbmdTbGFzaChyb290KTtcbiAgICAgICAgaWYgKGtleSkge1xuICAgICAgICAgICAgdXJsICs9IHF1dGlsLmFkZFRyYWlsaW5nU2xhc2goa2V5KTtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gdXJsO1xuICAgIH07XG5cbiAgICB2YXIgaHR0cE9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSwgc2VydmljZU9wdGlvbnMudHJhbnNwb3J0LCB7XG4gICAgICAgIHVybDogZ2V0VVJMXG4gICAgfSk7XG4gICAgaWYgKHNlcnZpY2VPcHRpb25zLnRva2VuKSB7XG4gICAgICAgIGh0dHBPcHRpb25zLmhlYWRlcnMgPSB7XG4gICAgICAgICAgICBBdXRob3JpemF0aW9uOiAnQmVhcmVyICcgKyBzZXJ2aWNlT3B0aW9ucy50b2tlblxuICAgICAgICB9O1xuICAgIH1cbiAgICB2YXIgaHR0cCA9IG5ldyBUcmFuc3BvcnRGYWN0b3J5KGh0dHBPcHRpb25zKTtcblxuICAgIHZhciBwdWJsaWNBUEkgPSB7XG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIFNlYXJjaCBmb3IgZGF0YSB3aXRoaW4gYSBjb2xsZWN0aW9uLlxuICAgICAgICAgKlxuICAgICAgICAgKiBTZWFyY2hpbmcgdXNpbmcgY29tcGFyaXNvbiBvciBsb2dpY2FsIG9wZXJhdG9ycyAoYXMgb3Bwb3NlZCB0byBleGFjdCBtYXRjaGVzKSByZXF1aXJlcyBNb25nb0RCIHN5bnRheC4gU2VlIHRoZSB1bmRlcmx5aW5nIFtEYXRhIEFQSV0oLi4vLi4vLi4vcmVzdF9hcGlzL2RhdGFfYXBpLyNzZWFyY2hpbmcpIGZvciBhZGRpdGlvbmFsIGRldGFpbHMuXG4gICAgICAgICAqXG4gICAgICAgICAqICoqRXhhbXBsZXMqKlxuICAgICAgICAgKlxuICAgICAgICAgKiAgICAgIC8vIHJlcXVlc3QgYWxsIGRhdGEgYXNzb2NpYXRlZCB3aXRoIGRvY3VtZW50ICd1c2VyMSdcbiAgICAgICAgICogICAgICBkcy5xdWVyeSgndXNlcjEnKTtcbiAgICAgICAgICpcbiAgICAgICAgICogICAgICAvLyBleGFjdCBtYXRjaGluZzpcbiAgICAgICAgICogICAgICAvLyByZXF1ZXN0IGFsbCBkb2N1bWVudHMgaW4gY29sbGVjdGlvbiB3aGVyZSAncXVlc3Rpb24yJyBpcyA5XG4gICAgICAgICAqICAgICAgZHMucXVlcnkoJycsIHsgJ3F1ZXN0aW9uMic6IDl9KTtcbiAgICAgICAgICpcbiAgICAgICAgICogICAgICAvLyBjb21wYXJpc29uIG9wZXJhdG9yczpcbiAgICAgICAgICogICAgICAvLyByZXF1ZXN0IGFsbCBkb2N1bWVudHMgaW4gY29sbGVjdGlvblxuICAgICAgICAgKiAgICAgIC8vIHdoZXJlICdxdWVzdGlvbjInIGlzIGdyZWF0ZXIgdGhhbiA5XG4gICAgICAgICAqICAgICAgZHMucXVlcnkoJycsIHsgJ3F1ZXN0aW9uMic6IHsgJyRndCc6IDl9IH0pO1xuICAgICAgICAgKlxuICAgICAgICAgKiAgICAgIC8vIGxvZ2ljYWwgb3BlcmF0b3JzOlxuICAgICAgICAgKiAgICAgIC8vIHJlcXVlc3QgYWxsIGRvY3VtZW50cyBpbiBjb2xsZWN0aW9uXG4gICAgICAgICAqICAgICAgLy8gd2hlcmUgJ3F1ZXN0aW9uMicgaXMgbGVzcyB0aGFuIDEwLCBhbmQgJ3F1ZXN0aW9uMycgaXMgZmFsc2VcbiAgICAgICAgICogICAgICBkcy5xdWVyeSgnJywgeyAnJGFuZCc6IFsgeyAncXVlc3Rpb24yJzogeyAnJGx0JzoxMH0gfSwgeyAncXVlc3Rpb24zJzogZmFsc2UgfV0gfSk7XG4gICAgICAgICAqXG4gICAgICAgICAqICAgICAgLy8gcmVndWxhciBleHByZXNzc2lvbnM6IHVzZSBhbnkgUGVybC1jb21wYXRpYmxlIHJlZ3VsYXIgZXhwcmVzc2lvbnNcbiAgICAgICAgICogICAgICAvLyByZXF1ZXN0IGFsbCBkb2N1bWVudHMgaW4gY29sbGVjdGlvblxuICAgICAgICAgKiAgICAgIC8vIHdoZXJlICdxdWVzdGlvbjUnIGNvbnRhaW5zIHRoZSBzdHJpbmcgJy4qZGF5J1xuICAgICAgICAgKiAgICAgIGRzLnF1ZXJ5KCcnLCB7ICdxdWVzdGlvbjUnOiB7ICckcmVnZXgnOiAnLipkYXknIH0gfSk7XG4gICAgICAgICAqXG4gICAgICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICAgICAqIEBwYXJhbSB7U3RyaW5nfSBrZXkgVGhlIG5hbWUgb2YgdGhlIGRvY3VtZW50IHRvIHNlYXJjaC4gUGFzcyB0aGUgZW1wdHkgc3RyaW5nICgnJykgdG8gc2VhcmNoIHRoZSBlbnRpcmUgY29sbGVjdGlvbi5cbiAgICAgICAgICogQHBhcmFtIHtPYmplY3R9IHF1ZXJ5IFRoZSBxdWVyeSBvYmplY3QuIEZvciBleGFjdCBtYXRjaGluZywgdGhpcyBvYmplY3QgY29udGFpbnMgdGhlIGZpZWxkIG5hbWUgYW5kIGZpZWxkIHZhbHVlIHRvIG1hdGNoLiBGb3IgbWF0Y2hpbmcgYmFzZWQgb24gY29tcGFyaXNvbiwgdGhpcyBvYmplY3QgY29udGFpbnMgdGhlIGZpZWxkIG5hbWUgYW5kIHRoZSBjb21wYXJpc29uIGV4cHJlc3Npb24uIEZvciBtYXRjaGluZyBiYXNlZCBvbiBsb2dpY2FsIG9wZXJhdG9ycywgdGhpcyBvYmplY3QgY29udGFpbnMgYW4gZXhwcmVzc2lvbiB1c2luZyBNb25nb0RCIHN5bnRheC4gU2VlIHRoZSB1bmRlcmx5aW5nIFtEYXRhIEFQSV0oLi4vLi4vLi4vcmVzdF9hcGlzL2RhdGFfYXBpLyNzZWFyY2hpbmcpIGZvciBhZGRpdGlvbmFsIGV4YW1wbGVzLlxuICAgICAgICAgKiBAcGFyYW0ge09iamVjdH0gb3V0cHV0TW9kaWZpZXIgKE9wdGlvbmFsKSBBdmFpbGFibGUgZmllbGRzIGluY2x1ZGU6IGBzdGFydHJlY29yZGAsIGBlbmRyZWNvcmRgLCBgc29ydGAsIGFuZCBgZGlyZWN0aW9uYCAoYGFzY2Agb3IgYGRlc2NgKS5cbiAgICAgICAgICogQHBhcmFtIHtPYmplY3R9IG9wdGlvbnMgKE9wdGlvbmFsKSBPdmVycmlkZXMgZm9yIGNvbmZpZ3VyYXRpb24gb3B0aW9ucy5cbiAgICAgICAgICogQHJldHVybiB7UHJvbWlzZX0gXG4gICAgICAgICAqL1xuICAgICAgICBxdWVyeTogZnVuY3Rpb24gKGtleSwgcXVlcnksIG91dHB1dE1vZGlmaWVyLCBvcHRpb25zKSB7XG4gICAgICAgICAgICB2YXIgcGFyYW1zID0gJC5leHRlbmQodHJ1ZSwgeyBxOiBxdWVyeSB9LCBvdXRwdXRNb2RpZmllcik7XG4gICAgICAgICAgICB2YXIgaHR0cE9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSwgc2VydmljZU9wdGlvbnMsIG9wdGlvbnMpO1xuICAgICAgICAgICAgaHR0cE9wdGlvbnMudXJsID0gZ2V0VVJMKGtleSwgaHR0cE9wdGlvbnMucm9vdCk7XG4gICAgICAgICAgICByZXR1cm4gaHR0cC5nZXQocGFyYW1zLCBodHRwT3B0aW9ucyk7XG4gICAgICAgIH0sXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIFNhdmUgZGF0YSBpbiBhbiBhbm9ueW1vdXMgZG9jdW1lbnQgd2l0aGluIHRoZSBjb2xsZWN0aW9uLlxuICAgICAgICAgKlxuICAgICAgICAgKiBUaGUgYHJvb3RgIG9mIHRoZSBjb2xsZWN0aW9uIG11c3QgYmUgc3BlY2lmaWVkLiBCeSBkZWZhdWx0IHRoZSBgcm9vdGAgaXMgdGFrZW4gZnJvbSB0aGUgRGF0YSBTZXJ2aWNlIGNvbmZpZ3VyYXRpb24gb3B0aW9uczsgeW91IGNhbiBhbHNvIHBhc3MgdGhlIGByb290YCB0byB0aGUgYHNhdmVgIGNhbGwgZXhwbGljaXRseSBieSBvdmVycmlkaW5nIHRoZSBvcHRpb25zICh0aGlyZCBwYXJhbWV0ZXIpLlxuICAgICAgICAgKlxuICAgICAgICAgKiAoQWRkaXRpb25hbCBiYWNrZ3JvdW5kOiBEb2N1bWVudHMgYXJlIHRvcC1sZXZlbCBlbGVtZW50cyB3aXRoaW4gYSBjb2xsZWN0aW9uLiBDb2xsZWN0aW9ucyBtdXN0IGJlIHVuaXF1ZSB3aXRoaW4gdGhpcyBhY2NvdW50ICh0ZWFtIG9yIHBlcnNvbmFsIGFjY291bnQpIGFuZCBwcm9qZWN0IGFuZCBhcmUgc2V0IHdpdGggdGhlIGByb290YCBmaWVsZCBpbiB0aGUgYG9wdGlvbmAgcGFyYW1ldGVyLiBTZWUgdGhlIHVuZGVybHlpbmcgW0RhdGEgQVBJXSguLi8uLi8uLi9yZXN0X2FwaXMvZGF0YV9hcGkvKSBmb3IgbW9yZSBpbmZvcm1hdGlvbi4gVGhlIGBzYXZlYCBtZXRob2QgaXMgbWFraW5nIGEgYFBPU1RgIHJlcXVlc3QuKVxuICAgICAgICAgKlxuICAgICAgICAgKiAqKkV4YW1wbGUqKlxuICAgICAgICAgKlxuICAgICAgICAgKiAgICAgIC8vIENyZWF0ZSBhIG5ldyBkb2N1bWVudCwgd2l0aCBvbmUgZWxlbWVudCwgYXQgdGhlIGRlZmF1bHQgcm9vdCBsZXZlbFxuICAgICAgICAgKiAgICAgIGRzLnNhdmUoJ3F1ZXN0aW9uMScsICd5ZXMnKTtcbiAgICAgICAgICpcbiAgICAgICAgICogICAgICAvLyBDcmVhdGUgYSBuZXcgZG9jdW1lbnQsIHdpdGggdHdvIGVsZW1lbnRzLCBhdCB0aGUgZGVmYXVsdCByb290IGxldmVsXG4gICAgICAgICAqICAgICAgZHMuc2F2ZSh7IHF1ZXN0aW9uMToneWVzJywgcXVlc3Rpb24yOiAzMiB9KTtcbiAgICAgICAgICpcbiAgICAgICAgICogICAgICAvLyBDcmVhdGUgYSBuZXcgZG9jdW1lbnQsIHdpdGggdHdvIGVsZW1lbnRzLCBhdCBgL3N0dWRlbnRzL2BcbiAgICAgICAgICogICAgICBkcy5zYXZlKHsgbmFtZTonSm9obicsIGNsYXNzTmFtZTogJ0NTMTAxJyB9LCB7IHJvb3Q6ICdzdHVkZW50cycgfSk7XG4gICAgICAgICAqXG4gICAgICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICAgICAqXG4gICAgICAgICAqIEBwYXJhbSB7U3RyaW5nfE9iamVjdH0ga2V5IElmIGBrZXlgIGlzIGEgc3RyaW5nLCBpdCBpcyB0aGUgaWQgb2YgdGhlIGVsZW1lbnQgdG8gc2F2ZSAoY3JlYXRlKSBpbiB0aGlzIGRvY3VtZW50LiBJZiBga2V5YCBpcyBhbiBvYmplY3QsIHRoZSBvYmplY3QgaXMgdGhlIGRhdGEgdG8gc2F2ZSAoY3JlYXRlKSBpbiB0aGlzIGRvY3VtZW50LiBJbiBib3RoIGNhc2VzLCB0aGUgaWQgZm9yIHRoZSBkb2N1bWVudCBpcyBnZW5lcmF0ZWQgYXV0b21hdGljYWxseS5cbiAgICAgICAgICogQHBhcmFtIHtPYmplY3R9IHZhbHVlIChPcHRpb25hbCkgVGhlIGRhdGEgdG8gc2F2ZS4gSWYgYGtleWAgaXMgYSBzdHJpbmcsIHRoaXMgaXMgdGhlIHZhbHVlIHRvIHNhdmUuIElmIGBrZXlgIGlzIGFuIG9iamVjdCwgdGhlIHZhbHVlKHMpIHRvIHNhdmUgYXJlIGFscmVhZHkgcGFydCBvZiBga2V5YCBhbmQgdGhpcyBhcmd1bWVudCBpcyBub3QgcmVxdWlyZWQuXG4gICAgICAgICAqIEBwYXJhbSB7T2JqZWN0fSBvcHRpb25zIChPcHRpb25hbCkgT3ZlcnJpZGVzIGZvciBjb25maWd1cmF0aW9uIG9wdGlvbnMuIElmIHlvdSB3YW50IHRvIG92ZXJyaWRlIHRoZSBkZWZhdWx0IGByb290YCBvZiB0aGUgY29sbGVjdGlvbiwgZG8gc28gaGVyZS5cbiAgICAgICAgICogQHJldHVybiB7UHJvbWlzZX0gXG4gICAgICAgICAqL1xuICAgICAgICBzYXZlOiBmdW5jdGlvbiAoa2V5LCB2YWx1ZSwgb3B0aW9ucykge1xuICAgICAgICAgICAgdmFyIGF0dHJzO1xuICAgICAgICAgICAgaWYgKHR5cGVvZiBrZXkgPT09ICdvYmplY3QnKSB7XG4gICAgICAgICAgICAgICAgYXR0cnMgPSBrZXk7XG4gICAgICAgICAgICAgICAgb3B0aW9ucyA9IHZhbHVlO1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICAoYXR0cnMgPSB7fSlba2V5XSA9IHZhbHVlO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgdmFyIGh0dHBPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sIHNlcnZpY2VPcHRpb25zLCBvcHRpb25zKTtcbiAgICAgICAgICAgIGh0dHBPcHRpb25zLnVybCA9IGdldFVSTCgnJywgaHR0cE9wdGlvbnMucm9vdCk7XG5cbiAgICAgICAgICAgIHJldHVybiBodHRwLnBvc3QoYXR0cnMsIGh0dHBPcHRpb25zKTtcbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgICogU2F2ZSAoY3JlYXRlIG9yIHJlcGxhY2UpIGRhdGEgaW4gYSBuYW1lZCBkb2N1bWVudCBvciBlbGVtZW50IHdpdGhpbiB0aGUgY29sbGVjdGlvbi4gXG4gICAgICAgICAqIFxuICAgICAgICAgKiBUaGUgYHJvb3RgIG9mIHRoZSBjb2xsZWN0aW9uIG11c3QgYmUgc3BlY2lmaWVkLiBCeSBkZWZhdWx0IHRoZSBgcm9vdGAgaXMgdGFrZW4gZnJvbSB0aGUgRGF0YSBTZXJ2aWNlIGNvbmZpZ3VyYXRpb24gb3B0aW9uczsgeW91IGNhbiBhbHNvIHBhc3MgdGhlIGByb290YCB0byB0aGUgYHNhdmVBc2AgY2FsbCBleHBsaWNpdGx5IGJ5IG92ZXJyaWRpbmcgdGhlIG9wdGlvbnMgKHRoaXJkIHBhcmFtZXRlcikuXG4gICAgICAgICAqXG4gICAgICAgICAqIE9wdGlvbmFsbHksIHRoZSBuYW1lZCBkb2N1bWVudCBvciBlbGVtZW50IGNhbiBpbmNsdWRlIHBhdGggaW5mb3JtYXRpb24sIHNvIHRoYXQgeW91IGFyZSBzYXZpbmcganVzdCBwYXJ0IG9mIHRoZSBkb2N1bWVudC5cbiAgICAgICAgICpcbiAgICAgICAgICogKEFkZGl0aW9uYWwgYmFja2dyb3VuZDogRG9jdW1lbnRzIGFyZSB0b3AtbGV2ZWwgZWxlbWVudHMgd2l0aGluIGEgY29sbGVjdGlvbi4gQ29sbGVjdGlvbnMgbXVzdCBiZSB1bmlxdWUgd2l0aGluIHRoaXMgYWNjb3VudCAodGVhbSBvciBwZXJzb25hbCBhY2NvdW50KSBhbmQgcHJvamVjdCBhbmQgYXJlIHNldCB3aXRoIHRoZSBgcm9vdGAgZmllbGQgaW4gdGhlIGBvcHRpb25gIHBhcmFtZXRlci4gU2VlIHRoZSB1bmRlcmx5aW5nIFtEYXRhIEFQSV0oLi4vLi4vLi4vcmVzdF9hcGlzL2RhdGFfYXBpLykgZm9yIG1vcmUgaW5mb3JtYXRpb24uIFRoZSBgc2F2ZUFzYCBtZXRob2QgaXMgbWFraW5nIGEgYFBVVGAgcmVxdWVzdC4pXG4gICAgICAgICAqXG4gICAgICAgICAqICoqRXhhbXBsZSoqXG4gICAgICAgICAqXG4gICAgICAgICAqICAgICAgLy8gQ3JlYXRlIChvciByZXBsYWNlKSB0aGUgYHVzZXIxYCBkb2N1bWVudCBhdCB0aGUgZGVmYXVsdCByb290IGxldmVsLlxuICAgICAgICAgKiAgICAgIC8vIE5vdGUgdGhhdCB0aGlzIHJlcGxhY2VzIGFueSBleGlzdGluZyBjb250ZW50IGluIHRoZSBgdXNlcjFgIGRvY3VtZW50LlxuICAgICAgICAgKiAgICAgIGRzLnNhdmVBcygndXNlcjEnLFxuICAgICAgICAgKiAgICAgICAgICB7ICdxdWVzdGlvbjEnOiAyLCAncXVlc3Rpb24yJzogMTAsXG4gICAgICAgICAqICAgICAgICAgICAncXVlc3Rpb24zJzogZmFsc2UsICdxdWVzdGlvbjQnOiAnc29tZXRpbWVzJyB9ICk7XG4gICAgICAgICAqXG4gICAgICAgICAqICAgICAgLy8gQ3JlYXRlIChvciByZXBsYWNlKSB0aGUgYHN0dWRlbnQxYCBkb2N1bWVudCBhdCB0aGUgYHN0dWRlbnRzYCByb290LCBcbiAgICAgICAgICogICAgICAvLyB0aGF0IGlzLCB0aGUgZGF0YSBhdCBgL3N0dWRlbnRzL3N0dWRlbnQxL2AuXG4gICAgICAgICAqICAgICAgLy8gTm90ZSB0aGF0IHRoaXMgcmVwbGFjZXMgYW55IGV4aXN0aW5nIGNvbnRlbnQgaW4gdGhlIGAvc3R1ZGVudHMvc3R1ZGVudDEvYCBkb2N1bWVudC5cbiAgICAgICAgICogICAgICAvLyBIb3dldmVyLCB0aGlzIHdpbGwga2VlcCBleGlzdGluZyBjb250ZW50IGluIG90aGVyIHBhdGhzIG9mIHRoaXMgY29sbGVjdGlvbi5cbiAgICAgICAgICogICAgICAvLyBGb3IgZXhhbXBsZSwgdGhlIGRhdGEgYXQgYC9zdHVkZW50cy9zdHVkZW50Mi9gIGlzIHVuY2hhbmdlZCBieSB0aGlzIGNhbGwuXG4gICAgICAgICAqICAgICAgZHMuc2F2ZUFzKCdzdHVkZW50MScsXG4gICAgICAgICAqICAgICAgICAgIHsgZmlyc3ROYW1lOiAnam9obicsIGxhc3ROYW1lOiAnc21pdGgnIH0sXG4gICAgICAgICAqICAgICAgICAgIHsgcm9vdDogJ3N0dWRlbnRzJyB9KTtcbiAgICAgICAgICpcbiAgICAgICAgICogICAgICAvLyBDcmVhdGUgKG9yIHJlcGxhY2UpIHRoZSBgbWdtdDEwMC9ncm91cEJgIGRvY3VtZW50IGF0IHRoZSBgbXljbGFzc2VzYCByb290LFxuICAgICAgICAgKiAgICAgIC8vIHRoYXQgaXMsIHRoZSBkYXRhIGF0IGAvbXljbGFzc2VzL21nbXQxMDAvZ3JvdXBCL2AuXG4gICAgICAgICAqICAgICAgLy8gTm90ZSB0aGF0IHRoaXMgcmVwbGFjZXMgYW55IGV4aXN0aW5nIGNvbnRlbnQgaW4gdGhlIGAvbXljbGFzc2VzL21nbXQxMDAvZ3JvdXBCL2AgZG9jdW1lbnQuXG4gICAgICAgICAqICAgICAgLy8gSG93ZXZlciwgdGhpcyB3aWxsIGtlZXAgZXhpc3RpbmcgY29udGVudCBpbiBvdGhlciBwYXRocyBvZiB0aGlzIGNvbGxlY3Rpb24uXG4gICAgICAgICAqICAgICAgLy8gRm9yIGV4YW1wbGUsIHRoZSBkYXRhIGF0IGAvbXljbGFzc2VzL21nbXQxMDAvZ3JvdXBBL2AgaXMgdW5jaGFuZ2VkIGJ5IHRoaXMgY2FsbC5cbiAgICAgICAgICogICAgICBkcy5zYXZlQXMoJ21nbXQxMDAvZ3JvdXBCJyxcbiAgICAgICAgICogICAgICAgICAgeyBzY2VuYXJpb1llYXI6ICcyMDE1JyB9LFxuICAgICAgICAgKiAgICAgICAgICB7IHJvb3Q6ICdteWNsYXNzZXMnIH0pO1xuICAgICAgICAgKlxuICAgICAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAgKlxuICAgICAgICAgKiBAcGFyYW0ge1N0cmluZ30ga2V5IElkIG9mIHRoZSBkb2N1bWVudC5cbiAgICAgICAgICogQHBhcmFtIHtPYmplY3R9IHZhbHVlIChPcHRpb25hbCkgVGhlIGRhdGEgdG8gc2F2ZSwgaW4ga2V5OnZhbHVlIHBhaXJzLlxuICAgICAgICAgKiBAcGFyYW0ge09iamVjdH0gb3B0aW9ucyAoT3B0aW9uYWwpIE92ZXJyaWRlcyBmb3IgY29uZmlndXJhdGlvbiBvcHRpb25zLiBJZiB5b3Ugd2FudCB0byBvdmVycmlkZSB0aGUgZGVmYXVsdCBgcm9vdGAgb2YgdGhlIGNvbGxlY3Rpb24sIGRvIHNvIGhlcmUuXG4gICAgICAgICAqIEByZXR1cm4ge1Byb21pc2V9IFxuICAgICAgICAgKi9cbiAgICAgICAgc2F2ZUFzOiBmdW5jdGlvbiAoa2V5LCB2YWx1ZSwgb3B0aW9ucykge1xuICAgICAgICAgICAgdmFyIGh0dHBPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sIHNlcnZpY2VPcHRpb25zLCBvcHRpb25zKTtcbiAgICAgICAgICAgIGh0dHBPcHRpb25zLnVybCA9IGdldFVSTChrZXksIGh0dHBPcHRpb25zLnJvb3QpO1xuXG4gICAgICAgICAgICByZXR1cm4gaHR0cC5wdXQodmFsdWUsIGh0dHBPcHRpb25zKTtcbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgICogR2V0IGRhdGEgZm9yIGEgc3BlY2lmaWMgZG9jdW1lbnQgb3IgZmllbGQuXG4gICAgICAgICAqXG4gICAgICAgICAqICoqRXhhbXBsZSoqXG4gICAgICAgICAqXG4gICAgICAgICAqICAgICAgZHMubG9hZCgndXNlcjEnKTtcbiAgICAgICAgICogICAgICBkcy5sb2FkKCd1c2VyMS9xdWVzdGlvbjMnKTtcbiAgICAgICAgICpcbiAgICAgICAgICogKipQYXJhbWV0ZXJzKipcbiAgICAgICAgICogQHBhcmFtICB7U3RyaW5nfE9iamVjdH0ga2V5IFRoZSBpZCBvZiB0aGUgZGF0YSB0byByZXR1cm4uIENhbiBiZSB0aGUgaWQgb2YgYSBkb2N1bWVudCwgb3IgYSBwYXRoIHRvIGRhdGEgd2l0aGluIHRoYXQgZG9jdW1lbnQuXG4gICAgICAgICAqIEBwYXJhbSB7T2JqZWN0fSBvdXRwdXRNb2RpZmllciAoT3B0aW9uYWwpIEF2YWlsYWJsZSBmaWVsZHMgaW5jbHVkZTogYHN0YXJ0cmVjb3JkYCwgYGVuZHJlY29yZGAsIGBzb3J0YCwgYW5kIGBkaXJlY3Rpb25gIChgYXNjYCBvciBgZGVzY2ApLlxuICAgICAgICAgKiBAcGFyYW0ge09iamVjdH0gb3B0aW9ucyBPdmVycmlkZXMgZm9yIGNvbmZpZ3VyYXRpb24gb3B0aW9ucy5cbiAgICAgICAgICogQHJldHVybiB7UHJvbWlzZX0gXG4gICAgICAgICAqL1xuICAgICAgICBsb2FkOiBmdW5jdGlvbiAoa2V5LCBvdXRwdXRNb2RpZmllciwgb3B0aW9ucykge1xuICAgICAgICAgICAgdmFyIGh0dHBPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sIHNlcnZpY2VPcHRpb25zLCBvcHRpb25zKTtcbiAgICAgICAgICAgIGh0dHBPcHRpb25zLnVybCA9IGdldFVSTChrZXksIGh0dHBPcHRpb25zLnJvb3QpO1xuICAgICAgICAgICAgcmV0dXJuIGh0dHAuZ2V0KG91dHB1dE1vZGlmaWVyLCBodHRwT3B0aW9ucyk7XG4gICAgICAgIH0sXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIFJlbW92ZXMgZGF0YSBmcm9tIGNvbGxlY3Rpb24uIE9ubHkgZG9jdW1lbnRzICh0b3AtbGV2ZWwgZWxlbWVudHMgaW4gZWFjaCBjb2xsZWN0aW9uKSBjYW4gYmUgZGVsZXRlZC5cbiAgICAgICAgICpcbiAgICAgICAgICogKipFeGFtcGxlKipcbiAgICAgICAgICpcbiAgICAgICAgICogICAgIGRzLnJlbW92ZSgndXNlcjEnKTtcbiAgICAgICAgICpcbiAgICAgICAgICpcbiAgICAgICAgICogKipQYXJhbWV0ZXJzKipcbiAgICAgICAgICpcbiAgICAgICAgICogQHBhcmFtIHtTdHJpbmd8QXJyYXl9IGtleXMgVGhlIGlkIG9mIHRoZSBkb2N1bWVudCB0byByZW1vdmUgZnJvbSB0aGlzIGNvbGxlY3Rpb24sIG9yIGFuIGFycmF5IG9mIHN1Y2ggaWRzLlxuICAgICAgICAgKiBAcGFyYW0ge09iamVjdH0gb3B0aW9ucyAoT3B0aW9uYWwpIE92ZXJyaWRlcyBmb3IgY29uZmlndXJhdGlvbiBvcHRpb25zLlxuICAgICAgICAgKiBAcmV0dXJuIHtQcm9taXNlfSBcbiAgICAgICAgICovXG4gICAgICAgIHJlbW92ZTogZnVuY3Rpb24gKGtleXMsIG9wdGlvbnMpIHtcbiAgICAgICAgICAgIHZhciBodHRwT3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LCBzZXJ2aWNlT3B0aW9ucywgb3B0aW9ucyk7XG4gICAgICAgICAgICB2YXIgcGFyYW1zO1xuICAgICAgICAgICAgaWYgKCQuaXNBcnJheShrZXlzKSkge1xuICAgICAgICAgICAgICAgIHBhcmFtcyA9IHsgaWQ6IGtleXMgfTtcbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgcGFyYW1zID0gJyc7XG4gICAgICAgICAgICAgICAgaHR0cE9wdGlvbnMudXJsID0gZ2V0VVJMKGtleXMsIGh0dHBPcHRpb25zLnJvb3QpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgcmV0dXJuIGh0dHAuZGVsZXRlKHBhcmFtcywgaHR0cE9wdGlvbnMpO1xuICAgICAgICB9XG5cbiAgICAgICAgLy8gRXBpY2VudGVyIGRvZXNuJ3QgYWxsb3cgbnVraW5nIGNvbGxlY3Rpb25zXG4gICAgICAgIC8vICAgICAvKipcbiAgICAgICAgLy8gICAgICAqIFJlbW92ZXMgY29sbGVjdGlvbiBiZWluZyByZWZlcmVuY2VkXG4gICAgICAgIC8vICAgICAgKiBAcmV0dXJuIG51bGxcbiAgICAgICAgLy8gICAgICAqL1xuICAgICAgICAvLyAgICAgZGVzdHJveTogZnVuY3Rpb24gKG9wdGlvbnMpIHtcbiAgICAgICAgLy8gICAgICAgICByZXR1cm4gdGhpcy5yZW1vdmUoJycsIG9wdGlvbnMpO1xuICAgICAgICAvLyAgICAgfVxuICAgIH07XG5cbiAgICAkLmV4dGVuZCh0aGlzLCBwdWJsaWNBUEkpO1xufTtcbiIsIi8qKlxuICpcbiAqICMjIEdyb3VwIEFQSSBBZGFwdGVyXG4gKlxuICogVGhlIEdyb3VwIEFQSSBBZGFwdGVyIHByb3ZpZGVzIG1ldGhvZHMgdG8gbG9vayB1cCwgY3JlYXRlLCBjaGFuZ2Ugb3IgcmVtb3ZlIGluZm9ybWF0aW9uIGFib3V0IGdyb3VwcyBpbiBhIHByb2plY3QuIEl0IGlzIGJhc2VkIG9uIHF1ZXJ5IGNhcGFiaWxpdGllcyBvZiB0aGUgdW5kZXJseWluZyBSRVNUZnVsIFtHcm91cCBBUEldKC4uLy4uLy4uL3Jlc3RfYXBpcy91c2VyX21hbmFnZW1lbnQvZ3JvdXAvKS5cbiAqXG4gKiBUaGlzIGlzIG9ubHkgbmVlZGVkIGZvciBBdXRoZW50aWNhdGVkIHByb2plY3RzLCB0aGF0IGlzLCB0ZWFtIHByb2plY3RzIHdpdGggW2VuZCB1c2VycyBhbmQgZ3JvdXBzXSguLi8uLi8uLi9ncm91cHNfYW5kX2VuZF91c2Vycy8pLlxuICpcbiAqICAgICAgdmFyIG1hID0gbmV3IEYuc2VydmljZS5Hcm91cCh7IHRva2VuOiAndXNlci1vci1wcm9qZWN0LWFjY2Vzcy10b2tlbicgfSk7XG4gKiAgICAgIG1hLmdldEdyb3Vwc0ZvclByb2plY3QoeyBhY2NvdW50OiAnYWNtZScsIHByb2plY3Q6ICdzYW1wbGUnIH0pO1xuICovXG5cbid1c2Ugc3RyaWN0JztcblxudmFyIHNlcnZpY2VVdGlscyA9IHJlcXVpcmUoJy4vc2VydmljZS11dGlscycpO1xudmFyIFRyYW5zcG9ydEZhY3RvcnkgPSByZXF1aXJlKCcuLi90cmFuc3BvcnQvaHR0cC10cmFuc3BvcnQtZmFjdG9yeScpO1xudmFyIG9iamVjdEFzc2lnbiA9IHJlcXVpcmUoJ29iamVjdC1hc3NpZ24nKTtcblxudmFyIGFwaUVuZHBvaW50ID0gJ2dyb3VwL2xvY2FsJztcblxudmFyIEdyb3VwU2VydmljZSA9IGZ1bmN0aW9uIChjb25maWcpIHtcbiAgICB2YXIgZGVmYXVsdHMgPSB7XG4gICAgICAgIC8qKlxuICAgICAgICAgKiBFcGljZW50ZXIgYWNjb3VudCBuYW1lLiBEZWZhdWx0cyB0byB1bmRlZmluZWQuXG4gICAgICAgICAqIEB0eXBlIHtzdHJpbmd9XG4gICAgICAgICAqL1xuICAgICAgICBhY2NvdW50OiB1bmRlZmluZWQsXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIEVwaWNlbnRlciBwcm9qZWN0IG5hbWUuIERlZmF1bHRzIHRvIHVuZGVmaW5lZC5cbiAgICAgICAgICogQHR5cGUge3N0cmluZ31cbiAgICAgICAgICovXG4gICAgICAgIHByb2plY3Q6IHVuZGVmaW5lZCxcblxuICAgICAgICAvKipcbiAgICAgICAgICogT3B0aW9ucyB0byBwYXNzIG9uIHRvIHRoZSB1bmRlcmx5aW5nIHRyYW5zcG9ydCBsYXllci4gQWxsIGpxdWVyeS5hamF4IG9wdGlvbnMgYXQgaHR0cDovL2FwaS5qcXVlcnkuY29tL2pRdWVyeS5hamF4LyBhcmUgYXZhaWxhYmxlLiBEZWZhdWx0cyB0byBlbXB0eSBvYmplY3QuXG4gICAgICAgICAqIEB0eXBlIHtvYmplY3R9XG4gICAgICAgICAqL1xuICAgICAgICB0cmFuc3BvcnQ6IHt9XG4gICAgfTtcbiAgICB2YXIgc2VydmljZU9wdGlvbnMgPSBzZXJ2aWNlVXRpbHMuZ2V0RGVmYXVsdE9wdGlvbnMoZGVmYXVsdHMsIGNvbmZpZywgeyBhcGlFbmRwb2ludDogYXBpRW5kcG9pbnQgfSk7XG4gICAgdmFyIHRyYW5zcG9ydE9wdGlvbnMgPSBzZXJ2aWNlT3B0aW9ucy50cmFuc3BvcnQ7XG4gICAgZGVsZXRlIHNlcnZpY2VPcHRpb25zLnRyYW5zcG9ydDtcbiAgICB2YXIgaHR0cCA9IG5ldyBUcmFuc3BvcnRGYWN0b3J5KHRyYW5zcG9ydE9wdGlvbnMsIHNlcnZpY2VPcHRpb25zKTtcbiAgICB2YXIgcHVibGljQVBJID0ge1xuICAgICAgICAvKipcbiAgICAgICAgKiBHZXRzIGluZm9ybWF0aW9uIGZvciBhIGdyb3VwIG9yIG11bHRpcGxlIGdyb3Vwcy5cbiAgICAgICAgKiBAcGFyYW0ge09iamVjdH0gcGFyYW1zIG9iamVjdCB3aXRoIHF1ZXJ5IHBhcmFtZXRlcnNcbiAgICAgICAgKiBAcGF0YW0ge3N0cmluZ30gcGFyYW1zLnEgcGFydGlhbCBtYXRjaCBmb3IgbmFtZSwgb3JnYW5pemF0aW9uIG9yIGV2ZW50LlxuICAgICAgICAqIEBwYXRhbSB7c3RyaW5nfSBwYXJhbXMuYWNjb3VudCBFcGljZW50ZXIncyBUZWFtIElEXG4gICAgICAgICogQHBhdGFtIHtzdHJpbmd9IHBhcmFtcy5wcm9qZWN0IEVwaWNlbnRlcidzIFByb2plY3QgSURcbiAgICAgICAgKiBAcGF0YW0ge3N0cmluZ30gcGFyYW1zLm5hbWUgRXBpY2VudGVyJ3MgR3JvdXAgTmFtZVxuICAgICAgICAqIEBwYXJhbSB7T2JqZWN0fSBvcHRpb25zIChPcHRpb25hbCkgT3ZlcnJpZGVzIGZvciBjb25maWd1cmF0aW9uIG9wdGlvbnMuXG4gICAgICAgICogQHJldHVybiB7UHJvbWlzZX1cbiAgICAgICAgKi9cbiAgICAgICAgZ2V0R3JvdXBzOiBmdW5jdGlvbiAocGFyYW1zLCBvcHRpb25zKSB7XG4gICAgICAgICAgICAvL2dyb3VwSUQgaXMgcGFydCBvZiB0aGUgVVJMXG4gICAgICAgICAgICAvL3EsIGFjY291bnQgYW5kIHByb2plY3QgYXJlIHBhcnQgb2YgdGhlIHF1ZXJ5IHN0cmluZ1xuICAgICAgICAgICAgdmFyIGZpbmFsT3B0cyA9IG9iamVjdEFzc2lnbih7fSwgc2VydmljZU9wdGlvbnMsIG9wdGlvbnMpO1xuICAgICAgICAgICAgdmFyIGZpbmFsUGFyYW1zO1xuICAgICAgICAgICAgaWYgKHR5cGVvZiBwYXJhbXMgPT09ICdzdHJpbmcnKSB7XG4gICAgICAgICAgICAgICAgZmluYWxPcHRzLnVybCA9IHNlcnZpY2VVdGlscy5nZXRBcGlVcmwoYXBpRW5kcG9pbnQgKyAnLycgKyBwYXJhbXMsIGZpbmFsT3B0cyk7XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgIGZpbmFsUGFyYW1zID0gcGFyYW1zO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgcmV0dXJuIGh0dHAuZ2V0KGZpbmFsUGFyYW1zLCBmaW5hbE9wdHMpO1xuICAgICAgICB9XG4gICAgfTtcbiAgICBvYmplY3RBc3NpZ24odGhpcywgcHVibGljQVBJKTtcbn07XG5cbm1vZHVsZS5leHBvcnRzID0gR3JvdXBTZXJ2aWNlO1xuIiwiLyoqXG4gKlxuICogIyMgSW50cm9zcGVjdGlvbiBBUEkgU2VydmljZVxuICpcbiAqIFRoZSBJbnRyb3NwZWN0aW9uIEFQSSBTZXJ2aWNlIGFsbG93cyB5b3UgdG8gdmlldyBhIGxpc3Qgb2YgdGhlIHZhcmlhYmxlcyBhbmQgb3BlcmF0aW9ucyBpbiBhIG1vZGVsLiBUeXBpY2FsbHkgdXNlZCBpbiBjb25qdW5jdGlvbiB3aXRoIHRoZSBbUnVuIEFQSSBTZXJ2aWNlXSguLi9ydW4tYXBpLXNlcnZpY2UvKS5cbiAqXG4gKiBUaGUgSW50cm9zcGVjdGlvbiBBUEkgU2VydmljZSBpcyBub3QgYXZhaWxhYmxlIGZvciBGb3JpbyBTaW1MYW5nLlxuICpcbiAqICAgICAgIHZhciBpbnRybyA9IG5ldyBGLnNlcnZpY2UuSW50cm9zcGVjdCh7XG4gKiAgICAgICAgICAgICAgIGFjY291bnQ6ICdhY21lLXNpbXVsYXRpb25zJyxcbiAqICAgICAgICAgICAgICAgcHJvamVjdDogJ3N1cHBseS1jaGFpbi1nYW1lJ1xuICogICAgICAgfSk7XG4gKiAgICAgICBpbnRyby5ieU1vZGVsKCdzdXBwbHktY2hhaW4ucHknKS50aGVuKGZ1bmN0aW9uKGRhdGEpeyAuLi4gfSk7XG4gKiAgICAgICBpbnRyby5ieVJ1bklEKCcyYjRkOGY3MS01YzM0LTQzNWEtOGMxNi05ZGU2NzRhYjcyZTYnKS50aGVuKGZ1bmN0aW9uKGRhdGEpeyAuLi4gfSk7XG4gKlxuICovXG5cbid1c2Ugc3RyaWN0JztcblxudmFyIENvbmZpZ1NlcnZpY2UgPSByZXF1aXJlKCcuL2NvbmZpZ3VyYXRpb24tc2VydmljZScpO1xudmFyIFRyYW5zcG9ydEZhY3RvcnkgPSByZXF1aXJlKCcuLi90cmFuc3BvcnQvaHR0cC10cmFuc3BvcnQtZmFjdG9yeScpO1xudmFyIFNlc3Npb25NYW5hZ2VyID0gcmVxdWlyZSgnLi4vc3RvcmUvc2Vzc2lvbi1tYW5hZ2VyJyk7XG5cbnZhciBhcGlFbmRwb2ludCA9ICdtb2RlbC9pbnRyb3NwZWN0JztcblxubW9kdWxlLmV4cG9ydHMgPSBmdW5jdGlvbiAoY29uZmlnKSB7XG4gICAgdmFyIGRlZmF1bHRzID0ge1xuICAgICAgICAvKipcbiAgICAgICAgICogRm9yIHByb2plY3RzIHRoYXQgcmVxdWlyZSBhdXRoZW50aWNhdGlvbiwgcGFzcyBpbiB0aGUgdXNlciBhY2Nlc3MgdG9rZW4gKGRlZmF1bHRzIHRvIGVtcHR5IHN0cmluZykuIElmIHRoZSB1c2VyIGlzIGFscmVhZHkgbG9nZ2VkIGluIHRvIEVwaWNlbnRlciwgdGhlIHVzZXIgYWNjZXNzIHRva2VuIGlzIGFscmVhZHkgc2V0IGluIGEgY29va2llIGFuZCBhdXRvbWF0aWNhbGx5IGxvYWRlZCBmcm9tIHRoZXJlLiAoU2VlIFttb3JlIGJhY2tncm91bmQgb24gYWNjZXNzIHRva2Vuc10oLi4vLi4vLi4vcHJvamVjdF9hY2Nlc3MvKSkuXG4gICAgICAgICAqIEBzZWUgW0F1dGhlbnRpY2F0aW9uIEFQSSBTZXJ2aWNlXSguLi9hdXRoLWFwaS1zZXJ2aWNlLykgZm9yIGdldHRpbmcgdG9rZW5zLlxuICAgICAgICAgKiBAdHlwZSB7U3RyaW5nfVxuICAgICAgICAgKi9cbiAgICAgICAgdG9rZW46IHVuZGVmaW5lZCxcblxuICAgICAgICAvKipcbiAgICAgICAgICogVGhlIGFjY291bnQgaWQuIEluIHRoZSBFcGljZW50ZXIgVUksIHRoaXMgaXMgdGhlICoqVGVhbSBJRCoqIChmb3IgdGVhbSBwcm9qZWN0cykgb3IgKipVc2VyIElEKiogKGZvciBwZXJzb25hbCBwcm9qZWN0cykuIERlZmF1bHRzIHRvIGVtcHR5IHN0cmluZy4gSWYgbGVmdCB1bmRlZmluZWQsIHRha2VuIGZyb20gdGhlIFVSTC5cbiAgICAgICAgICogQHR5cGUge1N0cmluZ31cbiAgICAgICAgICovXG4gICAgICAgIGFjY291bnQ6IHVuZGVmaW5lZCxcblxuICAgICAgICAvKipcbiAgICAgICAgICogVGhlIHByb2plY3QgaWQuIERlZmF1bHRzIHRvIGVtcHR5IHN0cmluZy4gSWYgbGVmdCB1bmRlZmluZWQsIHRha2VuIGZyb20gdGhlIFVSTC5cbiAgICAgICAgICogQHR5cGUge1N0cmluZ31cbiAgICAgICAgICovXG4gICAgICAgIHByb2plY3Q6IHVuZGVmaW5lZCxcblxuICAgIH07XG5cbiAgICB2YXIgc2Vzc2lvbk1hbmFnZXIgPSBuZXcgU2Vzc2lvbk1hbmFnZXIoKTtcbiAgICB2YXIgc2VydmljZU9wdGlvbnMgPSBzZXNzaW9uTWFuYWdlci5nZXRNZXJnZWRPcHRpb25zKGRlZmF1bHRzLCBjb25maWcpO1xuXG4gICAgdmFyIHVybENvbmZpZyA9IG5ldyBDb25maWdTZXJ2aWNlKHNlcnZpY2VPcHRpb25zKS5nZXQoJ3NlcnZlcicpO1xuICAgIGlmIChzZXJ2aWNlT3B0aW9ucy5hY2NvdW50KSB7XG4gICAgICAgIHVybENvbmZpZy5hY2NvdW50UGF0aCA9IHNlcnZpY2VPcHRpb25zLmFjY291bnQ7XG4gICAgfVxuICAgIGlmIChzZXJ2aWNlT3B0aW9ucy5wcm9qZWN0KSB7XG4gICAgICAgIHVybENvbmZpZy5wcm9qZWN0UGF0aCA9IHNlcnZpY2VPcHRpb25zLnByb2plY3Q7XG4gICAgfVxuXG4gICAgdmFyIHRyYW5zcG9ydE9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSwgc2VydmljZU9wdGlvbnMudHJhbnNwb3J0LCB7XG4gICAgICAgIHVybDogdXJsQ29uZmlnLmdldEFQSVBhdGgoYXBpRW5kcG9pbnQpXG4gICAgfSk7XG4gICAgaWYgKHNlcnZpY2VPcHRpb25zLnRva2VuKSB7XG4gICAgICAgIHRyYW5zcG9ydE9wdGlvbnMuaGVhZGVycyA9IHtcbiAgICAgICAgICAgIEF1dGhvcml6YXRpb246ICdCZWFyZXIgJyArIHNlcnZpY2VPcHRpb25zLnRva2VuXG4gICAgICAgIH07XG4gICAgfVxuICAgIHZhciBodHRwID0gbmV3IFRyYW5zcG9ydEZhY3RvcnkodHJhbnNwb3J0T3B0aW9ucyk7XG5cbiAgICB2YXIgcHVibGljQVBJID0ge1xuICAgICAgICAvKipcbiAgICAgICAgICogR2V0IHRoZSBhdmFpbGFibGUgdmFyaWFibGVzIGFuZCBvcGVyYXRpb25zIGZvciBhIGdpdmVuIG1vZGVsIGZpbGUuXG4gICAgICAgICAqXG4gICAgICAgICAqIE5vdGU6IFRoaXMgZG9lcyBub3Qgd29yayBmb3IgYW55IG1vZGVsIHdoaWNoIHJlcXVpcmVzIGFkZGl0aW9uYWwgcGFyYW1ldGVycywgc3VjaCBhcyBgZmlsZXNgLlxuICAgICAgICAgKlxuICAgICAgICAgKiAqKkV4YW1wbGUqKlxuICAgICAgICAgKlxuICAgICAgICAgKiAgICAgIGludHJvLmJ5TW9kZWwoJ2FiYy52bWYnKVxuICAgICAgICAgKiAgICAgICAgICAudGhlbihmdW5jdGlvbihkYXRhKSB7XG4gICAgICAgICAqICAgICAgICAgICAgICAvLyBkYXRhIGNvbnRhaW5zIGFuIG9iamVjdCB3aXRoIGF2YWlsYWJsZSBmdW5jdGlvbnMgKHVzZWQgd2l0aCBvcGVyYXRpb25zIEFQSSkgYW5kIGF2YWlsYWJsZSB2YXJpYWJsZXMgKHVzZWQgd2l0aCB2YXJpYWJsZXMgQVBJKVxuICAgICAgICAgKiAgICAgICAgICAgICAgY29uc29sZS5sb2coZGF0YS5mdW5jdGlvbnMpO1xuICAgICAgICAgKiAgICAgICAgICAgICAgY29uc29sZS5sb2coZGF0YS52YXJpYWJsZXMpO1xuICAgICAgICAgKiAgICAgICAgICB9KTtcbiAgICAgICAgICpcbiAgICAgICAgICogKipQYXJhbWV0ZXJzKipcbiAgICAgICAgICogQHBhcmFtICB7U3RyaW5nfSBtb2RlbEZpbGUgTmFtZSBvZiB0aGUgbW9kZWwgZmlsZSB0byBpbnRyb3NwZWN0LlxuICAgICAgICAgKiBAcGFyYW0gIHtPYmplY3R9IG9wdGlvbnMgKE9wdGlvbmFsKSBPdmVycmlkZXMgZm9yIGNvbmZpZ3VyYXRpb24gb3B0aW9ucy5cbiAgICAgICAgICogQHJldHVybiB7UHJvbWlzZX0gXG4gICAgICAgICAqL1xuICAgICAgICBieU1vZGVsOiBmdW5jdGlvbiAobW9kZWxGaWxlLCBvcHRpb25zKSB7XG4gICAgICAgICAgICB2YXIgb3B0cyA9ICQuZXh0ZW5kKHRydWUsIHt9LCBzZXJ2aWNlT3B0aW9ucywgb3B0aW9ucyk7XG4gICAgICAgICAgICBpZiAoIW9wdHMuYWNjb3VudCB8fCAhb3B0cy5wcm9qZWN0KSB7XG4gICAgICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdBY2NvdW50IGFuZCBwcm9qZWN0IGFyZSByZXF1aXJlZCB3aGVuIHVzaW5nIGludHJvc3BlY3QjYnlNb2RlbCcpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgaWYgKCFtb2RlbEZpbGUpIHtcbiAgICAgICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ21vZGVsRmlsZSBpcyByZXF1aXJlZCB3aGVuIHVzaW5nIGludHJvc3BlY3QjYnlNb2RlbCcpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgdmFyIHVybCA9IHsgdXJsOiB1cmxDb25maWcuZ2V0QVBJUGF0aChhcGlFbmRwb2ludCkgKyBbb3B0cy5hY2NvdW50LCBvcHRzLnByb2plY3QsIG1vZGVsRmlsZV0uam9pbignLycpIH07XG4gICAgICAgICAgICB2YXIgaHR0cE9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSwgc2VydmljZU9wdGlvbnMsIG9wdGlvbnMsIHVybCk7XG4gICAgICAgICAgICByZXR1cm4gaHR0cC5nZXQoJycsIGh0dHBPcHRpb25zKTtcbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgICogR2V0IHRoZSBhdmFpbGFibGUgdmFyaWFibGVzIGFuZCBvcGVyYXRpb25zIGZvciBhIGdpdmVuIG1vZGVsIGZpbGUuXG4gICAgICAgICAqXG4gICAgICAgICAqIE5vdGU6IFRoaXMgZG9lcyBub3Qgd29yayBmb3IgYW55IG1vZGVsIHdoaWNoIHJlcXVpcmVzIGFkZGl0aW9uYWwgcGFyYW1ldGVycyBzdWNoIGFzIGBmaWxlc2AuXG4gICAgICAgICAqXG4gICAgICAgICAqICoqRXhhbXBsZSoqXG4gICAgICAgICAqXG4gICAgICAgICAqICAgICAgaW50cm8uYnlSdW5JRCgnMmI0ZDhmNzEtNWMzNC00MzVhLThjMTYtOWRlNjc0YWI3MmU2JylcbiAgICAgICAgICogICAgICAgICAgLnRoZW4oZnVuY3Rpb24oZGF0YSkge1xuICAgICAgICAgKiAgICAgICAgICAgICAgLy8gZGF0YSBjb250YWlucyBhbiBvYmplY3Qgd2l0aCBhdmFpbGFibGUgZnVuY3Rpb25zICh1c2VkIHdpdGggb3BlcmF0aW9ucyBBUEkpIGFuZCBhdmFpbGFibGUgdmFyaWFibGVzICh1c2VkIHdpdGggdmFyaWFibGVzIEFQSSlcbiAgICAgICAgICogICAgICAgICAgICAgIGNvbnNvbGUubG9nKGRhdGEuZnVuY3Rpb25zKTtcbiAgICAgICAgICogICAgICAgICAgICAgIGNvbnNvbGUubG9nKGRhdGEudmFyaWFibGVzKTtcbiAgICAgICAgICogICAgICAgICAgfSk7XG4gICAgICAgICAqXG4gICAgICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICAgICAqIEBwYXJhbSAge1N0cmluZ30gcnVuSUQgSWQgb2YgdGhlIHJ1biB0byBpbnRyb3NwZWN0LlxuICAgICAgICAgKiBAcGFyYW0gIHtPYmplY3R9IG9wdGlvbnMgKE9wdGlvbmFsKSBPdmVycmlkZXMgZm9yIGNvbmZpZ3VyYXRpb24gb3B0aW9ucy5cbiAgICAgICAgICogQHJldHVybiB7UHJvbWlzZX0gXG4gICAgICAgICAqL1xuICAgICAgICBieVJ1bklEOiBmdW5jdGlvbiAocnVuSUQsIG9wdGlvbnMpIHtcbiAgICAgICAgICAgIGlmICghcnVuSUQpIHtcbiAgICAgICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ3J1bklEIGlzIHJlcXVpcmVkIHdoZW4gdXNpbmcgaW50cm9zcGVjdCNieU1vZGVsJyk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICB2YXIgdXJsID0geyB1cmw6IHVybENvbmZpZy5nZXRBUElQYXRoKGFwaUVuZHBvaW50KSArIHJ1bklEIH07XG4gICAgICAgICAgICB2YXIgaHR0cE9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSwgc2VydmljZU9wdGlvbnMsIG9wdGlvbnMsIHVybCk7XG4gICAgICAgICAgICByZXR1cm4gaHR0cC5nZXQoJycsIGh0dHBPcHRpb25zKTtcbiAgICAgICAgfVxuICAgIH07XG4gICAgJC5leHRlbmQodGhpcywgcHVibGljQVBJKTtcbn07XG4iLCIvKipcbiAqXG4gKiAjIyBNZW1iZXIgQVBJIEFkYXB0ZXJcbiAqXG4gKiBUaGUgTWVtYmVyIEFQSSBBZGFwdGVyIHByb3ZpZGVzIG1ldGhvZHMgdG8gbG9vayB1cCBpbmZvcm1hdGlvbiBhYm91dCBlbmQgdXNlcnMgZm9yIHlvdXIgcHJvamVjdCBhbmQgaG93IHRoZXkgYXJlIGRpdmlkZWQgYWNyb3NzIGdyb3Vwcy4gSXQgaXMgYmFzZWQgb24gcXVlcnkgY2FwYWJpbGl0aWVzIG9mIHRoZSB1bmRlcmx5aW5nIFJFU1RmdWwgW01lbWJlciBBUEldKC4uLy4uLy4uL3Jlc3RfYXBpcy91c2VyX21hbmFnZW1lbnQvbWVtYmVyLykuXG4gKlxuICogVGhpcyBpcyBvbmx5IG5lZWRlZCBmb3IgQXV0aGVudGljYXRlZCBwcm9qZWN0cywgdGhhdCBpcywgdGVhbSBwcm9qZWN0cyB3aXRoIFtlbmQgdXNlcnMgYW5kIGdyb3Vwc10oLi4vLi4vLi4vZ3JvdXBzX2FuZF9lbmRfdXNlcnMvKS4gRm9yIGV4YW1wbGUsIGlmIHNvbWUgb2YgeW91ciBlbmQgdXNlcnMgYXJlIGZhY2lsaXRhdG9ycywgb3IgaWYgeW91ciBlbmQgdXNlcnMgc2hvdWxkIGJlIHRyZWF0ZWQgZGlmZmVyZW50bHkgYmFzZWQgb24gd2hpY2ggZ3JvdXAgdGhleSBhcmUgaW4sIHVzZSB0aGUgTWVtYmVyIEFQSSB0byBmaW5kIHRoYXQgaW5mb3JtYXRpb24uXG4gKlxuICogICAgICB2YXIgbWEgPSBuZXcgRi5zZXJ2aWNlLk1lbWJlcih7IHRva2VuOiAndXNlci1vci1wcm9qZWN0LWFjY2Vzcy10b2tlbicgfSk7XG4gKiAgICAgIG1hLmdldEdyb3Vwc0ZvclVzZXIoeyB1c2VySWQ6ICdiNmIzMTNhMy1hYjg0LTQ3OWMtYmFlYS0yMDZmNmJmZjMzNycgfSk7XG4gKiAgICAgIG1hLmdldEdyb3VwRGV0YWlscyh7IGdyb3VwSWQ6ICcwMGI1MzMwOC05ODMzLTQ3ZjItYjIxZS0xMjc4YzA3ZDUzYjgnIH0pO1xuICovXG5cbid1c2Ugc3RyaWN0JztcblxudmFyIENvbmZpZ1NlcnZpY2UgPSByZXF1aXJlKCcuL2NvbmZpZ3VyYXRpb24tc2VydmljZScpO1xudmFyIFRyYW5zcG9ydEZhY3RvcnkgPSByZXF1aXJlKCcuLi90cmFuc3BvcnQvaHR0cC10cmFuc3BvcnQtZmFjdG9yeScpO1xudmFyIFNlc3Npb25NYW5hZ2VyID0gcmVxdWlyZSgnLi4vc3RvcmUvc2Vzc2lvbi1tYW5hZ2VyJyk7XG52YXIgX3BpY2sgPSByZXF1aXJlKCcuLi91dGlsL29iamVjdC11dGlsJykuX3BpY2s7XG52YXIgYXBpRW5kcG9pbnQgPSAnbWVtYmVyL2xvY2FsJztcblxubW9kdWxlLmV4cG9ydHMgPSBmdW5jdGlvbiAoY29uZmlnKSB7XG4gICAgdmFyIGRlZmF1bHRzID0ge1xuICAgICAgICAvKipcbiAgICAgICAgICogRXBpY2VudGVyIHVzZXIgaWQuIERlZmF1bHRzIHRvIGEgYmxhbmsgc3RyaW5nLlxuICAgICAgICAgKiBAdHlwZSB7c3RyaW5nfVxuICAgICAgICAgKi9cbiAgICAgICAgdXNlcklkOiB1bmRlZmluZWQsXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIEVwaWNlbnRlciBncm91cCBpZC4gRGVmYXVsdHMgdG8gYSBibGFuayBzdHJpbmcuIE5vdGUgdGhhdCB0aGlzIGlzIHRoZSBncm91cCAqaWQqLCBub3QgdGhlIGdyb3VwICpuYW1lKi5cbiAgICAgICAgICogQHR5cGUge3N0cmluZ31cbiAgICAgICAgICovXG4gICAgICAgIGdyb3VwSWQ6IHVuZGVmaW5lZCxcblxuICAgICAgICAvKipcbiAgICAgICAgICogT3B0aW9ucyB0byBwYXNzIG9uIHRvIHRoZSB1bmRlcmx5aW5nIHRyYW5zcG9ydCBsYXllci4gQWxsIGpxdWVyeS5hamF4IG9wdGlvbnMgYXQgaHR0cDovL2FwaS5qcXVlcnkuY29tL2pRdWVyeS5hamF4LyBhcmUgYXZhaWxhYmxlLiBEZWZhdWx0cyB0byBlbXB0eSBvYmplY3QuXG4gICAgICAgICAqIEB0eXBlIHtvYmplY3R9XG4gICAgICAgICAqL1xuICAgICAgICB0cmFuc3BvcnQ6IHt9XG4gICAgfTtcbiAgICB0aGlzLnNlc3Npb25NYW5hZ2VyID0gbmV3IFNlc3Npb25NYW5hZ2VyKCk7XG4gICAgdmFyIHNlcnZpY2VPcHRpb25zID0gdGhpcy5zZXNzaW9uTWFuYWdlci5nZXRNZXJnZWRPcHRpb25zKGRlZmF1bHRzLCBjb25maWcpO1xuICAgIHZhciB1cmxDb25maWcgPSBuZXcgQ29uZmlnU2VydmljZShzZXJ2aWNlT3B0aW9ucykuZ2V0KCdzZXJ2ZXInKTtcblxuICAgIHZhciB0cmFuc3BvcnRPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sIHNlcnZpY2VPcHRpb25zLnRyYW5zcG9ydCwge1xuICAgICAgICB1cmw6IHVybENvbmZpZy5nZXRBUElQYXRoKGFwaUVuZHBvaW50KVxuICAgIH0pO1xuXG4gICAgaWYgKHNlcnZpY2VPcHRpb25zLnRva2VuKSB7XG4gICAgICAgIHRyYW5zcG9ydE9wdGlvbnMuaGVhZGVycyA9IHtcbiAgICAgICAgICAgIEF1dGhvcml6YXRpb246ICdCZWFyZXIgJyArIHNlcnZpY2VPcHRpb25zLnRva2VuXG4gICAgICAgIH07XG4gICAgfVxuICAgIHZhciBodHRwID0gbmV3IFRyYW5zcG9ydEZhY3RvcnkodHJhbnNwb3J0T3B0aW9ucywgc2VydmljZU9wdGlvbnMpO1xuXG4gICAgdmFyIGdldEZpbmFsUGFyYW1zID0gZnVuY3Rpb24gKHBhcmFtcykge1xuICAgICAgICBpZiAodHlwZW9mIHBhcmFtcyA9PT0gJ29iamVjdCcpIHtcbiAgICAgICAgICAgIHJldHVybiAkLmV4dGVuZCh0cnVlLCBzZXJ2aWNlT3B0aW9ucywgcGFyYW1zKTtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gc2VydmljZU9wdGlvbnM7XG4gICAgfTtcblxuICAgIHZhciBwYXRjaFVzZXJBY3RpdmVGaWVsZCA9IGZ1bmN0aW9uIChwYXJhbXMsIGFjdGl2ZSwgb3B0aW9ucykge1xuICAgICAgICB2YXIgaHR0cE9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCBzZXJ2aWNlT3B0aW9ucywgb3B0aW9ucywge1xuICAgICAgICAgICAgdXJsOiB1cmxDb25maWcuZ2V0QVBJUGF0aChhcGlFbmRwb2ludCkgKyBwYXJhbXMuZ3JvdXBJZCArICcvJyArIHBhcmFtcy51c2VySWRcbiAgICAgICAgfSk7XG5cbiAgICAgICAgcmV0dXJuIGh0dHAucGF0Y2goeyBhY3RpdmU6IGFjdGl2ZSB9LCBodHRwT3B0aW9ucyk7XG4gICAgfTtcblxuICAgIHZhciBwdWJsaWNBUEkgPSB7XG5cbiAgICAgICAgLyoqXG4gICAgICAgICogUmV0cmlldmUgZGV0YWlscyBhYm91dCBhbGwgb2YgdGhlIGdyb3VwIG1lbWJlcnNoaXBzIGZvciBvbmUgZW5kIHVzZXIuIFRoZSBtZW1iZXJzaGlwIGRldGFpbHMgYXJlIHJldHVybmVkIGluIGFuIGFycmF5LCB3aXRoIG9uZSBlbGVtZW50IChncm91cCByZWNvcmQpIGZvciBlYWNoIGdyb3VwIHRvIHdoaWNoIHRoZSBlbmQgdXNlciBiZWxvbmdzLlxuICAgICAgICAqXG4gICAgICAgICogSW4gdGhlIG1lbWJlcnNoaXAgYXJyYXksIGVhY2ggZ3JvdXAgcmVjb3JkIGluY2x1ZGVzIHRoZSBncm91cCBpZCwgcHJvamVjdCBpZCwgYWNjb3VudCAodGVhbSkgaWQsIGFuZCBhbiBhcnJheSBvZiBtZW1iZXJzLiBIb3dldmVyLCBvbmx5IHRoZSB1c2VyIHdob3NlIHVzZXJJZCBpcyBpbmNsdWRlZCBpbiB0aGUgY2FsbCBpcyBsaXN0ZWQgaW4gdGhlIG1lbWJlcnMgYXJyYXkgKHJlZ2FyZGxlc3Mgb2Ygd2hldGhlciB0aGVyZSBhcmUgb3RoZXIgbWVtYmVycyBpbiB0aGlzIGdyb3VwKS5cbiAgICAgICAgKlxuICAgICAgICAqICoqRXhhbXBsZSoqXG4gICAgICAgICpcbiAgICAgICAgKiAgICAgICB2YXIgbWEgPSBuZXcgRi5zZXJ2aWNlLk1lbWJlcih7IHRva2VuOiAndXNlci1vci1wcm9qZWN0LWFjY2Vzcy10b2tlbicgfSk7XG4gICAgICAgICogICAgICAgbWEuZ2V0R3JvdXBzRm9yVXNlcignNDI4MzZkNGItNWI2MS00ZmU0LTgwZWItMzEzNmU5NTZlZTVjJylcbiAgICAgICAgKiAgICAgICAgICAgLnRoZW4oZnVuY3Rpb24obWVtYmVyc2hpcHMpe1xuICAgICAgICAqICAgICAgICAgICAgICAgZm9yICh2YXIgaT0wOyBpPG1lbWJlcnNoaXBzLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgICogICAgICAgICAgICAgICAgICAgY29uc29sZS5sb2cobWVtYmVyc2hpcHNbaV0uZ3JvdXBJZCk7XG4gICAgICAgICogICAgICAgICAgICAgICB9XG4gICAgICAgICogICAgICAgICAgIH0pO1xuICAgICAgICAqXG4gICAgICAgICogICAgICAgbWEuZ2V0R3JvdXBzRm9yVXNlcih7IHVzZXJJZDogJzQyODM2ZDRiLTViNjEtNGZlNC04MGViLTMxMzZlOTU2ZWU1YycgfSk7XG4gICAgICAgICpcbiAgICAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAqIEBwYXJhbSB7c3RyaW5nfG9iamVjdH0gcGFyYW1zIFRoZSB1c2VyIGlkIGZvciB0aGUgZW5kIHVzZXIuIEFsdGVybmF0aXZlbHksIGFuIG9iamVjdCB3aXRoIGZpZWxkIGB1c2VySWRgIGFuZCB2YWx1ZSB0aGUgdXNlciBpZC5cbiAgICAgICAgKiBAcGFyYW0ge29iamVjdH0gb3B0aW9ucyAoT3B0aW9uYWwpIE92ZXJyaWRlcyBmb3IgY29uZmlndXJhdGlvbiBvcHRpb25zLlxuICAgICAgICAqL1xuXG4gICAgICAgIGdldEdyb3Vwc0ZvclVzZXI6IGZ1bmN0aW9uIChwYXJhbXMsIG9wdGlvbnMpIHtcbiAgICAgICAgICAgIG9wdGlvbnMgPSBvcHRpb25zIHx8IHt9O1xuICAgICAgICAgICAgdmFyIGh0dHBPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwgc2VydmljZU9wdGlvbnMsIG9wdGlvbnMpO1xuICAgICAgICAgICAgdmFyIGlzU3RyaW5nID0gdHlwZW9mIHBhcmFtcyA9PT0gJ3N0cmluZyc7XG4gICAgICAgICAgICB2YXIgb2JqUGFyYW1zID0gZ2V0RmluYWxQYXJhbXMocGFyYW1zKTtcbiAgICAgICAgICAgIGlmICghaXNTdHJpbmcgJiYgIW9ialBhcmFtcy51c2VySWQpIHtcbiAgICAgICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ05vIHVzZXJJZCBzcGVjaWZpZWQuJyk7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIHZhciBnZXRQYXJtcyA9IGlzU3RyaW5nID8geyB1c2VySWQ6IHBhcmFtcyB9IDogX3BpY2sob2JqUGFyYW1zLCAndXNlcklkJyk7XG4gICAgICAgICAgICByZXR1cm4gaHR0cC5nZXQoZ2V0UGFybXMsIGh0dHBPcHRpb25zKTtcbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgKiBSZXRyaWV2ZSBkZXRhaWxzIGFib3V0IG9uZSBncm91cCwgaW5jbHVkaW5nIGFuIGFycmF5IG9mIGFsbCBpdHMgbWVtYmVycy5cbiAgICAgICAgKlxuICAgICAgICAqICoqRXhhbXBsZSoqXG4gICAgICAgICpcbiAgICAgICAgKiAgICAgICB2YXIgbWEgPSBuZXcgRi5zZXJ2aWNlLk1lbWJlcih7IHRva2VuOiAndXNlci1vci1wcm9qZWN0LWFjY2Vzcy10b2tlbicgfSk7XG4gICAgICAgICogICAgICAgbWEuZ2V0R3JvdXBEZXRhaWxzKCc4MDI1N2EyNS1hYTEwLTQ5NTktOTY4Yi1mZDA1MzkwMWY3MmYnKVxuICAgICAgICAqICAgICAgICAgICAudGhlbihmdW5jdGlvbihncm91cCl7XG4gICAgICAgICogICAgICAgICAgICAgICBmb3IgKHZhciBpPTA7IGk8Z3JvdXAubWVtYmVycy5sZW5ndGg7IGkrKykge1xuICAgICAgICAqICAgICAgICAgICAgICAgICAgIGNvbnNvbGUubG9nKGdyb3VwLm1lbWJlcnNbaV0udXNlck5hbWUpO1xuICAgICAgICAqICAgICAgICAgICAgICAgfVxuICAgICAgICAqICAgICAgICAgICB9KTtcbiAgICAgICAgKlxuICAgICAgICAqICAgICAgIG1hLmdldEdyb3VwRGV0YWlscyh7IGdyb3VwSWQ6ICc4MDI1N2EyNS1hYTEwLTQ5NTktOTY4Yi1mZDA1MzkwMWY3MmYnIH0pO1xuICAgICAgICAqXG4gICAgICAgICogKipQYXJhbWV0ZXJzKipcbiAgICAgICAgKiBAcGFyYW0ge3N0cmluZ3xvYmplY3R9IHBhcmFtcyBUaGUgZ3JvdXAgaWQuIEFsdGVybmF0aXZlbHksIGFuIG9iamVjdCB3aXRoIGZpZWxkIGBncm91cElkYCBhbmQgdmFsdWUgdGhlIGdyb3VwIGlkLlxuICAgICAgICAqIEBwYXJhbSB7b2JqZWN0fSBvcHRpb25zIChPcHRpb25hbCkgT3ZlcnJpZGVzIGZvciBjb25maWd1cmF0aW9uIG9wdGlvbnMuXG4gICAgICAgICogQHJldHVybiB7UHJvbWlzZX1cbiAgICAgICAgKi9cbiAgICAgICAgZ2V0R3JvdXBEZXRhaWxzOiBmdW5jdGlvbiAocGFyYW1zLCBvcHRpb25zKSB7XG4gICAgICAgICAgICBvcHRpb25zID0gb3B0aW9ucyB8fCB7fTtcbiAgICAgICAgICAgIHZhciBpc1N0cmluZyA9IHR5cGVvZiBwYXJhbXMgPT09ICdzdHJpbmcnO1xuICAgICAgICAgICAgdmFyIG9ialBhcmFtcyA9IGdldEZpbmFsUGFyYW1zKHBhcmFtcyk7XG4gICAgICAgICAgICBpZiAoIWlzU3RyaW5nICYmICFvYmpQYXJhbXMuZ3JvdXBJZCkge1xuICAgICAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcignTm8gZ3JvdXBJZCBzcGVjaWZpZWQuJyk7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIHZhciBncm91cElkID0gaXNTdHJpbmcgPyBwYXJhbXMgOiBvYmpQYXJhbXMuZ3JvdXBJZDtcbiAgICAgICAgICAgIHZhciBodHRwT3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHNlcnZpY2VPcHRpb25zLFxuICAgICAgICAgICAgICAgIG9wdGlvbnMsXG4gICAgICAgICAgICAgICAgeyB1cmw6IHVybENvbmZpZy5nZXRBUElQYXRoKGFwaUVuZHBvaW50KSArIGdyb3VwSWQgfVxuICAgICAgICAgICAgKTtcblxuICAgICAgICAgICAgcmV0dXJuIGh0dHAuZ2V0KHt9LCBodHRwT3B0aW9ucyk7XG4gICAgICAgIH0sXG5cbiAgICAgICAgLyoqXG4gICAgICAgICogU2V0IGEgcGFydGljdWxhciBlbmQgdXNlciBhcyBgYWN0aXZlYC4gQWN0aXZlIGVuZCB1c2VycyBjYW4gYmUgYXNzaWduZWQgdG8gW3dvcmxkc10oLi4vd29ybGQtbWFuYWdlci8pIGluIG11bHRpcGxheWVyIGdhbWVzIGR1cmluZyBhdXRvbWF0aWMgYXNzaWdubWVudC5cbiAgICAgICAgKlxuICAgICAgICAqICoqRXhhbXBsZSoqXG4gICAgICAgICpcbiAgICAgICAgKiAgICAgICB2YXIgbWEgPSBuZXcgRi5zZXJ2aWNlLk1lbWJlcih7IHRva2VuOiAndXNlci1vci1wcm9qZWN0LWFjY2Vzcy10b2tlbicgfSk7XG4gICAgICAgICogICAgICAgbWEubWFrZVVzZXJBY3RpdmUoeyB1c2VySWQ6ICc0MjgzNmQ0Yi01YjYxLTRmZTQtODBlYi0zMTM2ZTk1NmVlNWMnLFxuICAgICAgICAqICAgICAgICAgICAgICAgICAgICAgICAgICAgZ3JvdXBJZDogJzgwMjU3YTI1LWFhMTAtNDk1OS05NjhiLWZkMDUzOTAxZjcyZicgfSk7XG4gICAgICAgICpcbiAgICAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAqIEBwYXJhbSB7b2JqZWN0fSBwYXJhbXMgVGhlIGVuZCB1c2VyIGFuZCBncm91cCBpbmZvcm1hdGlvbi5cbiAgICAgICAgKiBAcGFyYW0ge3N0cmluZ30gcGFyYW1zLnVzZXJJZCBUaGUgaWQgb2YgdGhlIGVuZCB1c2VyIHRvIG1ha2UgYWN0aXZlLlxuICAgICAgICAqIEBwYXJhbSB7c3RyaW5nfSBwYXJhbXMuZ3JvdXBJZCBUaGUgaWQgb2YgdGhlIGdyb3VwIHRvIHdoaWNoIHRoaXMgZW5kIHVzZXIgYmVsb25ncywgYW5kIGluIHdoaWNoIHRoZSBlbmQgdXNlciBzaG91bGQgYmVjb21lIGFjdGl2ZS5cbiAgICAgICAgKiBAcGFyYW0ge29iamVjdH0gb3B0aW9ucyAoT3B0aW9uYWwpIE92ZXJyaWRlcyBmb3IgY29uZmlndXJhdGlvbiBvcHRpb25zLlxuICAgICAgICAqIEByZXR1cm4ge1Byb21pc2V9XG4gICAgICAgICovXG4gICAgICAgIG1ha2VVc2VyQWN0aXZlOiBmdW5jdGlvbiAocGFyYW1zLCBvcHRpb25zKSB7XG4gICAgICAgICAgICByZXR1cm4gcGF0Y2hVc2VyQWN0aXZlRmllbGQocGFyYW1zLCB0cnVlLCBvcHRpb25zKTtcbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgKiBTZXQgYSBwYXJ0aWN1bGFyIGVuZCB1c2VyIGFzIGBpbmFjdGl2ZWAuIEluYWN0aXZlIGVuZCB1c2VycyBhcmUgbm90IGFzc2lnbmVkIHRvIFt3b3JsZHNdKC4uL3dvcmxkLW1hbmFnZXIvKSBpbiBtdWx0aXBsYXllciBnYW1lcyBkdXJpbmcgYXV0b21hdGljIGFzc2lnbm1lbnQuXG4gICAgICAgICpcbiAgICAgICAgKiAqKkV4YW1wbGUqKlxuICAgICAgICAqXG4gICAgICAgICogICAgICAgdmFyIG1hID0gbmV3IEYuc2VydmljZS5NZW1iZXIoeyB0b2tlbjogJ3VzZXItb3ItcHJvamVjdC1hY2Nlc3MtdG9rZW4nIH0pO1xuICAgICAgICAqICAgICAgIG1hLm1ha2VVc2VySW5hY3RpdmUoeyB1c2VySWQ6ICc0MjgzNmQ0Yi01YjYxLTRmZTQtODBlYi0zMTM2ZTk1NmVlNWMnLFxuICAgICAgICAqICAgICAgICAgICAgICAgICAgICAgICAgICAgZ3JvdXBJZDogJzgwMjU3YTI1LWFhMTAtNDk1OS05NjhiLWZkMDUzOTAxZjcyZicgfSk7XG4gICAgICAgICpcbiAgICAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAqIEBwYXJhbSB7b2JqZWN0fSBwYXJhbXMgVGhlIGVuZCB1c2VyIGFuZCBncm91cCBpbmZvcm1hdGlvbi5cbiAgICAgICAgKiBAcGFyYW0ge3N0cmluZ30gcGFyYW1zLnVzZXJJZCBUaGUgaWQgb2YgdGhlIGVuZCB1c2VyIHRvIG1ha2UgaW5hY3RpdmUuXG4gICAgICAgICogQHBhcmFtIHtzdHJpbmd9IHBhcmFtcy5ncm91cElkIFRoZSBpZCBvZiB0aGUgZ3JvdXAgdG8gd2hpY2ggdGhpcyBlbmQgdXNlciBiZWxvbmdzLCBhbmQgaW4gd2hpY2ggdGhlIGVuZCB1c2VyIHNob3VsZCBiZWNvbWUgaW5hY3RpdmUuXG4gICAgICAgICogQHBhcmFtIHtvYmplY3R9IG9wdGlvbnMgKE9wdGlvbmFsKSBPdmVycmlkZXMgZm9yIGNvbmZpZ3VyYXRpb24gb3B0aW9ucy5cbiAgICAgICAgKiBAcmV0dXJuIHtQcm9taXNlfVxuICAgICAgICAqL1xuICAgICAgICBtYWtlVXNlckluYWN0aXZlOiBmdW5jdGlvbiAocGFyYW1zLCBvcHRpb25zKSB7XG4gICAgICAgICAgICByZXR1cm4gcGF0Y2hVc2VyQWN0aXZlRmllbGQocGFyYW1zLCBmYWxzZSwgb3B0aW9ucyk7XG4gICAgICAgIH1cbiAgICB9O1xuXG4gICAgJC5leHRlbmQodGhpcywgcHVibGljQVBJKTtcbn07XG4iLCIvKipcbiAqXG4gKiAjIyBQcmVzZW5jZSBBUEkgU2VydmljZVxuICpcbiAqIFRoZSBQcmVzZW5jZSBBUEkgU2VydmljZSBwcm92aWRlcyBtZXRob2RzIHRvIGdldCBhbmQgc2V0IHRoZSBwcmVzZW5jZSBvZiBhbiBlbmQgdXNlciBpbiBhIHByb2plY3QsIHRoYXQgaXMsIHRvIGluZGljYXRlIHdoZXRoZXIgdGhlIGVuZCB1c2VyIGlzIG9ubGluZS4gVGhpcyBoYXBwZW5zIGF1dG9tYXRpY2FsbHk6IGluIHByb2plY3RzIHRoYXQgdXNlIFtjaGFubmVsc10oLi4vZXBpY2VudGVyLWNoYW5uZWwtbWFuYWdlci8pLCB0aGUgZW5kIHVzZXIncyBwcmVzZW5jZSBpcyBwdWJsaXNoZWQgYXV0b21hdGljYWxseSBvbiBhIFwicHJlc2VuY2VcIiBjaGFubmVsIHRoYXQgaXMgc3BlY2lmaWMgdG8gZWFjaCBncm91cC4gWW91IGNhbiBhbHNvIHVzZSB0aGUgUHJlc2VuY2UgQVBJIFNlcnZpY2UgdG8gZG8gdGhpcyBleHBsaWNpdGx5OiB5b3UgY2FuIG1ha2UgYSBjYWxsIHRvIGluZGljYXRlIHRoYXQgYSBwYXJ0aWN1bGFyIGVuZCB1c2VyIGlzIG9ubGluZSBvciBvZmZsaW5lLiBcbiAqXG4gKiBUaGUgUHJlc2VuY2UgQVBJIFNlcnZpY2UgaXMgb25seSBuZWVkZWQgZm9yIEF1dGhlbnRpY2F0ZWQgcHJvamVjdHMsIHRoYXQgaXMsIHRlYW0gcHJvamVjdHMgd2l0aCBbZW5kIHVzZXJzIGFuZCBncm91cHNdKC4uLy4uLy4uL2dyb3Vwc19hbmRfZW5kX3VzZXJzLykuIEl0IGlzIHR5cGljYWxseSB1c2VkIG9ubHkgaW4gbXVsdGlwbGF5ZXIgcHJvamVjdHMsIHRvIGZhY2lsaXRhdGUgZW5kIHVzZXJzIGNvbW11bmljYXRpbmcgd2l0aCBlYWNoIG90aGVyLiBJdCBpcyBiYXNlZCBvbiB0aGUgcXVlcnkgY2FwYWJpbGl0aWVzIG9mIHRoZSB1bmRlcmx5aW5nIFJFU1RmdWwgW1ByZXNlbmNlIEFQSV0oLi4vLi4vLi4vcmVzdF9hcGlzL211bHRpcGxheWVyL3ByZXNlbmNlLykuXG4gKlxuICogICAgICB2YXIgcHIgPSBuZXcgRi5zZXJ2aWNlLlByZXNlbmNlKCk7XG4gKiAgICAgIHByLm1hcmtPbmxpbmUoJ2V4YW1wbGUtdXNlcklkJyk7XG4gKiAgICAgIHByLm1hcmtPZmZsaW5lKCdleGFtcGxlLXVzZXJJZCcpO1xuICogICAgICBwci5nZXRTdGF0dXMoKTtcbiAqL1xuXG52YXIgQ29uZmlnU2VydmljZSA9IHJlcXVpcmUoJy4vY29uZmlndXJhdGlvbi1zZXJ2aWNlJyk7XG52YXIgVHJhbnNwb3J0RmFjdG9yeSA9IHJlcXVpcmUoJy4uL3RyYW5zcG9ydC9odHRwLXRyYW5zcG9ydC1mYWN0b3J5Jyk7XG52YXIgU2Vzc2lvbk1hbmFnZXIgPSByZXF1aXJlKCcuLi9zdG9yZS9zZXNzaW9uLW1hbmFnZXInKTtcbnZhciBhcGlFbmRwb2ludCA9ICdwcmVzZW5jZSc7XG52YXIgQ2hhbm5lbE1hbmFnZXIgPSByZXF1aXJlKCcuLi9tYW5hZ2Vycy9lcGljZW50ZXItY2hhbm5lbC1tYW5hZ2VyJyk7XG5cbm1vZHVsZS5leHBvcnRzID0gZnVuY3Rpb24gKGNvbmZpZykge1xuICAgIHZhciBkZWZhdWx0cyA9IHtcbiAgICAgICAgLyoqXG4gICAgICAgICAqIFRoZSBhY2NvdW50IGlkLiBJbiB0aGUgRXBpY2VudGVyIFVJLCB0aGlzIGlzIHRoZSAqKlRlYW0gSUQqKiAoZm9yIHRlYW0gcHJvamVjdHMpIG9yICoqVXNlciBJRCoqIChmb3IgcGVyc29uYWwgcHJvamVjdHMpLiBEZWZhdWx0cyB0byB1bmRlZmluZWQuIElmIGxlZnQgdW5kZWZpbmVkLCB0YWtlbiBmcm9tIHRoZSBVUkwgb3Igc2Vzc2lvbiBtYW5hZ2VyLlxuICAgICAgICAgKiBAdHlwZSB7U3RyaW5nfVxuICAgICAgICAgKi9cbiAgICAgICAgYWNjb3VudDogdW5kZWZpbmVkLFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBUaGUgcHJvamVjdCBpZC4gRGVmYXVsdHMgdG8gdW5kZWZpbmVkLiBJZiBsZWZ0IHVuZGVmaW5lZCwgdGFrZW4gZnJvbSB0aGUgVVJMIG9yIHNlc3Npb24gbWFuYWdlci5cbiAgICAgICAgICogQHR5cGUge1N0cmluZ31cbiAgICAgICAgICovXG4gICAgICAgIHByb2plY3Q6IHVuZGVmaW5lZCxcblxuICAgICAgICAvKipcbiAgICAgICAgICogRXBpY2VudGVyIGdyb3VwIG5hbWUuIERlZmF1bHRzIHRvIHVuZGVmaW5lZC4gTm90ZSB0aGF0IHRoaXMgaXMgdGhlIGdyb3VwICpuYW1lKiwgbm90IHRoZSBncm91cCAqaWQqLiBJZiBsZWZ0IGJsYW5rLCB0YWtlbiBmcm9tIHRoZSBzZXNzaW9uIG1hbmFnZXIuXG4gICAgICAgICAqIEB0eXBlIHtzdHJpbmd9XG4gICAgICAgICAqL1xuICAgICAgICBncm91cE5hbWU6IHVuZGVmaW5lZCxcblxuICAgICAgICAvKipcbiAgICAgICAgICogT3B0aW9ucyB0byBwYXNzIG9uIHRvIHRoZSB1bmRlcmx5aW5nIHRyYW5zcG9ydCBsYXllci4gQWxsIGpxdWVyeS5hamF4IG9wdGlvbnMgYXQgaHR0cDovL2FwaS5qcXVlcnkuY29tL2pRdWVyeS5hamF4LyBhcmUgYXZhaWxhYmxlLiBEZWZhdWx0cyB0byBlbXB0eSBvYmplY3QuXG4gICAgICAgICAqIEB0eXBlIHtvYmplY3R9XG4gICAgICAgICAqL1xuICAgICAgICB0cmFuc3BvcnQ6IHt9LFxuICAgIH07XG4gICAgdGhpcy5zZXNzaW9uTWFuYWdlciA9IG5ldyBTZXNzaW9uTWFuYWdlcigpO1xuICAgIHZhciBzZXJ2aWNlT3B0aW9ucyA9IHRoaXMuc2Vzc2lvbk1hbmFnZXIuZ2V0TWVyZ2VkT3B0aW9ucyhkZWZhdWx0cywgY29uZmlnKTtcbiAgICB2YXIgdXJsQ29uZmlnID0gbmV3IENvbmZpZ1NlcnZpY2Uoc2VydmljZU9wdGlvbnMpLmdldCgnc2VydmVyJyk7XG4gICAgaWYgKHNlcnZpY2VPcHRpb25zLmFjY291bnQpIHtcbiAgICAgICAgdXJsQ29uZmlnLmFjY291bnRQYXRoID0gc2VydmljZU9wdGlvbnMuYWNjb3VudDtcbiAgICB9XG4gICAgaWYgKHNlcnZpY2VPcHRpb25zLnByb2plY3QpIHtcbiAgICAgICAgdXJsQ29uZmlnLnByb2plY3RQYXRoID0gc2VydmljZU9wdGlvbnMucHJvamVjdDtcbiAgICB9XG5cbiAgICB2YXIgdHJhbnNwb3J0T3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LCBzZXJ2aWNlT3B0aW9ucy50cmFuc3BvcnQsIHtcbiAgICAgICAgdXJsOiB1cmxDb25maWcuZ2V0QVBJUGF0aChhcGlFbmRwb2ludClcbiAgICB9KTtcblxuICAgIGlmIChzZXJ2aWNlT3B0aW9ucy50b2tlbikge1xuICAgICAgICB0cmFuc3BvcnRPcHRpb25zLmhlYWRlcnMgPSB7XG4gICAgICAgICAgICBBdXRob3JpemF0aW9uOiAnQmVhcmVyICcgKyBzZXJ2aWNlT3B0aW9ucy50b2tlblxuICAgICAgICB9O1xuICAgIH1cbiAgICB2YXIgaHR0cCA9IG5ldyBUcmFuc3BvcnRGYWN0b3J5KHRyYW5zcG9ydE9wdGlvbnMsIHNlcnZpY2VPcHRpb25zKTtcblxuXG4gICAgdmFyIGdldEZpbmFsUGFyYW1zID0gZnVuY3Rpb24gKHBhcmFtcykge1xuICAgICAgICBpZiAodHlwZW9mIHBhcmFtcyA9PT0gJ29iamVjdCcpIHtcbiAgICAgICAgICAgIHJldHVybiAkLmV4dGVuZCh0cnVlLCB7fSwgc2VydmljZU9wdGlvbnMsIHBhcmFtcyk7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIHNlcnZpY2VPcHRpb25zO1xuICAgIH07XG5cbiAgICB2YXIgcHVibGljQVBJID0ge1xuICAgICAgICAvKipcbiAgICAgICAgICogTWFya3MgYW4gZW5kIHVzZXIgYXMgb25saW5lLlxuICAgICAgICAgKlxuICAgICAgICAgKlxuICAgICAgICAgKiAqKkV4YW1wbGUqKlxuICAgICAgICAgKlxuICAgICAgICAgKiAgICAgdmFyIHByID0gbmV3IEYuc2VydmljZS5QcmVzZW5jZSgpO1xuICAgICAgICAgKiAgICAgcHIubWFya09ubGluZSgnMDAwMDAxNWE2OGQ4MDZiYzA5Y2QwYTdkMjA3ZjQ0YmE1Zjc0JylcbiAgICAgICAgICogICAgICAgICAgLnRoZW4oZnVuY3Rpb24ocHJlc2VuY2VPYmopIHtcbiAgICAgICAgICogICAgICAgICAgICAgICBjb25zb2xlLmxvZygndXNlciAnLCBwcmVzZW5jZU9iai51c2VySWQsIFxuICAgICAgICAgKiAgICAgICAgICAgICAgICAgICAgJyBub3cgb25saW5lLCBhcyBvZiAnLCBwcmVzZW5jZU9iai5sYXN0TW9kaWZpZWQpO1xuICAgICAgICAgKiAgICAgICAgICB9KTtcbiAgICAgICAgICpcbiAgICAgICAgICogKipSZXR1cm4gVmFsdWUqKlxuICAgICAgICAgKlxuICAgICAgICAgKiBQcm9taXNlIHdpdGggcHJlc2VuY2UgaW5mb3JtYXRpb24gZm9yIHVzZXIgbWFya2VkIG9ubGluZS5cbiAgICAgICAgICpcbiAgICAgICAgICogKipQYXJhbWV0ZXJzKipcbiAgICAgICAgICpcbiAgICAgICAgICogQHBhcmFtICB7U3RyaW5nfSB1c2VySWQgKG9wdGlvbmFsKSBJZiBub3QgcHJvdmlkZWQsIHRha2VuIGZyb20gc2Vzc2lvbiBjb29raWUuXG4gICAgICAgICAqIEBwYXJhbSAge09iamVjdH0gb3B0aW9ucyBBZGRpdGlvbmFsIG9wdGlvbnMgdG8gY2hhbmdlIHRoZSBwcmVzZW5jZSBzZXJ2aWNlIGRlZmF1bHRzLlxuICAgICAgICAgKiBAcmV0dXJuIHtQcm9taXNlfSBwcm9taXNlXG4gICAgICAgICAqL1xuICAgICAgICBtYXJrT25saW5lOiBmdW5jdGlvbiAodXNlcklkLCBvcHRpb25zKSB7XG4gICAgICAgICAgICBvcHRpb25zID0gb3B0aW9ucyB8fCB7fTtcbiAgICAgICAgICAgIHZhciBpc1N0cmluZyA9IHR5cGVvZiB1c2VySWQgPT09ICdzdHJpbmcnO1xuICAgICAgICAgICAgdmFyIG9ialBhcmFtcyA9IGdldEZpbmFsUGFyYW1zKHVzZXJJZCk7XG4gICAgICAgICAgICBpZiAoIW9ialBhcmFtcy5ncm91cE5hbWUgJiYgIW9wdGlvbnMuZ3JvdXBOYW1lKSB7XG4gICAgICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdObyBncm91cE5hbWUgc3BlY2lmaWVkLicpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgdXNlcklkID0gaXNTdHJpbmcgPyB1c2VySWQgOiBvYmpQYXJhbXMudXNlcklkO1xuICAgICAgICAgICAgdmFyIGdyb3VwTmFtZSA9IG9wdGlvbnMuZ3JvdXBOYW1lIHx8IG9ialBhcmFtcy5ncm91cE5hbWU7XG4gICAgICAgICAgICB2YXIgaHR0cE9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSwgc2VydmljZU9wdGlvbnMsIG9wdGlvbnMsXG4gICAgICAgICAgICAgICAgeyB1cmw6IHVybENvbmZpZy5nZXRBUElQYXRoKGFwaUVuZHBvaW50KSArIGdyb3VwTmFtZSArICcvJyArIHVzZXJJZCB9XG4gICAgICAgICAgICApO1xuICAgICAgICAgICAgcmV0dXJuIGh0dHAucG9zdCh7IG1lc3NhZ2U6ICdvbmxpbmUnIH0sIGh0dHBPcHRpb25zKTtcbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgICogTWFya3MgYW4gZW5kIHVzZXIgYXMgb2ZmbGluZS5cbiAgICAgICAgICpcbiAgICAgICAgICpcbiAgICAgICAgICogKipFeGFtcGxlKipcbiAgICAgICAgICpcbiAgICAgICAgICogICAgIHZhciBwciA9IG5ldyBGLnNlcnZpY2UuUHJlc2VuY2UoKTtcbiAgICAgICAgICogICAgIHByLm1hcmtPZmZsaW5lKCcwMDAwMDE1YTY4ZDgwNmJjMDljZDBhN2QyMDdmNDRiYTVmNzQnKTtcbiAgICAgICAgICpcbiAgICAgICAgICogKipSZXR1cm4gVmFsdWUqKlxuICAgICAgICAgKlxuICAgICAgICAgKiBQcm9taXNlIHRvIHJlbW92ZSBwcmVzZW5jZSByZWNvcmQgZm9yIGVuZCB1c2VyLlxuICAgICAgICAgKlxuICAgICAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAgKlxuICAgICAgICAgKiBAcGFyYW0gIHtTdHJpbmd9IHVzZXJJZCAob3B0aW9uYWwpIElmIG5vdCBwcm92aWRlZCwgdGFrZW4gZnJvbSBzZXNzaW9uIGNvb2tpZS5cbiAgICAgICAgICogQHBhcmFtICB7T2JqZWN0fSBvcHRpb25zIEFkZGl0aW9uYWwgb3B0aW9ucyB0byBjaGFuZ2UgdGhlIHByZXNlbmNlIHNlcnZpY2UgZGVmYXVsdHMuXG4gICAgICAgICAqIEByZXR1cm4ge1Byb21pc2V9IHByb21pc2VcbiAgICAgICAgICovXG4gICAgICAgIG1hcmtPZmZsaW5lOiBmdW5jdGlvbiAodXNlcklkLCBvcHRpb25zKSB7XG4gICAgICAgICAgICBvcHRpb25zID0gb3B0aW9ucyB8fCB7fTtcbiAgICAgICAgICAgIHZhciBpc1N0cmluZyA9IHR5cGVvZiB1c2VySWQgPT09ICdzdHJpbmcnO1xuICAgICAgICAgICAgdmFyIG9ialBhcmFtcyA9IGdldEZpbmFsUGFyYW1zKHVzZXJJZCk7XG4gICAgICAgICAgICBpZiAoIW9ialBhcmFtcy5ncm91cE5hbWUgJiYgIW9wdGlvbnMuZ3JvdXBOYW1lKSB7XG4gICAgICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdObyBncm91cE5hbWUgc3BlY2lmaWVkLicpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgdXNlcklkID0gaXNTdHJpbmcgPyB1c2VySWQgOiBvYmpQYXJhbXMudXNlcklkO1xuICAgICAgICAgICAgdmFyIGdyb3VwTmFtZSA9IG9wdGlvbnMuZ3JvdXBOYW1lIHx8IG9ialBhcmFtcy5ncm91cE5hbWU7XG4gICAgICAgICAgICB2YXIgaHR0cE9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSwgc2VydmljZU9wdGlvbnMsIG9wdGlvbnMsXG4gICAgICAgICAgICAgICAgeyB1cmw6IHVybENvbmZpZy5nZXRBUElQYXRoKGFwaUVuZHBvaW50KSArIGdyb3VwTmFtZSArICcvJyArIHVzZXJJZCB9XG4gICAgICAgICAgICApO1xuICAgICAgICAgICAgcmV0dXJuIGh0dHAuZGVsZXRlKHt9LCBodHRwT3B0aW9ucyk7XG4gICAgICAgIH0sXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIFJldHVybnMgYSBsaXN0IG9mIGFsbCBlbmQgdXNlcnMgaW4gdGhpcyBncm91cCB0aGF0IGFyZSBjdXJyZW50bHkgb25saW5lLlxuICAgICAgICAgKlxuICAgICAgICAgKlxuICAgICAgICAgKiAqKkV4YW1wbGUqKlxuICAgICAgICAgKlxuICAgICAgICAgKiAgICAgdmFyIHByID0gbmV3IEYuc2VydmljZS5QcmVzZW5jZSgpO1xuICAgICAgICAgKiAgICAgcHIuZ2V0U3RhdHVzKCdncm91cE5hbWUnKS50aGVuKGZ1bmN0aW9uKG9ubGluZVVzZXJzKSB7XG4gICAgICAgICAqICAgICAgICAgIGZvciAodmFyIGk9MDsgaSA8IG9ubGluZVVzZXJzLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgICAqICAgICAgICAgICAgICAgY29uc29sZS5sb2coJ3VzZXIgJywgb25saW5lVXNlcnNbaV0udXNlcklkLCBcbiAgICAgICAgICogICAgICAgICAgICAgICAgICAgICcgaXMgb25saW5lIGFzIG9mICcsIG9ubGluZVVzZXJzW2ldLmxhc3RNb2RpZmllZCk7XG4gICAgICAgICAqICAgICAgICAgIH1cbiAgICAgICAgICogICAgIH0pO1xuICAgICAgICAgKlxuICAgICAgICAgKiAqKlJldHVybiBWYWx1ZSoqXG4gICAgICAgICAqXG4gICAgICAgICAqIFByb21pc2Ugd2l0aCByZXNwb25zZSBvZiBvbmxpbmUgdXNlcnNcbiAgICAgICAgICpcbiAgICAgICAgICogKipQYXJhbWV0ZXJzKipcbiAgICAgICAgICpcbiAgICAgICAgICogQHBhcmFtICB7U3RyaW5nfSBncm91cE5hbWUgKG9wdGlvbmFsKSBJZiBub3QgcHJvdmlkZWQsIHRha2VuIGZyb20gc2Vzc2lvbiBjb29raWUuXG4gICAgICAgICAqIEBwYXJhbSAge09iamVjdH0gb3B0aW9ucyBBZGRpdGlvbmFsIG9wdGlvbnMgdG8gY2hhbmdlIHRoZSBwcmVzZW5jZSBzZXJ2aWNlIGRlZmF1bHRzLlxuICAgICAgICAgKiBAcmV0dXJuIHtQcm9taXNlfSBwcm9taXNlXG4gICAgICAgICAqL1xuICAgICAgICBnZXRTdGF0dXM6IGZ1bmN0aW9uIChncm91cE5hbWUsIG9wdGlvbnMpIHtcbiAgICAgICAgICAgIG9wdGlvbnMgPSBvcHRpb25zIHx8IHt9O1xuICAgICAgICAgICAgdmFyIG9ialBhcmFtcyA9IGdldEZpbmFsUGFyYW1zKGdyb3VwTmFtZSk7XG4gICAgICAgICAgICBpZiAoIWdyb3VwTmFtZSAmJiAhb2JqUGFyYW1zLmdyb3VwTmFtZSkge1xuICAgICAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcignTm8gZ3JvdXBOYW1lIHNwZWNpZmllZC4nKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGdyb3VwTmFtZSA9IGdyb3VwTmFtZSB8fCBvYmpQYXJhbXMuZ3JvdXBOYW1lO1xuICAgICAgICAgICAgdmFyIGh0dHBPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sIHNlcnZpY2VPcHRpb25zLCBvcHRpb25zLFxuICAgICAgICAgICAgICAgIHsgdXJsOiB1cmxDb25maWcuZ2V0QVBJUGF0aChhcGlFbmRwb2ludCkgKyBncm91cE5hbWUgfVxuICAgICAgICAgICAgKTtcbiAgICAgICAgICAgIHJldHVybiBodHRwLmdldCh7fSwgaHR0cE9wdGlvbnMpO1xuICAgICAgICB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBFbmQgdXNlcnMgYXJlIGF1dG9tYXRpY2FsbHkgbWFya2VkIG9ubGluZSBhbmQgb2ZmbGluZSBpbiBhIFwicHJlc2VuY2VcIiBjaGFubmVsIHRoYXQgaXMgc3BlY2lmaWMgdG8gZWFjaCBncm91cC4gR2V0cyB0aGlzIGNoYW5uZWwgKGFuIGluc3RhbmNlIG9mIHRoZSBbQ2hhbm5lbCBTZXJ2aWNlXSguLi9jaGFubmVsLXNlcnZpY2UvKSkgZm9yIHRoZSBnaXZlbiBncm91cC4gKE5vdGUgdGhhdCB0aGlzIENoYW5uZWwgU2VydmljZSBpbnN0YW5jZSBpcyBhbHNvIGF2YWlsYWJsZSBmcm9tIHRoZSBbRXBpY2VudGVyIENoYW5uZWwgTWFuYWdlciBnZXRQcmVzZW5jZUNoYW5uZWwoKV0oLi4vZXBpY2VudGVyLWNoYW5uZWwtbWFuYWdlci8jZ2V0UHJlc2VuY2VDaGFubmVsKS4pXG4gICAgICAgICAqXG4gICAgICAgICAqXG4gICAgICAgICAqICoqRXhhbXBsZSoqXG4gICAgICAgICAqXG4gICAgICAgICAqICAgICB2YXIgcHIgPSBuZXcgRi5zZXJ2aWNlLlByZXNlbmNlKCk7XG4gICAgICAgICAqICAgICB2YXIgY20gPSBwci5nZXRDaGFubmVsKCdncm91cDEnKTtcbiAgICAgICAgICogICAgIGNtLnB1Ymxpc2goJycsICdhIG1lc3NhZ2UgdG8gcHJlc2VuY2UgY2hhbm5lbCcpO1xuICAgICAgICAgKlxuICAgICAgICAgKiAqKlJldHVybiBWYWx1ZSoqXG4gICAgICAgICAqXG4gICAgICAgICAqIENoYW5uZWwgaW5zdGFuY2UgZm9yIFByZXNlbmNlIGNoYW5uZWxcbiAgICAgICAgICpcbiAgICAgICAgICogKipQYXJhbWV0ZXJzKipcbiAgICAgICAgICpcbiAgICAgICAgICogQHBhcmFtICB7U3RyaW5nfSBncm91cE5hbWUgKG9wdGlvbmFsKSBJZiBub3QgcHJvdmlkZWQsIHRha2VuIGZyb20gc2Vzc2lvbiBjb29raWUuXG4gICAgICAgICAqIEBwYXJhbSAge09iamVjdH0gb3B0aW9ucyBBZGRpdGlvbmFsIG9wdGlvbnMgdG8gY2hhbmdlIHRoZSBwcmVzZW5jZSBzZXJ2aWNlIGRlZmF1bHRzXG4gICAgICAgICAqIEByZXR1cm4ge0NoYW5uZWx9IENoYW5uZWwgaW5zdGFuY2VcbiAgICAgICAgICovXG4gICAgICAgIGdldENoYW5uZWw6IGZ1bmN0aW9uIChncm91cE5hbWUsIG9wdGlvbnMpIHtcbiAgICAgICAgICAgIG9wdGlvbnMgPSBvcHRpb25zIHx8IHt9O1xuICAgICAgICAgICAgdmFyIGlzU3RyaW5nID0gdHlwZW9mIGdyb3VwTmFtZSA9PT0gJ3N0cmluZyc7XG4gICAgICAgICAgICB2YXIgb2JqUGFyYW1zID0gZ2V0RmluYWxQYXJhbXMoZ3JvdXBOYW1lKTtcbiAgICAgICAgICAgIGlmICghaXNTdHJpbmcgJiYgIW9ialBhcmFtcy5ncm91cE5hbWUpIHtcbiAgICAgICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ05vIGdyb3VwTmFtZSBzcGVjaWZpZWQuJyk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBncm91cE5hbWUgPSBpc1N0cmluZyA/IGdyb3VwTmFtZSA6IG9ialBhcmFtcy5ncm91cE5hbWU7XG4gICAgICAgICAgICB2YXIgY20gPSBuZXcgQ2hhbm5lbE1hbmFnZXIob3B0aW9ucyk7XG4gICAgICAgICAgICByZXR1cm4gY20uZ2V0UHJlc2VuY2VDaGFubmVsKGdyb3VwTmFtZSk7XG4gICAgICAgIH1cbiAgICB9O1xuXG4gICAgJC5leHRlbmQodGhpcywgcHVibGljQVBJKTtcbn07XG4iLCIvKipcbiAqXG4gKiAjIyBSdW4gQVBJIFNlcnZpY2VcbiAqXG4gKiBUaGUgUnVuIEFQSSBTZXJ2aWNlIGFsbG93cyB5b3UgdG8gcGVyZm9ybSBjb21tb24gdGFza3MgYXJvdW5kIGNyZWF0aW5nIGFuZCB1cGRhdGluZyBydW5zLCB2YXJpYWJsZXMsIGFuZCBkYXRhLlxuICpcbiAqIFdoZW4gYnVpbGRpbmcgaW50ZXJmYWNlcyB0byBzaG93IHJ1biBvbmUgYXQgYSB0aW1lIChhcyBmb3Igc3RhbmRhcmQgZW5kIHVzZXJzKSwgdHlwaWNhbGx5IHlvdSBmaXJzdCBpbnN0YW50aWF0ZSBhIFtSdW4gTWFuYWdlcl0oLi4vcnVuLW1hbmFnZXIvKSBhbmQgdGhlbiBhY2Nlc3MgdGhlIFJ1biBTZXJ2aWNlIHRoYXQgaXMgYXV0b21hdGljYWxseSBwYXJ0IG9mIHRoZSBtYW5hZ2VyLCByYXRoZXIgdGhhbiBpbnN0YW50aWF0aW5nIHRoZSBSdW4gU2VydmljZSBkaXJlY3RseS4gVGhpcyBpcyBiZWNhdXNlIHRoZSBSdW4gTWFuYWdlciAoYW5kIGFzc29jaWF0ZWQgW3J1biBzdHJhdGVnaWVzXSguLi9zdHJhdGVnaWVzLykpIGdpdmVzIHlvdSBjb250cm9sIG92ZXIgcnVuIGNyZWF0aW9uIGRlcGVuZGluZyBvbiBydW4gc3RhdGVzLlxuICpcbiAqIFRoZSBSdW4gQVBJIFNlcnZpY2UgaXMgdXNlZnVsIGZvciBidWlsZGluZyBhbiBpbnRlcmZhY2Ugd2hlcmUgeW91IHdhbnQgdG8gc2hvdyBkYXRhIGFjcm9zcyBtdWx0aXBsZSBydW5zICh0aGlzIGlzIGVhc3kgdXNpbmcgdGhlIGBmaWx0ZXIoKWAgYW5kIGBxdWVyeSgpYCBtZXRob2RzKS4gRm9yIGluc3RhbmNlLCB5b3Ugd291bGQgcHJvYmFibHkgdXNlIGEgUnVuIFNlcnZpY2UgdG8gYnVpbGQgYSBwYWdlIGZvciBhIGZhY2lsaXRhdG9yLiBUaGlzIGlzIGJlY2F1c2UgYSBmYWNpbGl0YXRvciB0eXBpY2FsbHkgd2FudHMgdG8gZXZhbHVhdGUgcGVyZm9ybWFuY2UgZnJvbSBtdWx0aXBsZSBlbmQgdXNlcnMsIGVhY2ggb2Ygd2hvbSBoYXZlIGJlZW4gd29ya2luZyB3aXRoIHRoZWlyIG93biBydW4uXG4gKlxuICogVG8gdXNlIHRoZSBSdW4gQVBJIFNlcnZpY2UsIGluc3RhbnRpYXRlIGl0IGJ5IHBhc3NpbmcgaW46XG4gKlxuICogKiBgYWNjb3VudGA6IEVwaWNlbnRlciBhY2NvdW50IGlkICgqKlRlYW0gSUQqKiBmb3IgdGVhbSBwcm9qZWN0cywgKipVc2VyIElEKiogZm9yIHBlcnNvbmFsIHByb2plY3RzKS5cbiAqICogYHByb2plY3RgOiBFcGljZW50ZXIgcHJvamVjdCBpZC5cbiAqXG4gKiBJZiB5b3Uga25vdyBpbiBhZHZhbmNlIHRoYXQgeW91IHdvdWxkIGxpa2UgdG8gd29yayB3aXRoIHBhcnRpY3VsYXIsIGV4aXN0aW5nIHJ1bihzKSwgeW91IGNhbiBvcHRpb25hbGx5IHBhc3MgaW46XG4gKlxuICogKiBgZmlsdGVyYDogKE9wdGlvbmFsKSBDcml0ZXJpYSBieSB3aGljaCB0byBmaWx0ZXIgZm9yIGV4aXN0aW5nIHJ1bnMuIFxuICogKiBgaWRgOiAoT3B0aW9uYWwpIFRoZSBydW4gaWQgb2YgYW4gZXhpc3RpbmcgcnVuLiBUaGlzIGlzIGEgY29udmVuaWVuY2UgYWxpYXMgZm9yIHVzaW5nIGZpbHRlciwgaW4gdGhlIGNhc2Ugd2hlcmUgeW91IG9ubHkgd2FudCB0byB3b3JrIHdpdGggb25lIHJ1bi5cbiAqXG4gKiBGb3IgZXhhbXBsZSxcbiAqXG4gKiAgICAgICB2YXIgcnMgPSBuZXcgRi5zZXJ2aWNlLlJ1bih7XG4gKiAgICAgICAgICAgIGFjY291bnQ6ICdhY21lLXNpbXVsYXRpb25zJyxcbiAqICAgICAgICAgICAgcHJvamVjdDogJ3N1cHBseS1jaGFpbi1nYW1lJyxcbiAqICAgICAgfSk7XG4gKiAgICAgIHJzLmNyZWF0ZSgnc3VwcGx5X2NoYWluX2dhbWUucHknKS50aGVuKGZ1bmN0aW9uKHJ1bikge1xuICogICAgICAgICAgICAgcnMuZG8oJ3NvbWVPcGVyYXRpb24nKTtcbiAqICAgICAgfSk7XG4gKlxuICpcbiAqIEFkZGl0aW9uYWxseSwgYWxsIEFQSSBjYWxscyB0YWtlIGluIGFuIGBvcHRpb25zYCBvYmplY3QgYXMgdGhlIGxhc3QgcGFyYW1ldGVyLiBUaGUgb3B0aW9ucyBjYW4gYmUgdXNlZCB0byBleHRlbmQvb3ZlcnJpZGUgdGhlIFJ1biBBUEkgU2VydmljZSBkZWZhdWx0cyBsaXN0ZWQgYmVsb3cuIEluIHBhcnRpY3VsYXIsIHBhc3NpbmcgYHsgaWQ6ICdhLXJ1bi1pZCcgfWAgaW4gdGhpcyBgb3B0aW9uc2Agb2JqZWN0IGFsbG93cyB5b3UgdG8gbWFrZSBjYWxscyB0byBhbiBleGlzdGluZyBydW4uXG4gKlxuICogTm90ZSB0aGF0IGluIGFkZGl0aW9uIHRvIHRoZSBgYWNjb3VudGAsIGBwcm9qZWN0YCwgYW5kIGBtb2RlbGAsIHRoZSBSdW4gU2VydmljZSBwYXJhbWV0ZXJzIG9wdGlvbmFsbHkgaW5jbHVkZSBhIGBzZXJ2ZXJgIG9iamVjdCwgd2hvc2UgYGhvc3RgIGZpZWxkIGNvbnRhaW5zIHRoZSBVUkkgb2YgdGhlIEZvcmlvIHNlcnZlci4gVGhpcyBpcyBhdXRvbWF0aWNhbGx5IHNldCwgYnV0IHlvdSBjYW4gcGFzcyBpdCBleHBsaWNpdGx5IGlmIGRlc2lyZWQuIEl0IGlzIG1vc3QgY29tbW9ubHkgdXNlZCBmb3IgY2xhcml0eSB3aGVuIHlvdSBhcmUgW2hvc3RpbmcgYW4gRXBpY2VudGVyIHByb2plY3Qgb24geW91ciBvd24gc2VydmVyXSguLi8uLi8uLi9ob3dfdG8vc2VsZl9ob3N0aW5nLykuXG4gKlxuICogICAgICAgdmFyIHJtID0gbmV3IEYubWFuYWdlci5SdW5NYW5hZ2VyKHtcbiAqICAgICAgICAgICBydW46IHtcbiAqICAgICAgICAgICAgICAgYWNjb3VudDogJ2FjbWUtc2ltdWxhdGlvbnMnLFxuICogICAgICAgICAgICAgICBwcm9qZWN0OiAnc3VwcGx5LWNoYWluLWdhbWUnLFxuICogICAgICAgICAgICAgICBtb2RlbDogJ3N1cHBseV9jaGFpbl9nYW1lLnB5JyxcbiAqICAgICAgICAgICAgICAgc2VydmVyOiB7IGhvc3Q6ICdhcGkuZm9yaW8uY29tJyB9XG4gKiAgICAgICAgICAgfVxuICogICAgICAgfSk7XG4gKiAgICAgICBybS5nZXRSdW4oKVxuICogICAgICAgICAgIC50aGVuKGZ1bmN0aW9uKHJ1bikge1xuICogICAgICAgICAgICAgICAvLyB0aGUgUnVuTWFuYWdlci5ydW4gY29udGFpbnMgdGhlIGluc3RhbnRpYXRlZCBSdW4gU2VydmljZSxcbiAqICAgICAgICAgICAgICAgLy8gc28gYW55IFJ1biBTZXJ2aWNlIG1ldGhvZCBpcyB2YWxpZCBoZXJlXG4gKiAgICAgICAgICAgICAgIHZhciBycyA9IHJtLnJ1bjtcbiAqICAgICAgICAgICAgICAgcnMuZG8oJ3NvbWVPcGVyYXRpb24nKTtcbiAqICAgICAgIH0pXG4gKlxuICovXG5cbid1c2Ugc3RyaWN0JztcblxudmFyIENvbmZpZ1NlcnZpY2UgPSByZXF1aXJlKCcuL2NvbmZpZ3VyYXRpb24tc2VydmljZScpO1xudmFyIHF1dGlsID0gcmVxdWlyZSgnLi4vdXRpbC9xdWVyeS11dGlsJyk7XG52YXIgcnV0aWwgPSByZXF1aXJlKCcuLi91dGlsL3J1bi11dGlsJyk7XG52YXIgX3BpY2sgPSByZXF1aXJlKCcuLi91dGlsL29iamVjdC11dGlsJykuX3BpY2s7XG52YXIgVHJhbnNwb3J0RmFjdG9yeSA9IHJlcXVpcmUoJy4uL3RyYW5zcG9ydC9odHRwLXRyYW5zcG9ydC1mYWN0b3J5Jyk7XG52YXIgVmFyaWFibGVzU2VydmljZSA9IHJlcXVpcmUoJy4vdmFyaWFibGVzLWFwaS1zZXJ2aWNlJyk7XG52YXIgSW50cm9zcGVjdGlvblNlcnZpY2UgPSByZXF1aXJlKCcuL2ludHJvc3BlY3Rpb24tYXBpLXNlcnZpY2UnKTtcbnZhciBTZXNzaW9uTWFuYWdlciA9IHJlcXVpcmUoJy4uL3N0b3JlL3Nlc3Npb24tbWFuYWdlcicpO1xuXG5tb2R1bGUuZXhwb3J0cyA9IGZ1bmN0aW9uIChjb25maWcpIHtcbiAgICB2YXIgZGVmYXVsdHMgPSB7XG4gICAgICAgIC8qKlxuICAgICAgICAgKiBGb3IgcHJvamVjdHMgdGhhdCByZXF1aXJlIGF1dGhlbnRpY2F0aW9uLCBwYXNzIGluIHRoZSB1c2VyIGFjY2VzcyB0b2tlbiAoZGVmYXVsdHMgdG8gdW5kZWZpbmVkKS4gSWYgdGhlIHVzZXIgaXMgYWxyZWFkeSBsb2dnZWQgaW4gdG8gRXBpY2VudGVyLCB0aGUgdXNlciBhY2Nlc3MgdG9rZW4gaXMgYWxyZWFkeSBzZXQgaW4gYSBjb29raWUgYW5kIGF1dG9tYXRpY2FsbHkgbG9hZGVkIGZyb20gdGhlcmUuIChTZWUgW21vcmUgYmFja2dyb3VuZCBvbiBhY2Nlc3MgdG9rZW5zXSguLi8uLi8uLi9wcm9qZWN0X2FjY2Vzcy8pKS5cbiAgICAgICAgICogQHNlZSBbQXV0aGVudGljYXRpb24gQVBJIFNlcnZpY2VdKC4uL2F1dGgtYXBpLXNlcnZpY2UvKSBmb3IgZ2V0dGluZyB0b2tlbnMuXG4gICAgICAgICAqIEB0eXBlIHtTdHJpbmd9XG4gICAgICAgICAqL1xuICAgICAgICB0b2tlbjogdW5kZWZpbmVkLFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBUaGUgYWNjb3VudCBpZC4gSW4gdGhlIEVwaWNlbnRlciBVSSwgdGhpcyBpcyB0aGUgKipUZWFtIElEKiogKGZvciB0ZWFtIHByb2plY3RzKSBvciAqKlVzZXIgSUQqKiAoZm9yIHBlcnNvbmFsIHByb2plY3RzKS4gRGVmYXVsdHMgdG8gdW5kZWZpbmVkLiBJZiBsZWZ0IHVuZGVmaW5lZCwgdGFrZW4gZnJvbSB0aGUgVVJMLlxuICAgICAgICAgKiBAdHlwZSB7U3RyaW5nfVxuICAgICAgICAgKi9cbiAgICAgICAgYWNjb3VudDogdW5kZWZpbmVkLFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBUaGUgcHJvamVjdCBpZC4gRGVmYXVsdHMgdG8gdW5kZWZpbmVkLiBJZiBsZWZ0IHVuZGVmaW5lZCwgdGFrZW4gZnJvbSB0aGUgVVJMLlxuICAgICAgICAgKiBAdHlwZSB7U3RyaW5nfVxuICAgICAgICAgKi9cbiAgICAgICAgcHJvamVjdDogdW5kZWZpbmVkLFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBDcml0ZXJpYSBieSB3aGljaCB0byBmaWx0ZXIgcnVucy4gRGVmYXVsdHMgdG8gZW1wdHkgc3RyaW5nLlxuICAgICAgICAgKiBAdHlwZSB7U3RyaW5nfVxuICAgICAgICAgKi9cbiAgICAgICAgZmlsdGVyOiAnJyxcblxuICAgICAgICAvKipcbiAgICAgICAgICogQ29udmVuaWVuY2UgYWxpYXMgZm9yIGZpbHRlci4gUGFzcyBpbiBhbiBleGlzdGluZyBydW4gaWQgdG8gaW50ZXJhY3Qgd2l0aCBhIHBhcnRpY3VsYXIgcnVuLlxuICAgICAgICAgKiBAdHlwZSB7U3RyaW5nfVxuICAgICAgICAgKi9cbiAgICAgICAgaWQ6ICcnLFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBGbGFnIGRldGVybWluZXMgaWYgYFgtQXV0b1Jlc3RvcmU6IHRydWVgIGhlYWRlciBpcyBzZW50IHRvIEVwaWNlbnRlciwgbWVhbmluZyBydW5zIGFyZSBhdXRvbWF0aWNhbGx5IHB1bGxlZCBmcm9tIHRoZSBFcGljZW50ZXIgYmFja2VuZCBkYXRhYmFzZSBpZiBub3QgY3VycmVudGx5IGluIG1lbW9yeSBvbiB0aGUgRXBpY2VudGVyIHNlcnZlcnMuIERlZmF1bHRzIHRvIGB0cnVlYC5cbiAgICAgICAgICogQHR5cGUge2Jvb2xlYW59XG4gICAgICAgICAqL1xuICAgICAgICBhdXRvUmVzdG9yZTogdHJ1ZSxcblxuICAgICAgICAvKipcbiAgICAgICAgICogQ2FsbGVkIHdoZW4gdGhlIGNhbGwgY29tcGxldGVzIHN1Y2Nlc3NmdWxseS4gRGVmYXVsdHMgdG8gYCQubm9vcGAuXG4gICAgICAgICAqIEB0eXBlIHtmdW5jdGlvbn1cbiAgICAgICAgICovXG4gICAgICAgIHN1Y2Nlc3M6ICQubm9vcCxcblxuICAgICAgICAvKipcbiAgICAgICAgICogQ2FsbGVkIHdoZW4gdGhlIGNhbGwgZmFpbHMuIERlZmF1bHRzIHRvIGAkLm5vb3BgLlxuICAgICAgICAgKiBAdHlwZSB7ZnVuY3Rpb259XG4gICAgICAgICAqL1xuICAgICAgICBlcnJvcjogJC5ub29wLFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBPcHRpb25zIHRvIHBhc3Mgb24gdG8gdGhlIHVuZGVybHlpbmcgdHJhbnNwb3J0IGxheWVyLiBBbGwganF1ZXJ5LmFqYXggb3B0aW9ucyBhdCBodHRwOi8vYXBpLmpxdWVyeS5jb20valF1ZXJ5LmFqYXgvIGFyZSBhdmFpbGFibGUuIERlZmF1bHRzIHRvIGVtcHR5IG9iamVjdC5cbiAgICAgICAgICogQHR5cGUge09iamVjdH1cbiAgICAgICAgICovXG4gICAgICAgIHRyYW5zcG9ydDoge31cbiAgICB9O1xuXG4gICAgdGhpcy5zZXNzaW9uTWFuYWdlciA9IG5ldyBTZXNzaW9uTWFuYWdlcigpO1xuICAgIHZhciBzZXJ2aWNlT3B0aW9ucyA9IHRoaXMuc2Vzc2lvbk1hbmFnZXIuZ2V0TWVyZ2VkT3B0aW9ucyhkZWZhdWx0cywgY29uZmlnKTtcbiAgICBpZiAoc2VydmljZU9wdGlvbnMuaWQpIHtcbiAgICAgICAgc2VydmljZU9wdGlvbnMuZmlsdGVyID0gc2VydmljZU9wdGlvbnMuaWQ7XG4gICAgfVxuXG4gICAgZnVuY3Rpb24gdXBkYXRlVVJMQ29uZmlnKG9wdHMpIHtcbiAgICAgICAgdmFyIHVybENvbmZpZyA9IG5ldyBDb25maWdTZXJ2aWNlKG9wdHMpLmdldCgnc2VydmVyJyk7XG4gICAgICAgIGlmIChvcHRzLmFjY291bnQpIHtcbiAgICAgICAgICAgIHVybENvbmZpZy5hY2NvdW50UGF0aCA9IG9wdHMuYWNjb3VudDtcbiAgICAgICAgfVxuICAgICAgICBpZiAob3B0cy5wcm9qZWN0KSB7XG4gICAgICAgICAgICB1cmxDb25maWcucHJvamVjdFBhdGggPSBvcHRzLnByb2plY3Q7XG4gICAgICAgIH1cblxuICAgICAgICB1cmxDb25maWcuZmlsdGVyID0gJzsnO1xuICAgICAgICB1cmxDb25maWcuZ2V0RmlsdGVyVVJMID0gZnVuY3Rpb24gKGZpbHRlcikge1xuICAgICAgICAgICAgdmFyIHVybCA9IHVybENvbmZpZy5nZXRBUElQYXRoKCdydW4nKTtcbiAgICAgICAgICAgIHZhciBmaWx0ZXJNYXRyaXggPSBxdXRpbC50b01hdHJpeEZvcm1hdChmaWx0ZXIgfHwgb3B0cy5maWx0ZXIpO1xuXG4gICAgICAgICAgICBpZiAoZmlsdGVyTWF0cml4KSB7XG4gICAgICAgICAgICAgICAgdXJsICs9IGZpbHRlck1hdHJpeCArICcvJztcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHJldHVybiB1cmw7XG4gICAgICAgIH07XG5cbiAgICAgICAgdXJsQ29uZmlnLmFkZEF1dG9SZXN0b3JlSGVhZGVyID0gZnVuY3Rpb24gKG9wdGlvbnMpIHtcbiAgICAgICAgICAgIHZhciBmaWx0ZXIgPSBvcHRzLmZpbHRlcjtcbiAgICAgICAgICAgIC8vIFRoZSBzZW1pY29sb24gc2VwYXJhdGVkIGZpbHRlciBpcyB1c2VkIHdoZW4gZmlsdGVyIGlzIGFuIG9iamVjdFxuICAgICAgICAgICAgdmFyIGlzRmlsdGVyUnVuSWQgPSBmaWx0ZXIgJiYgJC50eXBlKGZpbHRlcikgPT09ICdzdHJpbmcnO1xuICAgICAgICAgICAgaWYgKG9wdHMuYXV0b1Jlc3RvcmUgJiYgaXNGaWx0ZXJSdW5JZCkge1xuICAgICAgICAgICAgICAgIC8vIEJ5IGRlZmF1bHQgYXV0b3JlcGxheSB0aGUgcnVuIGJ5IHNlbmRpbmcgdGhpcyBoZWFkZXIgdG8gZXBpY2VudGVyXG4gICAgICAgICAgICAgICAgLy8gaHR0cHM6Ly9mb3Jpby5jb20vZXBpY2VudGVyL2RvY3MvcHVibGljL3Jlc3RfYXBpcy9hZ2dyZWdhdGVfcnVuX2FwaS8jcmV0cmlldmluZ1xuICAgICAgICAgICAgICAgIHZhciBhdXRvcmVzdG9yZU9wdHMgPSB7XG4gICAgICAgICAgICAgICAgICAgIGhlYWRlcnM6IHtcbiAgICAgICAgICAgICAgICAgICAgICAgICdYLUF1dG9SZXN0b3JlJzogdHJ1ZVxuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgfTtcbiAgICAgICAgICAgICAgICByZXR1cm4gJC5leHRlbmQodHJ1ZSwgYXV0b3Jlc3RvcmVPcHRzLCBvcHRpb25zKTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgcmV0dXJuIG9wdGlvbnM7XG4gICAgICAgIH07XG4gICAgICAgIHJldHVybiB1cmxDb25maWc7XG4gICAgfVxuXG4gICAgdmFyIGh0dHA7XG4gICAgdmFyIGh0dHBPcHRpb25zOyAvL0ZJWE1FOiBNYWtlIHRoaXMgc2lkZS1lZmZlY3QtbGVzc1xuICAgIGZ1bmN0aW9uIHVwZGF0ZUhUVFBDb25maWcoc2VydmljZU9wdGlvbnMsIHVybENvbmZpZykge1xuICAgICAgICBodHRwT3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LCBzZXJ2aWNlT3B0aW9ucy50cmFuc3BvcnQsIHtcbiAgICAgICAgICAgIHVybDogdXJsQ29uZmlnLmdldEZpbHRlclVSTFxuICAgICAgICB9KTtcblxuICAgICAgICBpZiAoc2VydmljZU9wdGlvbnMudG9rZW4pIHtcbiAgICAgICAgICAgIGh0dHBPcHRpb25zLmhlYWRlcnMgPSB7XG4gICAgICAgICAgICAgICAgQXV0aG9yaXphdGlvbjogJ0JlYXJlciAnICsgc2VydmljZU9wdGlvbnMudG9rZW5cbiAgICAgICAgICAgIH07XG4gICAgICAgIH1cbiAgICAgICAgaHR0cCA9IG5ldyBUcmFuc3BvcnRGYWN0b3J5KGh0dHBPcHRpb25zKTtcbiAgICAgICAgaHR0cC5zcGxpdEdldCA9IHJ1dGlsLnNwbGl0R2V0RmFjdG9yeShodHRwT3B0aW9ucyk7XG4gICAgfVxuXG4gICAgdmFyIHVybENvbmZpZyA9IHVwZGF0ZVVSTENvbmZpZyhzZXJ2aWNlT3B0aW9ucyk7IC8vbWFraW5nIGEgZnVuY3Rpb24gc28gI3VwZGF0ZUNvbmZpZyBjYW4gY2FsbCB0aGlzOyBjaGFuZ2Ugd2hlbiByZWZhY3RvcmVkXG4gICAgdXBkYXRlSFRUUENvbmZpZyhzZXJ2aWNlT3B0aW9ucywgdXJsQ29uZmlnKTtcbiAgIFxuXG4gICAgZnVuY3Rpb24gc2V0RmlsdGVyT3JUaHJvd0Vycm9yKG9wdGlvbnMpIHtcbiAgICAgICAgaWYgKG9wdGlvbnMuaWQpIHtcbiAgICAgICAgICAgIHNlcnZpY2VPcHRpb25zLmZpbHRlciA9IHNlcnZpY2VPcHRpb25zLmlkID0gb3B0aW9ucy5pZDtcbiAgICAgICAgfVxuICAgICAgICBpZiAob3B0aW9ucy5maWx0ZXIpIHtcbiAgICAgICAgICAgIHNlcnZpY2VPcHRpb25zLmZpbHRlciA9IHNlcnZpY2VPcHRpb25zLmlkID0gb3B0aW9ucy5maWx0ZXI7XG4gICAgICAgIH1cbiAgICAgICAgaWYgKCFzZXJ2aWNlT3B0aW9ucy5maWx0ZXIpIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcignTm8gZmlsdGVyIHNwZWNpZmllZCB0byBhcHBseSBvcGVyYXRpb25zIGFnYWluc3QnKTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIHZhciBwdWJsaWNBc3luY0FQSSA9IHtcbiAgICAgICAgdXJsQ29uZmlnOiB1cmxDb25maWcsXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIENyZWF0ZSBhIG5ldyBydW4uXG4gICAgICAgICAqXG4gICAgICAgICAqIE5PVEU6IFR5cGljYWxseSB0aGlzIGlzIG5vdCB1c2VkISBVc2UgYFJ1bk1hbmFnZXIuZ2V0UnVuKClgIHdpdGggYSBgc3RyYXRlZ3lgIG9mIGByZXVzZS1uZXZlcmAsIG9yIHVzZSBgUnVuTWFuYWdlci5yZXNldCgpYC4gU2VlIFtSdW4gTWFuYWdlcl0oLi4vcnVuLW1hbmFnZXIvKSBmb3IgbW9yZSBkZXRhaWxzLlxuICAgICAgICAgKlxuICAgICAgICAgKiAgKipFeGFtcGxlKipcbiAgICAgICAgICpcbiAgICAgICAgICogICAgICBycy5jcmVhdGUoJ2hlbGxvX3dvcmxkLmpsJyk7XG4gICAgICAgICAqXG4gICAgICAgICAqICAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAgKiBAcGFyYW0ge1N0cmluZ3xPYmplY3R9IHBhcmFtcyBJZiBhIHN0cmluZywgdGhlIG5hbWUgb2YgdGhlIHByaW1hcnkgW21vZGVsIGZpbGVdKC4uLy4uLy4uL3dyaXRpbmdfeW91cl9tb2RlbC8pLiBUaGlzIGlzIHRoZSBvbmUgZmlsZSBpbiB0aGUgcHJvamVjdCB0aGF0IGV4cGxpY2l0bHkgZXhwb3NlcyB2YXJpYWJsZXMgYW5kIG1ldGhvZHMsIGFuZCBpdCBtdXN0IGJlIHN0b3JlZCBpbiB0aGUgTW9kZWwgZm9sZGVyIG9mIHlvdXIgRXBpY2VudGVyIHByb2plY3QuIElmIGFuIG9iamVjdCwgbWF5IGluY2x1ZGUgYG1vZGVsYCwgYHNjb3BlYCwgYW5kIGBmaWxlc2AuIChTZWUgdGhlIFtSdW4gTWFuYWdlcl0oLi4vcnVuX21hbmFnZXIvKSBmb3IgbW9yZSBpbmZvcm1hdGlvbiBvbiBgc2NvcGVgIGFuZCBgZmlsZXNgLilcbiAgICAgICAgICogQHBhcmFtIHtPYmplY3R9IG9wdGlvbnMgKE9wdGlvbmFsKSBPdmVycmlkZXMgZm9yIGNvbmZpZ3VyYXRpb24gb3B0aW9ucy5cbiAgICAgICAgICogQHJldHVybiB7UHJvbWlzZX1cbiAgICAgICAgICovXG4gICAgICAgIGNyZWF0ZTogZnVuY3Rpb24gKHBhcmFtcywgb3B0aW9ucykge1xuICAgICAgICAgICAgdmFyIGNyZWF0ZU9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSwgc2VydmljZU9wdGlvbnMsIG9wdGlvbnMsIHsgdXJsOiB1cmxDb25maWcuZ2V0QVBJUGF0aCgncnVuJykgfSk7XG4gICAgICAgICAgICB2YXIgcnVuQXBpUGFyYW1zID0gWydtb2RlbCcsICdzY29wZScsICdmaWxlcycsICdlcGhlbWVyYWwnLCAnY2luRmlsZXMnXTtcbiAgICAgICAgICAgIGlmICh0eXBlb2YgcGFyYW1zID09PSAnc3RyaW5nJykge1xuICAgICAgICAgICAgICAgIC8vIHRoaXMgaXMganVzdCB0aGUgbW9kZWwgbmFtZVxuICAgICAgICAgICAgICAgIHBhcmFtcyA9IHsgbW9kZWw6IHBhcmFtcyB9O1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICAvLyB3aGl0ZWxpc3QgdGhlIGZpZWxkcyB0aGF0IHdlIGFjdHVhbGx5IGNhbiBzZW5kIHRvIHRoZSBhcGlcbiAgICAgICAgICAgICAgICBwYXJhbXMgPSBfcGljayhwYXJhbXMsIHJ1bkFwaVBhcmFtcyk7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIHZhciBvbGRTdWNjZXNzID0gY3JlYXRlT3B0aW9ucy5zdWNjZXNzO1xuICAgICAgICAgICAgY3JlYXRlT3B0aW9ucy5zdWNjZXNzID0gZnVuY3Rpb24gKHJlc3BvbnNlKSB7XG4gICAgICAgICAgICAgICAgc2VydmljZU9wdGlvbnMuZmlsdGVyID0gcmVzcG9uc2UuaWQ7IC8vYWxsIGZ1dHVyZSBjaGFpbmVkIGNhbGxzIHRvIG9wZXJhdGUgb24gdGhpcyBpZFxuICAgICAgICAgICAgICAgIHNlcnZpY2VPcHRpb25zLmlkID0gcmVzcG9uc2UuaWQ7XG4gICAgICAgICAgICAgICAgcmV0dXJuIG9sZFN1Y2Nlc3MuYXBwbHkodGhpcywgYXJndW1lbnRzKTtcbiAgICAgICAgICAgIH07XG5cbiAgICAgICAgICAgIHJldHVybiBodHRwLnBvc3QocGFyYW1zLCBjcmVhdGVPcHRpb25zKTtcbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgICogUmV0dXJucyBwYXJ0aWN1bGFyIHJ1bnMsIGJhc2VkIG9uIGNvbmRpdGlvbnMgc3BlY2lmaWVkIGluIHRoZSBgcXNgIG9iamVjdC5cbiAgICAgICAgICpcbiAgICAgICAgICogVGhlIGVsZW1lbnRzIG9mIHRoZSBgcXNgIG9iamVjdCBhcmUgQU5EZWQgdG9nZXRoZXIgd2l0aGluIGEgc2luZ2xlIGNhbGwgdG8gYC5xdWVyeSgpYC5cbiAgICAgICAgICpcbiAgICAgICAgICogKipFeGFtcGxlKipcbiAgICAgICAgICpcbiAgICAgICAgICogICAgICAvLyByZXR1cm5zIHJ1bnMgd2l0aCBzYXZlZCA9IHRydWUgYW5kIHZhcmlhYmxlcy5wcmljZSA+IDEsXG4gICAgICAgICAqICAgICAgLy8gd2hlcmUgdmFyaWFibGVzLnByaWNlIGhhcyBiZWVuIHBlcnNpc3RlZCAocmVjb3JkZWQpXG4gICAgICAgICAqICAgICAgLy8gaW4gdGhlIG1vZGVsLlxuICAgICAgICAgKiAgICAgcnMucXVlcnkoe1xuICAgICAgICAgKiAgICAgICAgICAnc2F2ZWQnOiAndHJ1ZScsXG4gICAgICAgICAqICAgICAgICAgICcucHJpY2UnOiAnPjEnXG4gICAgICAgICAqICAgICAgIH0sXG4gICAgICAgICAqICAgICAgIHtcbiAgICAgICAgICogICAgICAgICAgc3RhcnRyZWNvcmQ6IDIsXG4gICAgICAgICAqICAgICAgICAgIGVuZHJlY29yZDogNVxuICAgICAgICAgKiAgICAgICB9KTtcbiAgICAgICAgICpcbiAgICAgICAgICogKipQYXJhbWV0ZXJzKipcbiAgICAgICAgICogQHBhcmFtIHtPYmplY3R9IHFzIFF1ZXJ5IG9iamVjdC4gRWFjaCBrZXkgY2FuIGJlIGEgcHJvcGVydHkgb2YgdGhlIHJ1biBvciB0aGUgbmFtZSBvZiB2YXJpYWJsZSB0aGF0IGhhcyBiZWVuIHNhdmVkIGluIHRoZSBydW4gKHByZWZhY2VkIGJ5IGB2YXJpYWJsZXMuYCkuIEVhY2ggdmFsdWUgY2FuIGJlIGEgbGl0ZXJhbCB2YWx1ZSwgb3IgYSBjb21wYXJpc29uIG9wZXJhdG9yIGFuZCB2YWx1ZS4gKFNlZSBbbW9yZSBvbiBmaWx0ZXJpbmddKC4uLy4uLy4uL3Jlc3RfYXBpcy9hZ2dyZWdhdGVfcnVuX2FwaS8jZmlsdGVycykgYWxsb3dlZCBpbiB0aGUgdW5kZXJseWluZyBSdW4gQVBJLikgUXVlcnlpbmcgZm9yIHZhcmlhYmxlcyBpcyBhdmFpbGFibGUgZm9yIHJ1bnMgW2luIG1lbW9yeV0oLi4vLi4vLi4vcnVuX3BlcnNpc3RlbmNlLyNydW5zLWluLW1lbW9yeSkgYW5kIGZvciBydW5zIFtpbiB0aGUgZGF0YWJhc2VdKC4uLy4uLy4uL3J1bl9wZXJzaXN0ZW5jZS8jcnVucy1pbi1tZW1vcnkpIGlmIHRoZSB2YXJpYWJsZXMgYXJlIHBlcnNpc3RlZCAoZS5nLiB0aGF0IGhhdmUgYmVlbiBgcmVjb3JkYGVkIGluIHlvdXIgbW9kZWwgb3IgbWFya2VkIGZvciBzYXZpbmcgaW4geW91ciBbbW9kZWwgY29udGV4dCBmaWxlXSguLi8uLi8uLi9tb2RlbF9jb2RlL2NvbnRleHQvKSkuXG4gICAgICAgICAqIEBwYXJhbSB7T2JqZWN0fSBvdXRwdXRNb2RpZmllciAoT3B0aW9uYWwpIEF2YWlsYWJsZSBmaWVsZHMgaW5jbHVkZTogYHN0YXJ0cmVjb3JkYCwgYGVuZHJlY29yZGAsIGBzb3J0YCwgYW5kIGBkaXJlY3Rpb25gIChgYXNjYCBvciBgZGVzY2ApLlxuICAgICAgICAgKiBAcGFyYW0ge09iamVjdH0gb3B0aW9ucyAoT3B0aW9uYWwpIE92ZXJyaWRlcyBmb3IgY29uZmlndXJhdGlvbiBvcHRpb25zLlxuICAgICAgICAgKiBAcmV0dXJuIHtQcm9taXNlfVxuICAgICAgICAgKi9cbiAgICAgICAgcXVlcnk6IGZ1bmN0aW9uIChxcywgb3V0cHV0TW9kaWZpZXIsIG9wdGlvbnMpIHtcbiAgICAgICAgICAgIHZhciBodHRwT3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LCBzZXJ2aWNlT3B0aW9ucywgeyB1cmw6IHVybENvbmZpZy5nZXRGaWx0ZXJVUkwocXMpIH0sIG9wdGlvbnMpO1xuICAgICAgICAgICAgaHR0cE9wdGlvbnMgPSB1cmxDb25maWcuYWRkQXV0b1Jlc3RvcmVIZWFkZXIoaHR0cE9wdGlvbnMpO1xuXG4gICAgICAgICAgICByZXR1cm4gaHR0cC5zcGxpdEdldChvdXRwdXRNb2RpZmllciwgaHR0cE9wdGlvbnMpLnRoZW4oZnVuY3Rpb24gKHIpIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gKCQuaXNQbGFpbk9iamVjdChyKSAmJiBPYmplY3Qua2V5cyhyKS5sZW5ndGggPT09IDApID8gW10gOiByO1xuICAgICAgICAgICAgfSk7XG4gICAgICAgIH0sXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIFJldHVybnMgcGFydGljdWxhciBydW5zLCBiYXNlZCBvbiBjb25kaXRpb25zIHNwZWNpZmllZCBpbiB0aGUgYHFzYCBvYmplY3QuXG4gICAgICAgICAqXG4gICAgICAgICAqIFNpbWlsYXIgdG8gYC5xdWVyeSgpYC5cbiAgICAgICAgICpcbiAgICAgICAgICogKipQYXJhbWV0ZXJzKipcbiAgICAgICAgICogQHBhcmFtIHtPYmplY3R9IGZpbHRlciBGaWx0ZXIgb2JqZWN0LiBFYWNoIGtleSBjYW4gYmUgYSBwcm9wZXJ0eSBvZiB0aGUgcnVuIG9yIHRoZSBuYW1lIG9mIHZhcmlhYmxlIHRoYXQgaGFzIGJlZW4gc2F2ZWQgaW4gdGhlIHJ1biAocHJlZmFjZWQgYnkgYHZhcmlhYmxlcy5gKS4gRWFjaCB2YWx1ZSBjYW4gYmUgYSBsaXRlcmFsIHZhbHVlLCBvciBhIGNvbXBhcmlzb24gb3BlcmF0b3IgYW5kIHZhbHVlLiAoU2VlIFttb3JlIG9uIGZpbHRlcmluZ10oLi4vLi4vLi4vcmVzdF9hcGlzL2FnZ3JlZ2F0ZV9ydW5fYXBpLyNmaWx0ZXJzKSBhbGxvd2VkIGluIHRoZSB1bmRlcmx5aW5nIFJ1biBBUEkuKSBGaWx0ZXJpbmcgZm9yIHZhcmlhYmxlcyBpcyBhdmFpbGFibGUgZm9yIHJ1bnMgW2luIG1lbW9yeV0oLi4vLi4vLi4vcnVuX3BlcnNpc3RlbmNlLyNydW5zLWluLW1lbW9yeSkgYW5kIGZvciBydW5zIFtpbiB0aGUgZGF0YWJhc2VdKC4uLy4uLy4uL3J1bl9wZXJzaXN0ZW5jZS8jcnVucy1pbi1tZW1vcnkpIGlmIHRoZSB2YXJpYWJsZXMgYXJlIHBlcnNpc3RlZCAoZS5nLiB0aGF0IGhhdmUgYmVlbiBgcmVjb3JkYGVkIGluIHlvdXIgbW9kZWwgb3IgbWFya2VkIGZvciBzYXZpbmcgaW4geW91ciBbbW9kZWwgY29udGV4dCBmaWxlXSguLi8uLi8uLi9tb2RlbF9jb2RlL2NvbnRleHQvKSkuXG4gICAgICAgICAqIEBwYXJhbSB7T2JqZWN0fSBvdXRwdXRNb2RpZmllciAoT3B0aW9uYWwpIEF2YWlsYWJsZSBmaWVsZHMgaW5jbHVkZTogYHN0YXJ0cmVjb3JkYCwgYGVuZHJlY29yZGAsIGBzb3J0YCwgYW5kIGBkaXJlY3Rpb25gIChgYXNjYCBvciBgZGVzY2ApLlxuICAgICAgICAgKiBAcGFyYW0ge09iamVjdH0gb3B0aW9ucyAoT3B0aW9uYWwpIE92ZXJyaWRlcyBmb3IgY29uZmlndXJhdGlvbiBvcHRpb25zLlxuICAgICAgICAgKiBAcmV0dXJuIHtQcm9taXNlfVxuICAgICAgICAgKi9cbiAgICAgICAgZmlsdGVyOiBmdW5jdGlvbiAoZmlsdGVyLCBvdXRwdXRNb2RpZmllciwgb3B0aW9ucykge1xuICAgICAgICAgICAgaWYgKCQuaXNQbGFpbk9iamVjdChzZXJ2aWNlT3B0aW9ucy5maWx0ZXIpKSB7XG4gICAgICAgICAgICAgICAgJC5leHRlbmQoc2VydmljZU9wdGlvbnMuZmlsdGVyLCBmaWx0ZXIpO1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICBzZXJ2aWNlT3B0aW9ucy5maWx0ZXIgPSBmaWx0ZXI7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICB2YXIgaHR0cE9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSwgc2VydmljZU9wdGlvbnMsIG9wdGlvbnMpO1xuICAgICAgICAgICAgaHR0cE9wdGlvbnMgPSB1cmxDb25maWcuYWRkQXV0b1Jlc3RvcmVIZWFkZXIoaHR0cE9wdGlvbnMpO1xuICAgICAgICAgICAgcmV0dXJuIGh0dHAuc3BsaXRHZXQob3V0cHV0TW9kaWZpZXIsIGh0dHBPcHRpb25zKS50aGVuKGZ1bmN0aW9uIChyKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuICgkLmlzUGxhaW5PYmplY3QocikgJiYgT2JqZWN0LmtleXMocikubGVuZ3RoID09PSAwKSA/IFtdIDogcjtcbiAgICAgICAgICAgIH0pO1xuICAgICAgICB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBHZXQgZGF0YSBmb3IgYSBzcGVjaWZpYyBydW4uIFRoaXMgaW5jbHVkZXMgc3RhbmRhcmQgcnVuIGRhdGEgc3VjaCBhcyB0aGUgYWNjb3VudCwgbW9kZWwsIHByb2plY3QsIGFuZCBjcmVhdGVkIGFuZCBsYXN0IG1vZGlmaWVkIGRhdGVzLiBUbyByZXF1ZXN0IHNwZWNpZmljIG1vZGVsIHZhcmlhYmxlcyBvciBydW4gcmVjb3JkIHZhcmlhYmxlcywgcGFzcyB0aGVtIGFzIHBhcnQgb2YgdGhlIGBmaWx0ZXJzYCBwYXJhbWV0ZXIuXG4gICAgICAgICAqXG4gICAgICAgICAqIE5vdGUgdGhhdCBpZiB0aGUgcnVuIGlzIFtpbiBtZW1vcnldKC4uLy4uLy4uL3J1bl9wZXJzaXN0ZW5jZS8jcnVucy1pbi1tZW1vcnkpLCBhbnkgbW9kZWwgdmFyaWFibGVzIGFyZSBhdmFpbGFibGU7IGlmIHRoZSBydW4gaXMgW2luIHRoZSBkYXRhYmFzZV0oLi4vLi4vLi4vcnVuX3BlcnNpc3RlbmNlLyNydW5zLWluLWRiKSwgb25seSBtb2RlbCB2YXJpYWJsZXMgdGhhdCBoYXZlIGJlZW4gcGVyc2lzdGVkICZtZGFzaDsgdGhhdCBpcywgYHJlY29yZGBlZCBvciBzYXZlZCBpbiB5b3VyIG1vZGVsICZtZGFzaDsgYXJlIGF2YWlsYWJsZS5cbiAgICAgICAgICpcbiAgICAgICAgICogKipFeGFtcGxlKipcbiAgICAgICAgICpcbiAgICAgICAgICogICAgIHJzLmxvYWQoJ2JiNTg5Njc3LWQ0NzYtNDk3MS1hNjhlLTBjNThkMTkxZTQ1MCcsIHsgaW5jbHVkZTogWycucHJpY2UnLCAnLnNhbGVzJ10gfSk7XG4gICAgICAgICAqXG4gICAgICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICAgICAqIEBwYXJhbSB7U3RyaW5nfSBydW5JRCBUaGUgcnVuIGlkLlxuICAgICAgICAgKiBAcGFyYW0ge09iamVjdH0gZmlsdGVycyAoT3B0aW9uYWwpIE9iamVjdCBjb250YWluaW5nIGZpbHRlcnMgYW5kIG9wZXJhdGlvbiBtb2RpZmllcnMuIFVzZSBrZXkgYGluY2x1ZGVgIHRvIGxpc3QgbW9kZWwgdmFyaWFibGVzIHRoYXQgeW91IHdhbnQgdG8gaW5jbHVkZSBpbiB0aGUgcmVzcG9uc2UuIE90aGVyIGF2YWlsYWJsZSBmaWVsZHMgaW5jbHVkZTogYHN0YXJ0cmVjb3JkYCwgYGVuZHJlY29yZGAsIGBzb3J0YCwgYW5kIGBkaXJlY3Rpb25gIChgYXNjYCBvciBgZGVzY2ApLlxuICAgICAgICAgKiBAcGFyYW0ge09iamVjdH0gb3B0aW9ucyAoT3B0aW9uYWwpIE92ZXJyaWRlcyBmb3IgY29uZmlndXJhdGlvbiBvcHRpb25zLlxuICAgICAgICAgKiBAcmV0dXJuIHtQcm9taXNlfVxuICAgICAgICAgKi9cbiAgICAgICAgbG9hZDogZnVuY3Rpb24gKHJ1bklELCBmaWx0ZXJzLCBvcHRpb25zKSB7XG4gICAgICAgICAgICBpZiAocnVuSUQpIHtcbiAgICAgICAgICAgICAgICBzZXJ2aWNlT3B0aW9ucy5maWx0ZXIgPSBydW5JRDsgLy9zaG91bGRuJ3QgYmUgYWJsZSB0byBvdmVyLXJpZGVcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHZhciBodHRwT3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LCBzZXJ2aWNlT3B0aW9ucywgb3B0aW9ucyk7XG4gICAgICAgICAgICBodHRwT3B0aW9ucyA9IHVybENvbmZpZy5hZGRBdXRvUmVzdG9yZUhlYWRlcihodHRwT3B0aW9ucyk7XG4gICAgICAgICAgICByZXR1cm4gaHR0cC5nZXQoZmlsdGVycywgaHR0cE9wdGlvbnMpO1xuICAgICAgICB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBSZW1vdmVzIHNwZWNpZmllZCBydW5pZCBmcm9tIG1lbW9yeVxuICAgICAgICAgKlxuICAgICAgICAgKiAqKkV4YW1wbGUqKlxuICAgICAgICAgKlxuICAgICAgICAgKiAgICAgcnMucmVtb3ZlRnJvbU1lbW9yeSgnYmI1ODk2NzctZDQ3Ni00OTcxLWE2OGUtMGM1OGQxOTFlNDUwJyk7XG4gICAgICAgICAqXG4gICAgICAgICAqIFNlZSBbZGV0YWlscyBvbiBydW4gcGVyc2lzdGVuY2VdKC4uLy4uLy4uL3J1bl9wZXJzaXN0ZW5jZS8jcnVucy1pbi1tZW1vcnkpXG4gICAgICAgICAqIEBwYXJhbSAge1N0cmluZ30gW3J1bklEXSAgIGlkIG9mIHJ1biB0byByZW1vdmVcbiAgICAgICAgICogQHBhcmFtICB7T2JqZWN0fSBbZmlsdGVyc10gKE9wdGlvbmFsKSBPYmplY3QgY29udGFpbmluZyBmaWx0ZXJzIGFuZCBvcGVyYXRpb24gbW9kaWZpZXJzLiBVc2Uga2V5IGBpbmNsdWRlYCB0byBsaXN0IG1vZGVsIHZhcmlhYmxlcyB0aGF0IHlvdSB3YW50IHRvIGluY2x1ZGUgaW4gdGhlIHJlc3BvbnNlLiBPdGhlciBhdmFpbGFibGUgZmllbGRzIGluY2x1ZGU6IGBzdGFydHJlY29yZGAsIGBlbmRyZWNvcmRgLCBgc29ydGAsIGFuZCBgZGlyZWN0aW9uYCAoYGFzY2Agb3IgYGRlc2NgKS5cbiAgICAgICAgICogQHBhcmFtICB7T2JqZWN0fSBbb3B0aW9uc10gKE9wdGlvbmFsKSBPdmVycmlkZXMgZm9yIGNvbmZpZ3VyYXRpb24gb3B0aW9ucy5cbiAgICAgICAgICogQHJldHVybiB7UHJvbWlzZX1cbiAgICAgICAgICovXG4gICAgICAgIHJlbW92ZUZyb21NZW1vcnk6IGZ1bmN0aW9uIChydW5JRCwgZmlsdGVycywgb3B0aW9ucykge1xuICAgICAgICAgICAgdmFyIGh0dHBPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sIHNlcnZpY2VPcHRpb25zLCBvcHRpb25zKTtcbiAgICAgICAgICAgIGlmIChydW5JRCkge1xuICAgICAgICAgICAgICAgIGh0dHBPcHRpb25zLnVybCA9IHVybENvbmZpZy5nZXRBUElQYXRoKCdydW4nKSArIHJ1bklEO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgcmV0dXJuIGh0dHAuZGVsZXRlKHt9LCBodHRwT3B0aW9ucyk7XG4gICAgICAgIH0sXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIFNhdmUgYXR0cmlidXRlcyAoZGF0YSwgbW9kZWwgdmFyaWFibGVzKSBvZiB0aGUgcnVuLlxuICAgICAgICAgKlxuICAgICAgICAgKiAqKkV4YW1wbGVzKipcbiAgICAgICAgICpcbiAgICAgICAgICogICAgIC8vIGFkZCAnY29tcGxldGVkJyBmaWVsZCB0byBydW4gcmVjb3JkXG4gICAgICAgICAqICAgICBycy5zYXZlKHsgY29tcGxldGVkOiB0cnVlIH0pO1xuICAgICAgICAgKlxuICAgICAgICAgKiAgICAgLy8gdXBkYXRlICdzYXZlZCcgZmllbGQgb2YgcnVuIHJlY29yZCwgYW5kIHVwZGF0ZSB2YWx1ZXMgb2YgbW9kZWwgdmFyaWFibGVzIGZvciB0aGlzIHJ1blxuICAgICAgICAgKiAgICAgcnMuc2F2ZSh7IHNhdmVkOiB0cnVlLCB2YXJpYWJsZXM6IHsgYTogMjMsIGI6IDIzIH0gfSk7XG4gICAgICAgICAqXG4gICAgICAgICAqICAgICAvLyB1cGRhdGUgJ3NhdmVkJyBmaWVsZCBvZiBydW4gcmVjb3JkIGZvciBhIHBhcnRpY3VsYXIgcnVuXG4gICAgICAgICAqICAgICBycy5zYXZlKHsgc2F2ZWQ6IHRydWUgfSwgeyBpZDogJzAwMDAwMTViZjJhMDQ5OTU4ODBkZjZiODY4ZDIzZWIzZDIyOScgfSk7XG4gICAgICAgICAqXG4gICAgICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICAgICAqIEBwYXJhbSB7T2JqZWN0fSBhdHRyaWJ1dGVzIFRoZSBydW4gZGF0YSBhbmQgdmFyaWFibGVzIHRvIHNhdmUuXG4gICAgICAgICAqIEBwYXJhbSB7T2JqZWN0fSBhdHRyaWJ1dGVzLnZhcmlhYmxlcyBNb2RlbCB2YXJpYWJsZXMgbXVzdCBiZSBpbmNsdWRlZCBpbiBhIGB2YXJpYWJsZXNgIGZpZWxkIHdpdGhpbiB0aGUgYGF0dHJpYnV0ZXNgIG9iamVjdC4gKE90aGVyd2lzZSB0aGV5IGFyZSB0cmVhdGVkIGFzIHJ1biBkYXRhIGFuZCBhZGRlZCB0byB0aGUgcnVuIHJlY29yZCBkaXJlY3RseS4pXG4gICAgICAgICAqIEBwYXJhbSB7T2JqZWN0fSBvcHRpb25zIChPcHRpb25hbCkgT3ZlcnJpZGVzIGZvciBjb25maWd1cmF0aW9uIG9wdGlvbnMuXG4gICAgICAgICAqIEByZXR1cm4ge1Byb21pc2V9XG4gICAgICAgICAqL1xuICAgICAgICBzYXZlOiBmdW5jdGlvbiAoYXR0cmlidXRlcywgb3B0aW9ucykge1xuICAgICAgICAgICAgdmFyIGh0dHBPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sIHNlcnZpY2VPcHRpb25zLCBvcHRpb25zKTtcbiAgICAgICAgICAgIHNldEZpbHRlck9yVGhyb3dFcnJvcihodHRwT3B0aW9ucyk7XG4gICAgICAgICAgICByZXR1cm4gaHR0cC5wYXRjaChhdHRyaWJ1dGVzLCBodHRwT3B0aW9ucyk7XG4gICAgICAgIH0sXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIENhbGwgYW4gb3BlcmF0aW9uIGZyb20gdGhlIG1vZGVsLlxuICAgICAgICAgKlxuICAgICAgICAgKiBEZXBlbmRpbmcgb24gdGhlIGxhbmd1YWdlIGluIHdoaWNoIHlvdSBoYXZlIHdyaXR0ZW4geW91ciBtb2RlbCwgdGhlIG9wZXJhdGlvbiAoZnVuY3Rpb24gb3IgbWV0aG9kKSBtYXkgbmVlZCB0byBiZSBleHBvc2VkIChlLmcuIGBleHBvcnRgIGZvciBhIEp1bGlhIG1vZGVsKSBpbiB0aGUgbW9kZWwgZmlsZSBpbiBvcmRlciB0byBiZSBjYWxsZWQgdGhyb3VnaCB0aGUgQVBJLiBTZWUgW1dyaXRpbmcgeW91ciBNb2RlbF0oLi4vLi4vLi4vd3JpdGluZ195b3VyX21vZGVsLykpLlxuICAgICAgICAgKlxuICAgICAgICAgKiBUaGUgYHBhcmFtc2AgYXJndW1lbnQgaXMgbm9ybWFsbHkgYW4gYXJyYXkgb2YgYXJndW1lbnRzIHRvIHRoZSBgb3BlcmF0aW9uYC4gSW4gdGhlIHNwZWNpYWwgY2FzZSB3aGVyZSBgb3BlcmF0aW9uYCBvbmx5IHRha2VzIG9uZSBhcmd1bWVudCwgeW91IGFyZSBub3QgcmVxdWlyZWQgdG8gcHV0IHRoYXQgYXJndW1lbnQgaW50byBhbiBhcnJheS5cbiAgICAgICAgICpcbiAgICAgICAgICogTm90ZSB0aGF0IHlvdSBjYW4gY29tYmluZSB0aGUgYG9wZXJhdGlvbmAgYW5kIGBwYXJhbXNgIGFyZ3VtZW50cyBpbnRvIGEgc2luZ2xlIG9iamVjdCBpZiB5b3UgcHJlZmVyLCBhcyBpbiB0aGUgbGFzdCBleGFtcGxlLlxuICAgICAgICAgKlxuICAgICAgICAgKiAqKkV4YW1wbGVzKipcbiAgICAgICAgICpcbiAgICAgICAgICogICAgICAvLyBvcGVyYXRpb24gXCJzb2x2ZVwiIHRha2VzIG5vIGFyZ3VtZW50c1xuICAgICAgICAgKiAgICAgcnMuZG8oJ3NvbHZlJyk7XG4gICAgICAgICAqICAgICAgLy8gb3BlcmF0aW9uIFwiZWNob1wiIHRha2VzIG9uZSBhcmd1bWVudCwgYSBzdHJpbmdcbiAgICAgICAgICogICAgIHJzLmRvKCdlY2hvJywgWydoZWxsbyddKTtcbiAgICAgICAgICogICAgICAvLyBvcGVyYXRpb24gXCJlY2hvXCIgdGFrZXMgb25lIGFyZ3VtZW50LCBhIHN0cmluZ1xuICAgICAgICAgKiAgICAgcnMuZG8oJ2VjaG8nLCAnaGVsbG8nKTtcbiAgICAgICAgICogICAgICAvLyBvcGVyYXRpb24gXCJzdW1BcnJheVwiIHRha2VzIG9uZSBhcmd1bWVudCwgYW4gYXJyYXlcbiAgICAgICAgICogICAgIHJzLmRvKCdzdW1BcnJheScsIFtbNCwyLDFdXSk7XG4gICAgICAgICAqICAgICAgLy8gb3BlcmF0aW9uIFwiYWRkXCIgdGFrZXMgdHdvIGFyZ3VtZW50cywgYm90aCBpbnRlZ2Vyc1xuICAgICAgICAgKiAgICAgcnMuZG8oeyBuYW1lOidhZGQnLCBwYXJhbXM6WzIsNF0gfSk7XG4gICAgICAgICAqICAgICAgLy8gY2FsbCBvcGVyYXRpb24gXCJzb2x2ZVwiIG9uIGEgZGlmZmVyZW50IHJ1biBcbiAgICAgICAgICogICAgIHJzLmRvKCdzb2x2ZScsIHsgaWQ6ICcwMDAwMDE1YmYyYTA0OTk1ODgwZGY2Yjg2OGQyM2ViM2QyMjknIH0pO1xuICAgICAgICAgKlxuICAgICAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAgKiBAcGFyYW0ge1N0cmluZ30gb3BlcmF0aW9uIE5hbWUgb2Ygb3BlcmF0aW9uLlxuICAgICAgICAgKiBAcGFyYW0ge0FycmF5fSBwYXJhbXMgKE9wdGlvbmFsKSBBbnkgcGFyYW1ldGVycyB0aGUgb3BlcmF0aW9uIHRha2VzLCBwYXNzZWQgYXMgYW4gYXJyYXkuIEluIHRoZSBzcGVjaWFsIGNhc2Ugd2hlcmUgYG9wZXJhdGlvbmAgb25seSB0YWtlcyBvbmUgYXJndW1lbnQsIHlvdSBhcmUgbm90IHJlcXVpcmVkIHRvIHB1dCB0aGF0IGFyZ3VtZW50IGludG8gYW4gYXJyYXksIGFuZCBjYW4ganVzdCBwYXNzIGl0IGRpcmVjdGx5LlxuICAgICAgICAgKiBAcGFyYW0ge09iamVjdH0gb3B0aW9ucyAoT3B0aW9uYWwpIE92ZXJyaWRlcyBmb3IgY29uZmlndXJhdGlvbiBvcHRpb25zLlxuICAgICAgICAgKiBAcmV0dXJuIHtQcm9taXNlfVxuICAgICAgICAgKi9cbiAgICAgICAgZG86IGZ1bmN0aW9uIChvcGVyYXRpb24sIHBhcmFtcywgb3B0aW9ucykge1xuICAgICAgICAgICAgLy8gY29uc29sZS5sb2coJ2RvJywgb3BlcmF0aW9uLCBwYXJhbXMpO1xuICAgICAgICAgICAgdmFyIG9wc0FyZ3M7XG4gICAgICAgICAgICB2YXIgcG9zdE9wdGlvbnM7XG4gICAgICAgICAgICBpZiAob3B0aW9ucykge1xuICAgICAgICAgICAgICAgIG9wc0FyZ3MgPSBwYXJhbXM7XG4gICAgICAgICAgICAgICAgcG9zdE9wdGlvbnMgPSBvcHRpb25zO1xuICAgICAgICAgICAgfSBlbHNlIGlmICgkLmlzUGxhaW5PYmplY3QocGFyYW1zKSkge1xuICAgICAgICAgICAgICAgIG9wc0FyZ3MgPSBudWxsO1xuICAgICAgICAgICAgICAgIHBvc3RPcHRpb25zID0gcGFyYW1zO1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICBvcHNBcmdzID0gcGFyYW1zO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgdmFyIHJlc3VsdCA9IHJ1dGlsLm5vcm1hbGl6ZU9wZXJhdGlvbnMob3BlcmF0aW9uLCBvcHNBcmdzKTtcbiAgICAgICAgICAgIHZhciBodHRwT3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LCBzZXJ2aWNlT3B0aW9ucywgcG9zdE9wdGlvbnMpO1xuXG4gICAgICAgICAgICBzZXRGaWx0ZXJPclRocm93RXJyb3IoaHR0cE9wdGlvbnMpO1xuXG4gICAgICAgICAgICB2YXIgcHJtcyA9IChyZXN1bHQuYXJnc1swXS5sZW5ndGggJiYgKHJlc3VsdC5hcmdzWzBdICE9PSBudWxsICYmIHJlc3VsdC5hcmdzWzBdICE9PSB1bmRlZmluZWQpKSA/IHJlc3VsdC5hcmdzWzBdIDogW107XG4gICAgICAgICAgICByZXR1cm4gaHR0cC5wb3N0KHsgYXJndW1lbnRzOiBwcm1zIH0sICQuZXh0ZW5kKHRydWUsIHt9LCBodHRwT3B0aW9ucywge1xuICAgICAgICAgICAgICAgIHVybDogdXJsQ29uZmlnLmdldEZpbHRlclVSTCgpICsgJ29wZXJhdGlvbnMvJyArIHJlc3VsdC5vcHNbMF0gKyAnLydcbiAgICAgICAgICAgIH0pKTtcbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgICogQ2FsbCBzZXZlcmFsIG9wZXJhdGlvbnMgZnJvbSB0aGUgbW9kZWwsIHNlcXVlbnRpYWxseS5cbiAgICAgICAgICpcbiAgICAgICAgICogRGVwZW5kaW5nIG9uIHRoZSBsYW5ndWFnZSBpbiB3aGljaCB5b3UgaGF2ZSB3cml0dGVuIHlvdXIgbW9kZWwsIHRoZSBvcGVyYXRpb24gKGZ1bmN0aW9uIG9yIG1ldGhvZCkgbWF5IG5lZWQgdG8gYmUgZXhwb3NlZCAoZS5nLiBgZXhwb3J0YCBmb3IgYSBKdWxpYSBtb2RlbCkgaW4gdGhlIG1vZGVsIGZpbGUgaW4gb3JkZXIgdG8gYmUgY2FsbGVkIHRocm91Z2ggdGhlIEFQSS4gU2VlIFtXcml0aW5nIHlvdXIgTW9kZWxdKC4uLy4uLy4uL3dyaXRpbmdfeW91cl9tb2RlbC8pKS5cbiAgICAgICAgICpcbiAgICAgICAgICogKipFeGFtcGxlcyoqXG4gICAgICAgICAqXG4gICAgICAgICAqICAgICAgLy8gb3BlcmF0aW9ucyBcImluaXRpYWxpemVcIiBhbmQgXCJzb2x2ZVwiIGRvIG5vdCB0YWtlIGFueSBhcmd1bWVudHNcbiAgICAgICAgICogICAgIHJzLnNlcmlhbChbJ2luaXRpYWxpemUnLCAnc29sdmUnXSk7XG4gICAgICAgICAqICAgICAgLy8gb3BlcmF0aW9ucyBcImluaXRcIiBhbmQgXCJyZXNldFwiIHRha2UgdHdvIGFyZ3VtZW50cyBlYWNoXG4gICAgICAgICAqICAgICBycy5zZXJpYWwoWyAgeyBuYW1lOiAnaW5pdCcsIHBhcmFtczogWzEsMl0gfSxcbiAgICAgICAgICogICAgICAgICAgICAgICAgICB7IG5hbWU6ICdyZXNldCcsIHBhcmFtczogWzIsM10gfV0pO1xuICAgICAgICAgKiAgICAgIC8vIG9wZXJhdGlvbiBcImluaXRcIiB0YWtlcyB0d28gYXJndW1lbnRzLFxuICAgICAgICAgKiAgICAgIC8vIG9wZXJhdGlvbiBcInJ1bm1vZGVsXCIgdGFrZXMgbm9uZVxuICAgICAgICAgKiAgICAgcnMuc2VyaWFsKFsgIHsgbmFtZTogJ2luaXQnLCBwYXJhbXM6IFsxLDJdIH0sXG4gICAgICAgICAqICAgICAgICAgICAgICAgICAgeyBuYW1lOiAncnVubW9kZWwnLCBwYXJhbXM6IFtdIH1dKTtcbiAgICAgICAgICpcbiAgICAgICAgICogKipQYXJhbWV0ZXJzKipcbiAgICAgICAgICogQHBhcmFtIHtBcnJheX0gb3BlcmF0aW9ucyBJZiBub25lIG9mIHRoZSBvcGVyYXRpb25zIHRha2UgcGFyYW1ldGVycywgcGFzcyBhbiBhcnJheSBvZiB0aGUgb3BlcmF0aW9uIG5hbWVzIChzdHJpbmdzKS4gSWYgYW55IG9mIHRoZSBvcGVyYXRpb25zIGRvIHRha2UgcGFyYW1ldGVycywgcGFzcyBhbiBhcnJheSBvZiBvYmplY3RzLCBlYWNoIG9mIHdoaWNoIGNvbnRhaW5zIGFuIG9wZXJhdGlvbiBuYW1lIGFuZCBpdHMgb3duIChwb3NzaWJseSBlbXB0eSkgYXJyYXkgb2YgcGFyYW1ldGVycy5cbiAgICAgICAgICogQHBhcmFtIHsqfSBwYXJhbXMgUGFyYW1ldGVycyB0byBwYXNzIHRvIG9wZXJhdGlvbnMuXG4gICAgICAgICAqIEBwYXJhbSB7T2JqZWN0fSBvcHRpb25zIChPcHRpb25hbCkgT3ZlcnJpZGVzIGZvciBjb25maWd1cmF0aW9uIG9wdGlvbnMuXG4gICAgICAgICAqIEByZXR1cm4ge1Byb21pc2V9IFRoZSBwYXJhbWV0ZXIgdG8gdGhlIGNhbGxiYWNrIGlzIGFuIGFycmF5LiBFYWNoIGFycmF5IGVsZW1lbnQgaXMgYW4gb2JqZWN0IGNvbnRhaW5pbmcgdGhlIHJlc3VsdHMgb2Ygb25lIG9wZXJhdGlvbi5cbiAgICAgICAgICovXG4gICAgICAgIHNlcmlhbDogZnVuY3Rpb24gKG9wZXJhdGlvbnMsIHBhcmFtcywgb3B0aW9ucykge1xuICAgICAgICAgICAgdmFyIG9wUGFyYW1zID0gcnV0aWwubm9ybWFsaXplT3BlcmF0aW9ucyhvcGVyYXRpb25zLCBwYXJhbXMpO1xuICAgICAgICAgICAgdmFyIG9wcyA9IG9wUGFyYW1zLm9wcztcbiAgICAgICAgICAgIHZhciBhcmdzID0gb3BQYXJhbXMuYXJncztcbiAgICAgICAgICAgIHZhciBtZSA9IHRoaXM7XG5cbiAgICAgICAgICAgIHZhciAkZCA9ICQuRGVmZXJyZWQoKTtcbiAgICAgICAgICAgIHZhciBwb3N0T3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LCBzZXJ2aWNlT3B0aW9ucywgb3B0aW9ucyk7XG5cbiAgICAgICAgICAgIHZhciByZXNwb25zZXMgPSBbXTtcbiAgICAgICAgICAgIHZhciBkb1NpbmdsZU9wID0gZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgICAgIHZhciBvcCA9IG9wcy5zaGlmdCgpO1xuICAgICAgICAgICAgICAgIHZhciBhcmcgPSBhcmdzLnNoaWZ0KCk7XG5cbiAgICAgICAgICAgICAgICBtZS5kbyhvcCwgYXJnLCB7XG4gICAgICAgICAgICAgICAgICAgIHN1Y2Nlc3M6IGZ1bmN0aW9uIChyZXN1bHQpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHJlc3BvbnNlcy5wdXNoKHJlc3VsdCk7XG4gICAgICAgICAgICAgICAgICAgICAgICBpZiAob3BzLmxlbmd0aCkge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRvU2luZ2xlT3AoKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgJGQucmVzb2x2ZShyZXNwb25zZXMpO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBvc3RPcHRpb25zLnN1Y2Nlc3MocmVzcG9uc2VzLCBtZSk7XG4gICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICAgICAgICAgIGVycm9yOiBmdW5jdGlvbiAoZXJyKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICByZXNwb25zZXMucHVzaChlcnIpO1xuICAgICAgICAgICAgICAgICAgICAgICAgJGQucmVqZWN0KHJlc3BvbnNlcyk7XG4gICAgICAgICAgICAgICAgICAgICAgICBwb3N0T3B0aW9ucy5lcnJvcihyZXNwb25zZXMsIG1lKTtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgfTtcblxuICAgICAgICAgICAgZG9TaW5nbGVPcCgpO1xuXG4gICAgICAgICAgICByZXR1cm4gJGQucHJvbWlzZSgpO1xuICAgICAgICB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBDYWxsIHNldmVyYWwgb3BlcmF0aW9ucyBmcm9tIHRoZSBtb2RlbCwgZXhlY3V0aW5nIHRoZW0gaW4gcGFyYWxsZWwuXG4gICAgICAgICAqXG4gICAgICAgICAqIERlcGVuZGluZyBvbiB0aGUgbGFuZ3VhZ2UgaW4gd2hpY2ggeW91IGhhdmUgd3JpdHRlbiB5b3VyIG1vZGVsLCB0aGUgb3BlcmF0aW9uIChmdW5jdGlvbiBvciBtZXRob2QpIG1heSBuZWVkIHRvIGJlIGV4cG9zZWQgKGUuZy4gYGV4cG9ydGAgZm9yIGEgSnVsaWEgbW9kZWwpIGluIHRoZSBtb2RlbCBmaWxlIGluIG9yZGVyIHRvIGJlIGNhbGxlZCB0aHJvdWdoIHRoZSBBUEkuIFNlZSBbV3JpdGluZyB5b3VyIE1vZGVsXSguLi8uLi8uLi93cml0aW5nX3lvdXJfbW9kZWwvKSkuXG4gICAgICAgICAqXG4gICAgICAgICAqICoqRXhhbXBsZSoqXG4gICAgICAgICAqXG4gICAgICAgICAqICAgICAgLy8gb3BlcmF0aW9ucyBcInNvbHZlXCIgYW5kIFwicmVzZXRcIiBkbyBub3QgdGFrZSBhbnkgYXJndW1lbnRzXG4gICAgICAgICAqICAgICBycy5wYXJhbGxlbChbJ3NvbHZlJywgJ3Jlc2V0J10pO1xuICAgICAgICAgKiAgICAgIC8vIG9wZXJhdGlvbnMgXCJhZGRcIiBhbmQgXCJzdWJ0cmFjdFwiIHRha2UgdHdvIGFyZ3VtZW50cyBlYWNoXG4gICAgICAgICAqICAgICBycy5wYXJhbGxlbChbIHsgbmFtZTogJ2FkZCcsIHBhcmFtczogWzEsMl0gfSxcbiAgICAgICAgICogICAgICAgICAgICAgICAgICAgeyBuYW1lOiAnc3VidHJhY3QnLCBwYXJhbXM6WzIsM10gfV0pO1xuICAgICAgICAgKiAgICAgIC8vIG9wZXJhdGlvbnMgXCJhZGRcIiBhbmQgXCJzdWJ0cmFjdFwiIHRha2UgdHdvIGFyZ3VtZW50cyBlYWNoXG4gICAgICAgICAqICAgICBycy5wYXJhbGxlbCh7IGFkZDogWzEsMl0sIHN1YnRyYWN0OiBbMiw0XSB9KTtcbiAgICAgICAgICpcbiAgICAgICAgICogKipQYXJhbWV0ZXJzKipcbiAgICAgICAgICogQHBhcmFtIHtBcnJheXxPYmplY3R9IG9wZXJhdGlvbnMgSWYgbm9uZSBvZiB0aGUgb3BlcmF0aW9ucyB0YWtlIHBhcmFtZXRlcnMsIHBhc3MgYW4gYXJyYXkgb2YgdGhlIG9wZXJhdGlvbiBuYW1lcyAoYXMgc3RyaW5ncykuIElmIGFueSBvZiB0aGUgb3BlcmF0aW9ucyBkbyB0YWtlIHBhcmFtZXRlcnMsIHlvdSBoYXZlIHR3byBvcHRpb25zLiBZb3UgY2FuIHBhc3MgYW4gYXJyYXkgb2Ygb2JqZWN0cywgZWFjaCBvZiB3aGljaCBjb250YWlucyBhbiBvcGVyYXRpb24gbmFtZSBhbmQgaXRzIG93biAocG9zc2libHkgZW1wdHkpIGFycmF5IG9mIHBhcmFtZXRlcnMuIEFsdGVybmF0aXZlbHksIHlvdSBjYW4gcGFzcyBhIHNpbmdsZSBvYmplY3Qgd2l0aCB0aGUgb3BlcmF0aW9uIG5hbWUgYW5kIGEgKHBvc3NpYmx5IGVtcHR5KSBhcnJheSBvZiBwYXJhbWV0ZXJzLlxuICAgICAgICAgKiBAcGFyYW0geyp9IHBhcmFtcyBQYXJhbWV0ZXJzIHRvIHBhc3MgdG8gb3BlcmF0aW9ucy5cbiAgICAgICAgICogQHBhcmFtIHtPYmplY3R9IG9wdGlvbnMgKE9wdGlvbmFsKSBPdmVycmlkZXMgZm9yIGNvbmZpZ3VyYXRpb24gb3B0aW9ucy5cbiAgICAgICAgICogQHJldHVybiB7UHJvbWlzZX0gVGhlIHBhcmFtZXRlciB0byB0aGUgY2FsbGJhY2sgaXMgYW4gYXJyYXkuIEVhY2ggYXJyYXkgZWxlbWVudCBpcyBhbiBvYmplY3QgY29udGFpbmluZyB0aGUgcmVzdWx0cyBvZiBvbmUgb3BlcmF0aW9uLlxuICAgICAgICAgKi9cbiAgICAgICAgcGFyYWxsZWw6IGZ1bmN0aW9uIChvcGVyYXRpb25zLCBwYXJhbXMsIG9wdGlvbnMpIHtcbiAgICAgICAgICAgIHZhciAkZCA9ICQuRGVmZXJyZWQoKTtcblxuICAgICAgICAgICAgdmFyIG9wUGFyYW1zID0gcnV0aWwubm9ybWFsaXplT3BlcmF0aW9ucyhvcGVyYXRpb25zLCBwYXJhbXMpO1xuICAgICAgICAgICAgdmFyIG9wcyA9IG9wUGFyYW1zLm9wcztcbiAgICAgICAgICAgIHZhciBhcmdzID0gb3BQYXJhbXMuYXJncztcbiAgICAgICAgICAgIHZhciBwb3N0T3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LCBzZXJ2aWNlT3B0aW9ucywgb3B0aW9ucyk7XG5cbiAgICAgICAgICAgIHZhciBxdWV1ZSA9IFtdO1xuICAgICAgICAgICAgZm9yICh2YXIgaSA9IDA7IGkgPCBvcHMubGVuZ3RoOyBpKyspIHtcbiAgICAgICAgICAgICAgICBxdWV1ZS5wdXNoKFxuICAgICAgICAgICAgICAgICAgICB0aGlzLmRvKG9wc1tpXSwgYXJnc1tpXSlcbiAgICAgICAgICAgICAgICApO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICB2YXIgbWUgPSB0aGlzO1xuICAgICAgICAgICAgJC53aGVuLmFwcGx5KHRoaXMsIHF1ZXVlKVxuICAgICAgICAgICAgICAgIC50aGVuKGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgICAgICAgICAgdmFyIGFyZ3MgPSBBcnJheS5wcm90b3R5cGUuc2xpY2UuY2FsbChhcmd1bWVudHMpO1xuICAgICAgICAgICAgICAgICAgICB2YXIgYWN0dWFsUmVzcG9uc2UgPSBhcmdzLm1hcChmdW5jdGlvbiAoYSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIGFbMF07XG4gICAgICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICAgICAgICAkZC5yZXNvbHZlKGFjdHVhbFJlc3BvbnNlKTtcbiAgICAgICAgICAgICAgICAgICAgcG9zdE9wdGlvbnMuc3VjY2VzcyhhY3R1YWxSZXNwb25zZSwgbWUpO1xuICAgICAgICAgICAgICAgIH0pXG4gICAgICAgICAgICAgICAgLmZhaWwoZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgICAgICAgICB2YXIgYXJncyA9IEFycmF5LnByb3RvdHlwZS5zbGljZS5jYWxsKGFyZ3VtZW50cyk7XG4gICAgICAgICAgICAgICAgICAgIHZhciBhY3R1YWxSZXNwb25zZSA9IGFyZ3MubWFwKGZ1bmN0aW9uIChhKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICByZXR1cm4gYVswXTtcbiAgICAgICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgICAgICAgICRkLnJlamVjdChhY3R1YWxSZXNwb25zZSk7XG4gICAgICAgICAgICAgICAgICAgIHBvc3RPcHRpb25zLmVycm9yKGFjdHVhbFJlc3BvbnNlLCBtZSk7XG4gICAgICAgICAgICAgICAgfSk7XG5cbiAgICAgICAgICAgIHJldHVybiAkZC5wcm9taXNlKCk7XG4gICAgICAgIH0sXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIFNob3J0Y3V0IHRvIHVzaW5nIHRoZSBbSW50cm9zcGVjdGlvbiBBUEkgU2VydmljZV0oLi4vaW50cm9zcGVjdGlvbi1hcGktc2VydmljZS8pLiBBbGxvd3MgeW91IHRvIHZpZXcgYSBsaXN0IG9mIHRoZSB2YXJpYWJsZXMgYW5kIG9wZXJhdGlvbnMgaW4gYSBtb2RlbC5cbiAgICAgICAgICpcbiAgICAgICAgICogKipFeGFtcGxlKipcbiAgICAgICAgICpcbiAgICAgICAgICogICAgIHJzLmludHJvc3BlY3QoeyBydW5JRDogJ2NiZjg1NDM3LWI1MzktNDk3Ny1hMWZjLTIzNTE1Y2YwNzFiYicgfSkudGhlbihmdW5jdGlvbiAoZGF0YSkge1xuICAgICAgICAgKiAgICAgICAgICBjb25zb2xlLmxvZyhkYXRhLmZ1bmN0aW9ucyk7XG4gICAgICAgICAqICAgICAgICAgIGNvbnNvbGUubG9nKGRhdGEudmFyaWFibGVzKTtcbiAgICAgICAgICogICAgIH0pO1xuICAgICAgICAgKlxuICAgICAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAgKiBAcGFyYW0gIHtPYmplY3R9IG9wdGlvbnMgT3B0aW9ucyBjYW4gZWl0aGVyIGJlIG9mIHRoZSBmb3JtIGB7IHJ1bklEOiA8cnVuaWQ+IH1gIG9yIGB7IG1vZGVsOiA8bW9kZWxGaWxlTmFtZT4gfWAuIE5vdGUgdGhhdCB0aGUgYHJ1bklEYCBpcyBvcHRpb25hbCBpZiB0aGUgUnVuIFNlcnZpY2UgaXMgYWxyZWFkeSBhc3NvY2lhdGVkIHdpdGggYSBwYXJ0aWN1bGFyIHJ1biAoYmVjYXVzZSBgaWRgIHdhcyBwYXNzZWQgaW4gd2hlbiB0aGUgUnVuIFNlcnZpY2Ugd2FzIGluaXRpYWxpemVkKS4gSWYgcHJvdmlkZWQsIHRoZSBgcnVuSURgIG92ZXJyaWRlcyB0aGUgYGlkYCBjdXJyZW50bHkgYXNzb2NpYXRlZCB3aXRoIHRoZSBSdW4gU2VydmljZS5cbiAgICAgICAgICogQHBhcmFtICB7T2JqZWN0fSBpbnRyb3NwZWN0aW9uQ29uZmlnIChPcHRpb25hbCkgU2VydmljZSBvcHRpb25zIGZvciBJbnRyb3NwZWN0aW9uIFNlcnZpY2VcbiAgICAgICAgICogQHJldHVybiB7UHJvbWlzZX1cbiAgICAgICAgICovXG4gICAgICAgIGludHJvc3BlY3Q6IGZ1bmN0aW9uIChvcHRpb25zLCBpbnRyb3NwZWN0aW9uQ29uZmlnKSB7XG4gICAgICAgICAgICB2YXIgaW50cm9zcGVjdGlvbiA9IG5ldyBJbnRyb3NwZWN0aW9uU2VydmljZSgkLmV4dGVuZCh0cnVlLCB7fSwgc2VydmljZU9wdGlvbnMsIGludHJvc3BlY3Rpb25Db25maWcpKTtcbiAgICAgICAgICAgIGlmIChvcHRpb25zKSB7XG4gICAgICAgICAgICAgICAgaWYgKG9wdGlvbnMucnVuSUQpIHtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIGludHJvc3BlY3Rpb24uYnlSdW5JRChvcHRpb25zLnJ1bklEKTtcbiAgICAgICAgICAgICAgICB9IGVsc2UgaWYgKG9wdGlvbnMubW9kZWwpIHtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIGludHJvc3BlY3Rpb24uYnlNb2RlbChvcHRpb25zLm1vZGVsKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9IGVsc2UgaWYgKHNlcnZpY2VPcHRpb25zLmlkKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIGludHJvc3BlY3Rpb24uYnlSdW5JRChzZXJ2aWNlT3B0aW9ucy5pZCk7XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcignUGxlYXNlIHNwZWNpZnkgZWl0aGVyIHRoZSBtb2RlbCBvciBydW5pZCB0byBpbnRyb3NwZWN0Jyk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICB9O1xuXG4gICAgdmFyIHB1YmxpY1N5bmNBUEkgPSB7XG4gICAgICAgIGdldEN1cnJlbnRDb25maWc6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIHJldHVybiBzZXJ2aWNlT3B0aW9ucztcbiAgICAgICAgfSxcbiAgICAgICAgdXBkYXRlQ29uZmlnOiBmdW5jdGlvbiAoY29uZmlnKSB7XG4gICAgICAgICAgICBpZiAoY29uZmlnICYmIGNvbmZpZy5pZCkge1xuICAgICAgICAgICAgICAgIGNvbmZpZy5maWx0ZXIgPSBjb25maWcuaWQ7XG4gICAgICAgICAgICB9IGVsc2UgaWYgKGNvbmZpZyAmJiBjb25maWcuZmlsdGVyKSB7XG4gICAgICAgICAgICAgICAgY29uZmlnLmlkID0gY29uZmlnLmZpbHRlcjtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHNlcnZpY2VPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sIHNlcnZpY2VPcHRpb25zLCBjb25maWcpO1xuICAgICAgICAgICAgdXJsQ29uZmlnID0gdXBkYXRlVVJMQ29uZmlnKHNlcnZpY2VPcHRpb25zKTtcbiAgICAgICAgICAgIHRoaXMudXJsQ29uZmlnID0gdXJsQ29uZmlnO1xuICAgICAgICAgICAgdXBkYXRlSFRUUENvbmZpZyhzZXJ2aWNlT3B0aW9ucywgdXJsQ29uZmlnKTtcbiAgICAgICAgfSxcbiAgICAgICAgLyoqXG4gICAgICAgICAgKiBSZXR1cm5zIGEgVmFyaWFibGVzIFNlcnZpY2UgaW5zdGFuY2UuIFVzZSB0aGUgdmFyaWFibGVzIGluc3RhbmNlIHRvIGxvYWQsIHNhdmUsIGFuZCBxdWVyeSBmb3Igc3BlY2lmaWMgbW9kZWwgdmFyaWFibGVzLiBTZWUgdGhlIFtWYXJpYWJsZSBBUEkgU2VydmljZV0oLi4vdmFyaWFibGVzLWFwaS1zZXJ2aWNlLykgZm9yIG1vcmUgaW5mb3JtYXRpb24uXG4gICAgICAgICAgKlxuICAgICAgICAgICogKipFeGFtcGxlKipcbiAgICAgICAgICAqXG4gICAgICAgICAgKiAgICAgIHZhciB2cyA9IHJzLnZhcmlhYmxlcygpO1xuICAgICAgICAgICogICAgICB2cy5zYXZlKHsgc2FtcGxlX2ludDogNCB9KTtcbiAgICAgICAgICAqXG4gICAgICAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAgICogQHBhcmFtIHtPYmplY3R9IGNvbmZpZyAoT3B0aW9uYWwpIE92ZXJyaWRlcyBmb3IgY29uZmlndXJhdGlvbiBvcHRpb25zLlxuICAgICAgICAgICogQHJldHVybiB7T2JqZWN0fSB2YXJpYWJsZXNTZXJ2aWNlIEluc3RhbmNlXG4gICAgICAgICAgKi9cbiAgICAgICAgdmFyaWFibGVzOiBmdW5jdGlvbiAoY29uZmlnKSB7XG4gICAgICAgICAgICB2YXIgdnMgPSBuZXcgVmFyaWFibGVzU2VydmljZSgkLmV4dGVuZCh0cnVlLCB7fSwgc2VydmljZU9wdGlvbnMsIGNvbmZpZywge1xuICAgICAgICAgICAgICAgIHJ1blNlcnZpY2U6IHRoaXNcbiAgICAgICAgICAgIH0pKTtcbiAgICAgICAgICAgIHJldHVybiB2cztcbiAgICAgICAgfVxuICAgIH07XG5cbiAgICAkLmV4dGVuZCh0aGlzLCBwdWJsaWNBc3luY0FQSSk7XG4gICAgJC5leHRlbmQodGhpcywgcHVibGljU3luY0FQSSk7XG59O1xuIiwiJ3VzZSBzdHJpY3QnO1xuXG52YXIgQ29uZmlnU2VydmljZSA9IHJlcXVpcmUoJy4vY29uZmlndXJhdGlvbi1zZXJ2aWNlJyk7XG52YXIgU2Vzc2lvbk1hbmFnZXIgPSByZXF1aXJlKCcuLi9zdG9yZS9zZXNzaW9uLW1hbmFnZXInKTtcbnZhciBvYmplY3RBc3NpZ24gPSByZXF1aXJlKCdvYmplY3QtYXNzaWduJyk7XG5cbnZhciBzZXJ2aWNlVXRpbHMgPSB7XG4gICAgLypcbiAgICAqIEdldHMgdGhlIGRlZmF1bHQgb3B0aW9ucyBmb3IgYSBhcGkgc2VydmljZS5cbiAgICAqIEl0IHdpbGwgbWVyZ2U6XG4gICAgKiAtIFRoZSBTZXNzaW9uIG9wdGlvbnMgKFVzaW5nIHRoZSBTZXNzaW9uIE1hbmFnZXIpXG4gICAgKiAtIFRoZSBBdXRob3JpemF0aW9uIEhlYWRlciBmcm9tIHRoZSB0b2tlbiBvcHRpb25cbiAgICAqIC0gVGhlIGZ1bGwgdXJsIGZyb20gdGhlIGVuZHBvaW50IG9wdGlvblxuICAgICogV2l0aCB0aGUgc3VwcGxpZWQgb3ZlcnJpZGVzIGFuZCBkZWZhdWx0c1xuICAgICpcbiAgICAqL1xuICAgIGdldERlZmF1bHRPcHRpb25zOiBmdW5jdGlvbiAoZGVmYXVsdHMpIHtcbiAgICAgICAgdmFyIHJlc3QgPSBBcnJheS5wcm90b3R5cGUuc2xpY2UuY2FsbChhcmd1bWVudHMsIDEpO1xuICAgICAgICB2YXIgc2Vzc2lvbk1hbmFnZXIgPSBuZXcgU2Vzc2lvbk1hbmFnZXIoKTtcbiAgICAgICAgdmFyIHNlcnZpY2VPcHRpb25zID0gc2Vzc2lvbk1hbmFnZXIuZ2V0TWVyZ2VkT3B0aW9ucy5hcHBseShzZXNzaW9uTWFuYWdlciwgW2RlZmF1bHRzXS5jb25jYXQocmVzdCkpO1xuXG4gICAgICAgIHNlcnZpY2VPcHRpb25zLnRyYW5zcG9ydCA9IG9iamVjdEFzc2lnbih7fSwgc2VydmljZU9wdGlvbnMudHJhbnNwb3J0LCB7XG4gICAgICAgICAgICB1cmw6IHRoaXMuZ2V0QXBpVXJsKHNlcnZpY2VPcHRpb25zLmFwaUVuZHBvaW50LCBzZXJ2aWNlT3B0aW9ucylcbiAgICAgICAgfSk7XG5cbiAgICAgICAgaWYgKHNlcnZpY2VPcHRpb25zLnRva2VuKSB7XG4gICAgICAgICAgICBzZXJ2aWNlT3B0aW9ucy50cmFuc3BvcnQuaGVhZGVycyA9IHtcbiAgICAgICAgICAgICAgICBBdXRob3JpemF0aW9uOiAnQmVhcmVyICcgKyBzZXJ2aWNlT3B0aW9ucy50b2tlblxuICAgICAgICAgICAgfTtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gc2VydmljZU9wdGlvbnM7XG4gICAgfSxcblxuICAgIGdldEFwaVVybDogZnVuY3Rpb24gKGFwaUVuZHBvaW50LCBzZXJ2aWNlT3B0aW9ucykge1xuICAgICAgICB2YXIgdXJsQ29uZmlnID0gbmV3IENvbmZpZ1NlcnZpY2Uoc2VydmljZU9wdGlvbnMpLmdldCgnc2VydmVyJyk7XG4gICAgICAgIHJldHVybiB1cmxDb25maWcuZ2V0QVBJUGF0aChhcGlFbmRwb2ludCk7XG4gICAgfVxufTtcblxubW9kdWxlLmV4cG9ydHMgPSBzZXJ2aWNlVXRpbHM7IiwiJ3VzZSBzdHJpY3QnO1xuLyoqXG4gKiAjIyBTdGF0ZSBBUEkgQWRhcHRlclxuICpcbiAqIFRoZSBTdGF0ZSBBUEkgQWRhcHRlciBhbGxvd3MgeW91IHRvIHZpZXcgdGhlIGhpc3Rvcnkgb2YgYSBydW4sIGFuZCB0byByZXBsYXkgb3IgY2xvbmUgcnVucy4gXG4gKlxuICogVGhlIFN0YXRlIEFQSSBBZGFwdGVyIGJyaW5ncyBleGlzdGluZywgcGVyc2lzdGVkIHJ1biBkYXRhIGZyb20gdGhlIGRhdGFiYXNlIGJhY2sgaW50byBtZW1vcnksIHVzaW5nIHRoZSBzYW1lIHJ1biBpZCAoYHJlcGxheWApIG9yIGEgbmV3IHJ1biBpZCAoYGNsb25lYCkuIFJ1bnMgbXVzdCBiZSBpbiBtZW1vcnkgaW4gb3JkZXIgZm9yIHlvdSB0byB1cGRhdGUgdmFyaWFibGVzIG9yIGNhbGwgb3BlcmF0aW9ucyBvbiB0aGVtLlxuICpcbiAqIFNwZWNpZmljYWxseSwgdGhlIFN0YXRlIEFQSSBBZGFwdGVyIHdvcmtzIGJ5IFwicmUtcnVubmluZ1wiIHRoZSBydW4gKHVzZXIgaW50ZXJhY3Rpb25zKSBmcm9tIHRoZSBjcmVhdGlvbiBvZiB0aGUgcnVuIHVwIHRvIHRoZSB0aW1lIGl0IHdhcyBsYXN0IHBlcnNpc3RlZCBpbiB0aGUgZGF0YWJhc2UuIFRoaXMgcHJvY2VzcyB1c2VzIHRoZSBjdXJyZW50IHZlcnNpb24gb2YgdGhlIHJ1bidzIG1vZGVsLiBUaGVyZWZvcmUsIGlmIHRoZSBtb2RlbCBoYXMgY2hhbmdlZCBzaW5jZSB0aGUgb3JpZ2luYWwgcnVuIHdhcyBjcmVhdGVkLCB0aGUgcmV0cmlldmVkIHJ1biB3aWxsIHVzZSB0aGUgbmV3IG1vZGVsIOKAlCBhbmQgbWF5IGVuZCB1cCBoYXZpbmcgZGlmZmVyZW50IHZhbHVlcyBvciBiZWhhdmlvciBhcyBhIHJlc3VsdC4gVXNlIHdpdGggY2FyZSFcbiAqXG4gKiBUbyB1c2UgdGhlIFN0YXRlIEFQSSBBZGFwdGVyLCBpbnN0YW50aWF0ZSBpdCBhbmQgdGhlbiBjYWxsIGl0cyBtZXRob2RzOlxuICpcbiAqICAgICAgdmFyIHNhID0gbmV3IEYuc2VydmljZS5TdGF0ZSgpO1xuICogICAgICBzYS5yZXBsYXkoe3J1bklkOiAnMTg0MmJiNWMtODNhZC00YmE4LWE5NTUtYmQxM2NjMmZkYjRmJ30pO1xuICpcbiAqIFRoZSBjb25zdHJ1Y3RvciB0YWtlcyBhbiBvcHRpb25hbCBgb3B0aW9uc2AgcGFyYW1ldGVyIGluIHdoaWNoIHlvdSBjYW4gc3BlY2lmeSB0aGUgYGFjY291bnRgIGFuZCBgcHJvamVjdGAgaWYgdGhleSBhcmUgbm90IGFscmVhZHkgYXZhaWxhYmxlIGluIHRoZSBjdXJyZW50IGNvbnRleHQuXG4gKlxuICovXG5cbnZhciBDb25maWdTZXJ2aWNlID0gcmVxdWlyZSgnLi9jb25maWd1cmF0aW9uLXNlcnZpY2UnKTtcbnZhciBUcmFuc3BvcnRGYWN0b3J5ID0gcmVxdWlyZSgnLi4vdHJhbnNwb3J0L2h0dHAtdHJhbnNwb3J0LWZhY3RvcnknKTtcbnZhciBfcGljayA9IHJlcXVpcmUoJy4uL3V0aWwvb2JqZWN0LXV0aWwnKS5fcGljaztcbnZhciBTZXNzaW9uTWFuYWdlciA9IHJlcXVpcmUoJy4uL3N0b3JlL3Nlc3Npb24tbWFuYWdlcicpO1xudmFyIGFwaUVuZHBvaW50ID0gJ21vZGVsL3N0YXRlJztcblxubW9kdWxlLmV4cG9ydHMgPSBmdW5jdGlvbiAoY29uZmlnKSB7XG5cbiAgICB2YXIgZGVmYXVsdHMgPSB7XG5cbiAgICB9O1xuXG4gICAgdGhpcy5zZXNzaW9uTWFuYWdlciA9IG5ldyBTZXNzaW9uTWFuYWdlcigpO1xuICAgIHZhciBzZXJ2aWNlT3B0aW9ucyA9IHRoaXMuc2Vzc2lvbk1hbmFnZXIuZ2V0TWVyZ2VkT3B0aW9ucyhkZWZhdWx0cywgY29uZmlnKTtcbiAgICB2YXIgdXJsQ29uZmlnID0gbmV3IENvbmZpZ1NlcnZpY2Uoc2VydmljZU9wdGlvbnMpLmdldCgnc2VydmVyJyk7XG5cbiAgICB2YXIgdHJhbnNwb3J0T3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LCBzZXJ2aWNlT3B0aW9ucy50cmFuc3BvcnQsIHtcbiAgICAgICAgdXJsOiB1cmxDb25maWcuZ2V0QVBJUGF0aChhcGlFbmRwb2ludClcbiAgICB9KTtcblxuICAgIGlmIChzZXJ2aWNlT3B0aW9ucy50b2tlbikge1xuICAgICAgICB0cmFuc3BvcnRPcHRpb25zLmhlYWRlcnMgPSB7XG4gICAgICAgICAgICBBdXRob3JpemF0aW9uOiAnQmVhcmVyICcgKyBzZXJ2aWNlT3B0aW9ucy50b2tlblxuICAgICAgICB9O1xuICAgIH1cblxuICAgIHZhciBodHRwID0gbmV3IFRyYW5zcG9ydEZhY3RvcnkodHJhbnNwb3J0T3B0aW9ucyk7XG4gICAgdmFyIHBhcnNlUnVuSWRPckVycm9yID0gZnVuY3Rpb24gKHBhcmFtcykge1xuICAgICAgICBpZiAoJC5pc1BsYWluT2JqZWN0KHBhcmFtcykgJiYgcGFyYW1zLnJ1bklkKSB7XG4gICAgICAgICAgICByZXR1cm4gcGFyYW1zLnJ1bklkO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdQbGVhc2UgcGFzcyBpbiBhIHJ1biBpZCcpO1xuICAgICAgICB9XG4gICAgfTtcblxuICAgIHZhciBwdWJsaWNBUEkgPSB7XG5cbiAgICAgICAgLyoqXG4gICAgICAgICogVmlldyB0aGUgaGlzdG9yeSBvZiBhIHJ1bi5cbiAgICAgICAgKiBcbiAgICAgICAgKiAgKipFeGFtcGxlKipcbiAgICAgICAgKlxuICAgICAgICAqICAgICAgdmFyIHNhID0gbmV3IEYuc2VydmljZS5TdGF0ZSgpO1xuICAgICAgICAqICAgICAgc2EubG9hZCgnMDAwMDAxNWEwNmJiNTg2MTNiMjhiNTczNjU2NzdlYzg5ZWM1JykudGhlbihmdW5jdGlvbihoaXN0b3J5KSB7XG4gICAgICAgICogICAgICAgICAgICBjb25zb2xlLmxvZygnaGlzdG9yeSA9ICcsIGhpc3RvcnkpO1xuICAgICAgICAqICAgICAgfSk7XG4gICAgICAgICpcbiAgICAgICAgKiAgKipQYXJhbWV0ZXJzKipcbiAgICAgICAgKiBAcGFyYW0ge3N0cmluZ30gcnVuSWQgVGhlIGlkIG9mIHRoZSBydW4uXG4gICAgICAgICogQHBhcmFtIHtvYmplY3R9IG9wdGlvbnMgKE9wdGlvbmFsKSBPdmVycmlkZXMgZm9yIGNvbmZpZ3VyYXRpb24gb3B0aW9ucy5cbiAgICAgICAgKiBAcmV0dXJuIHtQcm9taXNlfVxuICAgICAgICAqL1xuICAgICAgICBsb2FkOiBmdW5jdGlvbiAocnVuSWQsIG9wdGlvbnMpIHtcbiAgICAgICAgICAgIHZhciBodHRwUGFyYW1zID0gJC5leHRlbmQodHJ1ZSwge30sXG4gICAgICAgICAgICAgICAgc2VydmljZU9wdGlvbnMsXG4gICAgICAgICAgICAgICAgb3B0aW9ucyxcbiAgICAgICAgICAgICAgICB7IHVybDogdXJsQ29uZmlnLmdldEFQSVBhdGgoYXBpRW5kcG9pbnQpICsgcnVuSWQgfVxuICAgICAgICAgICAgKTtcbiAgICAgICAgICAgIHJldHVybiBodHRwLmdldCgnJywgaHR0cFBhcmFtcyk7XG4gICAgICAgIH0sXG5cbiAgICAgICAgLyoqXG4gICAgICAgICogUmVwbGF5IGEgcnVuLiBBZnRlciB0aGlzIGNhbGwsIHRoZSBydW4sIHdpdGggaXRzIG9yaWdpbmFsIHJ1biBpZCwgaXMgbm93IGF2YWlsYWJsZSBbaW4gbWVtb3J5XSguLi8uLi8uLi9ydW5fcGVyc2lzdGVuY2UvI3J1bnMtaW4tbWVtb3J5KS4gKEl0IGNvbnRpbnVlcyB0byBiZSBwZXJzaXN0ZWQgaW50byB0aGUgRXBpY2VudGVyIGRhdGFiYXNlIGF0IHJlZ3VsYXIgaW50ZXJ2YWxzLilcbiAgICAgICAgKlxuICAgICAgICAqICAqKkV4YW1wbGUqKlxuICAgICAgICAqXG4gICAgICAgICogICAgICB2YXIgc2EgPSBuZXcgRi5zZXJ2aWNlLlN0YXRlKCk7XG4gICAgICAgICogICAgICBzYS5yZXBsYXkoe3J1bklkOiAnMTg0MmJiNWMtODNhZC00YmE4LWE5NTUtYmQxM2NjMmZkYjRmJywgc3RvcEJlZm9yZTogJ2NhbGN1bGF0ZVNjb3JlJ30pO1xuICAgICAgICAqXG4gICAgICAgICogICoqUGFyYW1ldGVycyoqXG4gICAgICAgICogQHBhcmFtIHtvYmplY3R9IHBhcmFtcyBQYXJhbWV0ZXJzIG9iamVjdC5cbiAgICAgICAgKiBAcGFyYW0ge3N0cmluZ30gcGFyYW1zLnJ1bklkIFRoZSBpZCBvZiB0aGUgcnVuIHRvIGJyaW5nIGJhY2sgdG8gbWVtb3J5LlxuICAgICAgICAqIEBwYXJhbSB7c3RyaW5nfSBwYXJhbXMuc3RvcEJlZm9yZSAoT3B0aW9uYWwpIFRoZSBydW4gaXMgYWR2YW5jZWQgb25seSB1cCB0byB0aGUgZmlyc3Qgb2NjdXJyZW5jZSBvZiB0aGlzIG1ldGhvZC5cbiAgICAgICAgKiBAcGFyYW0ge2FycmF5fSBwYXJhbXMuZXhjbHVkZSAoT3B0aW9uYWwpIEFycmF5IG9mIG1ldGhvZHMgdG8gZXhjbHVkZSB3aGVuIGFkdmFuY2luZyB0aGUgcnVuLlxuICAgICAgICAqIEBwYXJhbSB7b2JqZWN0fSBvcHRpb25zIChPcHRpb25hbCkgT3ZlcnJpZGVzIGZvciBjb25maWd1cmF0aW9uIG9wdGlvbnMuXG4gICAgICAgICogQHJldHVybiB7UHJvbWlzZX1cbiAgICAgICAgKi9cbiAgICAgICAgcmVwbGF5OiBmdW5jdGlvbiAocGFyYW1zLCBvcHRpb25zKSB7XG4gICAgICAgICAgICB2YXIgcnVuSWQgPSBwYXJzZVJ1bklkT3JFcnJvcihwYXJhbXMpO1xuXG4gICAgICAgICAgICB2YXIgcmVwbGF5T3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LFxuICAgICAgICAgICAgICAgIHNlcnZpY2VPcHRpb25zLFxuICAgICAgICAgICAgICAgIG9wdGlvbnMsXG4gICAgICAgICAgICAgICAgeyB1cmw6IHVybENvbmZpZy5nZXRBUElQYXRoKGFwaUVuZHBvaW50KSArIHJ1bklkIH1cbiAgICAgICAgICAgICk7XG5cbiAgICAgICAgICAgIHBhcmFtcyA9ICQuZXh0ZW5kKHRydWUsIHsgYWN0aW9uOiAncmVwbGF5JyB9LCBfcGljayhwYXJhbXMsIFsnc3RvcEJlZm9yZScsICdleGNsdWRlJ10pKTtcblxuICAgICAgICAgICAgcmV0dXJuIGh0dHAucG9zdChwYXJhbXMsIHJlcGxheU9wdGlvbnMpO1xuICAgICAgICB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAqIENsb25lIGEgZ2l2ZW4gcnVuIGFuZCByZXR1cm4gYSBuZXcgcnVuIGluIHRoZSBzYW1lIHN0YXRlIGFzIHRoZSBnaXZlbiBydW4uXG4gICAgICAgICpcbiAgICAgICAgKiBUaGUgbmV3IHJ1biBpZCBpcyBub3cgYXZhaWxhYmxlIFtpbiBtZW1vcnldKC4uLy4uLy4uL3J1bl9wZXJzaXN0ZW5jZS8jcnVucy1pbi1tZW1vcnkpLiBUaGUgbmV3IHJ1biBpbmNsdWRlcyBhIGNvcHkgb2YgYWxsIG9mIHRoZSBkYXRhIGZyb20gdGhlIG9yaWdpbmFsIHJ1biwgRVhDRVBUOlxuICAgICAgICAqXG4gICAgICAgICogKiBUaGUgYHNhdmVkYCBmaWVsZCBpbiB0aGUgbmV3IHJ1biByZWNvcmQgaXMgbm90IGNvcGllZCBmcm9tIHRoZSBvcmlnaW5hbCBydW4gcmVjb3JkLiBJdCBkZWZhdWx0cyB0byBgZmFsc2VgLlxuICAgICAgICAqICogVGhlIGBpbml0aWFsaXplZGAgZmllbGQgaW4gdGhlIG5ldyBydW4gcmVjb3JkIGlzIG5vdCBjb3BpZWQgZnJvbSB0aGUgb3JpZ2luYWwgcnVuIHJlY29yZC4gSXQgZGVmYXVsdHMgdG8gYGZhbHNlYCBidXQgbWF5IGNoYW5nZSB0byBgdHJ1ZWAgYXMgdGhlIG5ldyBydW4gaXMgYWR2YW5jZWQuIEZvciBleGFtcGxlLCBpZiB0aGVyZSBoYXMgYmVlbiBhIGNhbGwgdG8gdGhlIGBzdGVwYCBmdW5jdGlvbiAoZm9yIFZlbnNpbSBtb2RlbHMpLCB0aGUgYGluaXRpYWxpemVkYCBmaWVsZCBpcyBzZXQgdG8gYHRydWVgLlxuICAgICAgICAqICogVGhlIGBjcmVhdGVkYCBmaWVsZCBpbiB0aGUgbmV3IHJ1biByZWNvcmQgaXMgdGhlIGRhdGUgYW5kIHRpbWUgYXQgd2hpY2ggdGhlIGNsb25lIHdhcyBjcmVhdGVkIChub3QgdGhlIHRpbWUgdGhhdCB0aGUgb3JpZ2luYWwgcnVuIHdhcyBjcmVhdGVkLilcbiAgICAgICAgKlxuICAgICAgICAqIFRoZSBvcmlnaW5hbCBydW4gcmVtYWlucyBvbmx5IFtpbiB0aGUgZGF0YWJhc2VdKC4uLy4uLy4uL3J1bl9wZXJzaXN0ZW5jZS8jcnVucy1pbi1kYikuXG4gICAgICAgICpcbiAgICAgICAgKiAgKipFeGFtcGxlKipcbiAgICAgICAgKlxuICAgICAgICAqICAgICAgdmFyIHNhID0gbmV3IEYuc2VydmljZS5TdGF0ZSgpO1xuICAgICAgICAqICAgICAgc2EuY2xvbmUoe3J1bklkOiAnMTg0MmJiNWMtODNhZC00YmE4LWE5NTUtYmQxM2NjMmZkYjRmJywgc3RvcEJlZm9yZTogJ2NhbGN1bGF0ZVNjb3JlJywgZXhjbHVkZTogWydpbnRlcmltQ2FsY3VsYXRpb24nXSB9KTtcbiAgICAgICAgKlxuICAgICAgICAqICAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAqIEBwYXJhbSB7b2JqZWN0fSBwYXJhbXMgUGFyYW1ldGVycyBvYmplY3QuXG4gICAgICAgICogQHBhcmFtIHtzdHJpbmd9IHBhcmFtcy5ydW5JZCBUaGUgaWQgb2YgdGhlIHJ1biB0byBjbG9uZSBmcm9tIG1lbW9yeS5cbiAgICAgICAgKiBAcGFyYW0ge3N0cmluZ30gcGFyYW1zLnN0b3BCZWZvcmUgKE9wdGlvbmFsKSBUaGUgbmV3bHkgY2xvbmVkIHJ1biBpcyBhZHZhbmNlZCBvbmx5IHVwIHRvIHRoZSBmaXJzdCBvY2N1cnJlbmNlIG9mIHRoaXMgbWV0aG9kLlxuICAgICAgICAqIEBwYXJhbSB7YXJyYXl9IHBhcmFtcy5leGNsdWRlIChPcHRpb25hbCkgQXJyYXkgb2YgbWV0aG9kcyB0byBleGNsdWRlIHdoZW4gYWR2YW5jaW5nIHRoZSBuZXdseSBjbG9uZWQgcnVuLlxuICAgICAgICAqIEBwYXJhbSB7b2JqZWN0fSBvcHRpb25zIChPcHRpb25hbCkgT3ZlcnJpZGVzIGZvciBjb25maWd1cmF0aW9uIG9wdGlvbnMuXG4gICAgICAgICogQHJldHVybiB7UHJvbWlzZX1cbiAgICAgICAgKi9cbiAgICAgICAgY2xvbmU6IGZ1bmN0aW9uIChwYXJhbXMsIG9wdGlvbnMpIHtcbiAgICAgICAgICAgIHZhciBydW5JZCA9IHBhcnNlUnVuSWRPckVycm9yKHBhcmFtcyk7XG5cbiAgICAgICAgICAgIHZhciByZXBsYXlPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sXG4gICAgICAgICAgICAgICAgc2VydmljZU9wdGlvbnMsXG4gICAgICAgICAgICAgICAgb3B0aW9ucyxcbiAgICAgICAgICAgICAgICB7IHVybDogdXJsQ29uZmlnLmdldEFQSVBhdGgoYXBpRW5kcG9pbnQpICsgcnVuSWQgfVxuICAgICAgICAgICAgKTtcblxuICAgICAgICAgICAgcGFyYW1zID0gJC5leHRlbmQodHJ1ZSwgeyBhY3Rpb246ICdjbG9uZScgfSwgX3BpY2socGFyYW1zLCBbJ3N0b3BCZWZvcmUnLCAnZXhjbHVkZSddKSk7XG5cbiAgICAgICAgICAgIHJldHVybiBodHRwLnBvc3QocGFyYW1zLCByZXBsYXlPcHRpb25zKTtcbiAgICAgICAgfVxuICAgIH07XG5cbiAgICAkLmV4dGVuZCh0aGlzLCBwdWJsaWNBUEkpO1xufTtcbiIsIid1c2Ugc3RyaWN0JztcblxudmFyIGVwaVZlcnNpb24gPSByZXF1aXJlKCcuLi9hcGktdmVyc2lvbi5qc29uJyk7XG5cbi8vVE9ETzogdXJsdXRpbHMgdG8gZ2V0IGhvc3QsIHNpbmNlIG5vIHdpbmRvdyBvbiBub2RlXG52YXIgZGVmYXVsdHMgPSB7XG4gICAgaG9zdDogd2luZG93LmxvY2F0aW9uLmhvc3QsXG4gICAgcGF0aG5hbWU6IHdpbmRvdy5sb2NhdGlvbi5wYXRobmFtZVxufTtcblxuZnVuY3Rpb24gZ2V0TG9jYWxIb3N0KGV4aXN0aW5nRm4sIGhvc3QpIHtcbiAgICB2YXIgbG9jYWxIb3N0Rm47XG4gICAgaWYgKGV4aXN0aW5nRm4gIT09IHVuZGVmaW5lZCkge1xuICAgICAgICBpZiAoISQuaXNGdW5jdGlvbihleGlzdGluZ0ZuKSkge1xuICAgICAgICAgICAgbG9jYWxIb3N0Rm4gPSBmdW5jdGlvbiAoKSB7IHJldHVybiBleGlzdGluZ0ZuOyB9O1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgbG9jYWxIb3N0Rm4gPSBleGlzdGluZ0ZuO1xuICAgICAgICB9XG4gICAgfSBlbHNlIHtcbiAgICAgICAgbG9jYWxIb3N0Rm4gPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICB2YXIgaXNMb2NhbCA9ICFob3N0IHx8IC8vcGhhbnRvbWpzXG4gICAgICAgICAgICAgICAgaG9zdCA9PT0gJzEyNy4wLjAuMScgfHwgXG4gICAgICAgICAgICAgICAgaG9zdC5pbmRleE9mKCdsb2NhbC4nKSA9PT0gMCB8fCBcbiAgICAgICAgICAgICAgICBob3N0LmluZGV4T2YoJ2xvY2FsaG9zdCcpID09PSAwO1xuICAgICAgICAgICAgcmV0dXJuIGlzTG9jYWw7XG4gICAgICAgIH07XG4gICAgfVxuICAgIHJldHVybiBsb2NhbEhvc3RGbjtcbn1cblxudmFyIFVybENvbmZpZ1NlcnZpY2UgPSBmdW5jdGlvbiAoY29uZmlnKSB7XG4gICAgdmFyIGVudkNvbmYgPSBVcmxDb25maWdTZXJ2aWNlLmRlZmF1bHRzO1xuXG4gICAgaWYgKCFjb25maWcpIHtcbiAgICAgICAgY29uZmlnID0ge307XG4gICAgfVxuICAgIC8vIGNvbnNvbGUubG9nKHRoaXMuZGVmYXVsdHMpO1xuICAgIHZhciBvdmVycmlkZXMgPSAkLmV4dGVuZCh7fSwgZW52Q29uZiwgY29uZmlnKTtcbiAgICB2YXIgb3B0aW9ucyA9ICQuZXh0ZW5kKHt9LCBkZWZhdWx0cywgb3ZlcnJpZGVzKTtcblxuICAgIG92ZXJyaWRlcy5pc0xvY2FsaG9zdCA9IG9wdGlvbnMuaXNMb2NhbGhvc3QgPSBnZXRMb2NhbEhvc3Qob3B0aW9ucy5pc0xvY2FsaG9zdCwgb3B0aW9ucy5ob3N0KTtcbiAgICBcbiAgICAvLyBjb25zb2xlLmxvZyhpc0xvY2FsaG9zdCgpLCAnX19fX19fX19fX18nKTtcbiAgICB2YXIgYWN0aW5nSG9zdCA9IGNvbmZpZyAmJiBjb25maWcuaG9zdDtcbiAgICBpZiAoIWFjdGluZ0hvc3QgJiYgb3B0aW9ucy5pc0xvY2FsaG9zdCgpKSB7XG4gICAgICAgIGFjdGluZ0hvc3QgPSAnZm9yaW8uY29tJztcbiAgICB9IGVsc2Uge1xuICAgICAgICBhY3RpbmdIb3N0ID0gb3B0aW9ucy5ob3N0O1xuICAgIH1cblxuICAgIHZhciBBUElfUFJPVE9DT0wgPSAnaHR0cHMnO1xuICAgIHZhciBIT1NUX0FQSV9NQVBQSU5HID0ge1xuICAgICAgICAnZm9yaW8uY29tJzogJ2FwaS5mb3Jpby5jb20nLFxuICAgICAgICAnZm9yaW9kZXYuY29tJzogJ2FwaS5lcGljZW50ZXIuZm9yaW9kZXYuY29tJ1xuICAgIH07XG5cbiAgICB2YXIgcHVibGljRXhwb3J0cyA9IHtcbiAgICAgICAgcHJvdG9jb2w6IEFQSV9QUk9UT0NPTCxcblxuICAgICAgICBhcGk6ICcnLFxuXG4gICAgICAgIC8vVE9ETzogdGhpcyBzaG91bGQgcmVhbGx5IGJlIGNhbGxlZCAnYXBpaG9zdCcsIGJ1dCBjYW4ndCBiZWNhdXNlIHRoYXQgd291bGQgYnJlYWsgdG9vIG1hbnkgdGhpbmdzXG4gICAgICAgIGhvc3Q6IChmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICB2YXIgYXBpSG9zdCA9IChIT1NUX0FQSV9NQVBQSU5HW2FjdGluZ0hvc3RdKSA/IEhPU1RfQVBJX01BUFBJTkdbYWN0aW5nSG9zdF0gOiBhY3RpbmdIb3N0O1xuICAgICAgICAgICAgLy8gY29uc29sZS5sb2coYWN0aW5nSG9zdCwgY29uZmlnLCBhcGlIb3N0KTtcbiAgICAgICAgICAgIHJldHVybiBhcGlIb3N0O1xuICAgICAgICB9KCkpLFxuXG4gICAgICAgIGlzQ3VzdG9tRG9tYWluOiAoZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgdmFyIHBhdGggPSBvcHRpb25zLnBhdGhuYW1lLnNwbGl0KCdcXC8nKTtcbiAgICAgICAgICAgIHZhciBwYXRoSGFzQXBwID0gcGF0aCAmJiBwYXRoWzFdID09PSAnYXBwJztcbiAgICAgICAgICAgIHJldHVybiAoIW9wdGlvbnMuaXNMb2NhbGhvc3QoKSAmJiAhcGF0aEhhc0FwcCk7XG4gICAgICAgIH0oKSksXG5cbiAgICAgICAgYXBwUGF0aDogKGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIHZhciBwYXRoID0gb3B0aW9ucy5wYXRobmFtZS5zcGxpdCgnXFwvJyk7XG5cbiAgICAgICAgICAgIHJldHVybiBwYXRoICYmIHBhdGhbMV0gfHwgJyc7XG4gICAgICAgIH0oKSksXG5cbiAgICAgICAgYWNjb3VudFBhdGg6IChmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICB2YXIgYWNjbnQgPSAnJztcbiAgICAgICAgICAgIHZhciBwYXRoID0gb3B0aW9ucy5wYXRobmFtZS5zcGxpdCgnXFwvJyk7XG4gICAgICAgICAgICBpZiAocGF0aCAmJiBwYXRoWzFdID09PSAnYXBwJykge1xuICAgICAgICAgICAgICAgIGFjY250ID0gcGF0aFsyXTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHJldHVybiBhY2NudDtcbiAgICAgICAgfSgpKSxcblxuICAgICAgICBwcm9qZWN0UGF0aDogKGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIHZhciBwcmogPSAnJztcbiAgICAgICAgICAgIHZhciBwYXRoID0gb3B0aW9ucy5wYXRobmFtZS5zcGxpdCgnXFwvJyk7XG4gICAgICAgICAgICBpZiAocGF0aCAmJiBwYXRoWzFdID09PSAnYXBwJykge1xuICAgICAgICAgICAgICAgIHByaiA9IHBhdGhbM107IC8vZXNsaW50LWRpc2FibGUtbGluZSBuby1tYWdpYy1udW1iZXJzXG4gICAgICAgICAgICB9XG4gICAgICAgICAgICByZXR1cm4gcHJqO1xuICAgICAgICB9KCkpLFxuXG4gICAgICAgIHZlcnNpb25QYXRoOiAoZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgdmFyIHZlcnNpb24gPSBlcGlWZXJzaW9uLnZlcnNpb24gPyBlcGlWZXJzaW9uLnZlcnNpb24gKyAnLycgOiAnJztcbiAgICAgICAgICAgIHJldHVybiB2ZXJzaW9uO1xuICAgICAgICB9KCkpLFxuXG4gICAgICAgIGdldEFQSVBhdGg6IGZ1bmN0aW9uIChhcGkpIHtcbiAgICAgICAgICAgIHZhciBQUk9KRUNUX0FQSVMgPSBbJ3J1bicsICdkYXRhJywgJ2ZpbGUnLCAncHJlc2VuY2UnXTtcbiAgICAgICAgICAgIHZhciBhcGlNYXBwaW5nID0ge1xuICAgICAgICAgICAgICAgIGNoYW5uZWw6ICdjaGFubmVsL3N1YnNjcmliZSdcbiAgICAgICAgICAgIH07XG4gICAgICAgICAgICB2YXIgYXBpRW5kcG9pbnQgPSBhcGlNYXBwaW5nW2FwaV0gfHwgYXBpO1xuICAgICAgICAgICAgXG4gICAgICAgICAgICBpZiAoYXBpRW5kcG9pbnQgPT09ICdjb25maWcnKSB7XG4gICAgICAgICAgICAgICAgdmFyIGFjdHVhbFByb3RvY29sID0gd2luZG93LmxvY2F0aW9uLnByb3RvY29sLnJlcGxhY2UoJzonLCAnJyk7XG4gICAgICAgICAgICAgICAgdmFyIGNvbmZpZ1Byb3RvY29sID0gKG9wdGlvbnMuaXNMb2NhbGhvc3QoKSkgPyB0aGlzLnByb3RvY29sIDogYWN0dWFsUHJvdG9jb2w7XG4gICAgICAgICAgICAgICAgcmV0dXJuIGNvbmZpZ1Byb3RvY29sICsgJzovLycgKyBhY3RpbmdIb3N0ICsgJy9lcGljZW50ZXIvJyArIHRoaXMudmVyc2lvblBhdGggKyAnY29uZmlnJztcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHZhciBhcGlQYXRoID0gdGhpcy5wcm90b2NvbCArICc6Ly8nICsgdGhpcy5ob3N0ICsgJy8nICsgdGhpcy52ZXJzaW9uUGF0aCArIGFwaUVuZHBvaW50ICsgJy8nO1xuXG4gICAgICAgICAgICBpZiAoJC5pbkFycmF5KGFwaUVuZHBvaW50LCBQUk9KRUNUX0FQSVMpICE9PSAtMSkge1xuICAgICAgICAgICAgICAgIGFwaVBhdGggKz0gdGhpcy5hY2NvdW50UGF0aCArICcvJyArIHRoaXMucHJvamVjdFBhdGggKyAnLyc7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICByZXR1cm4gYXBpUGF0aDtcbiAgICAgICAgfVxuICAgIH07XG5cblxuICAgICQuZXh0ZW5kKHB1YmxpY0V4cG9ydHMsIG92ZXJyaWRlcyk7XG4gICAgcmV0dXJuIHB1YmxpY0V4cG9ydHM7XG59O1xuLy8gVGhpcyBkYXRhIGNhbiBiZSBzZXQgYnkgZXh0ZXJuYWwgc2NyaXB0cywgZm9yIGxvYWRpbmcgZnJvbSBhbiBlbnYgc2VydmVyIGZvciBlZztcblVybENvbmZpZ1NlcnZpY2UuZGVmYXVsdHMgPSB7fTtcblxubW9kdWxlLmV4cG9ydHMgPSBVcmxDb25maWdTZXJ2aWNlO1xuIiwiJ3VzZSBzdHJpY3QnO1xuLyoqXG4qICMjIFVzZXIgQVBJIEFkYXB0ZXJcbipcbiogVGhlIFVzZXIgQVBJIEFkYXB0ZXIgYWxsb3dzIHlvdSB0byByZXRyaWV2ZSBkZXRhaWxzIGFib3V0IGVuZCB1c2VycyBpbiB5b3VyIHRlYW0gKGFjY291bnQpLiBJdCBpcyBiYXNlZCBvbiB0aGUgcXVlcnlpbmcgY2FwYWJpbGl0aWVzIG9mIHRoZSB1bmRlcmx5aW5nIFJFU1RmdWwgW1VzZXIgQVBJXSguLi8uLi8uLi9yZXN0X2FwaXMvdXNlcl9tYW5hZ2VtZW50L3VzZXIvKS5cbipcbiogVG8gdXNlIHRoZSBVc2VyIEFQSSBBZGFwdGVyLCBpbnN0YW50aWF0ZSBpdCBhbmQgdGhlbiBjYWxsIGl0cyBtZXRob2RzLlxuKlxuKiAgICAgICB2YXIgdWEgPSBuZXcgRi5zZXJ2aWNlLlVzZXIoe1xuKiAgICAgICAgICAgYWNjb3VudDogJ2FjbWUtc2ltdWxhdGlvbnMnLFxuKiAgICAgICAgICAgdG9rZW46ICd1c2VyLW9yLXByb2plY3QtYWNjZXNzLXRva2VuJ1xuKiAgICAgICB9KTtcbiogICAgICAgdWEuZ2V0QnlJZCgnNDI4MzZkNGItNWI2MS00ZmU0LTgwZWItMzEzNmU5NTZlZTVjJyk7XG4qICAgICAgIHVhLmdldCh7IHVzZXJOYW1lOiAnanNtaXRoJyB9KTtcbiogICAgICAgdWEuZ2V0KHsgaWQ6IFsnNDI4MzZkNGItNWI2MS00ZmU0LTgwZWItMzEzNmU5NTZlZTVjJyxcbiogICAgICAgICAgICAgICAgICAgJzRlYTc1NjMxLTRjOGQtNDg3Mi05ZDgwLWI0NjAwMTQ2NDc4ZSddIH0pO1xuKlxuKiBUaGUgY29uc3RydWN0b3IgdGFrZXMgYW4gb3B0aW9uYWwgYG9wdGlvbnNgIHBhcmFtZXRlciBpbiB3aGljaCB5b3UgY2FuIHNwZWNpZnkgdGhlIGBhY2NvdW50YCBhbmQgYHRva2VuYCBpZiB0aGV5IGFyZSBub3QgYWxyZWFkeSBhdmFpbGFibGUgaW4gdGhlIGN1cnJlbnQgY29udGV4dC5cbiovXG5cbnZhciBDb25maWdTZXJ2aWNlID0gcmVxdWlyZSgnLi9jb25maWd1cmF0aW9uLXNlcnZpY2UnKTtcbnZhciBUcmFuc3BvcnRGYWN0b3J5ID0gcmVxdWlyZSgnLi4vdHJhbnNwb3J0L2h0dHAtdHJhbnNwb3J0LWZhY3RvcnknKTtcbnZhciBTZXNzaW9uTWFuYWdlciA9IHJlcXVpcmUoJy4uL3N0b3JlL3Nlc3Npb24tbWFuYWdlcicpO1xudmFyIHF1dGlsID0gcmVxdWlyZSgnLi4vdXRpbC9xdWVyeS11dGlsJyk7XG5cbm1vZHVsZS5leHBvcnRzID0gZnVuY3Rpb24gKGNvbmZpZykge1xuICAgIHZhciBkZWZhdWx0cyA9IHtcblxuICAgICAgICAvKipcbiAgICAgICAgICogVGhlIGFjY291bnQgaWQuIEluIHRoZSBFcGljZW50ZXIgVUksIHRoaXMgaXMgdGhlICoqVGVhbSBJRCoqIChmb3IgdGVhbSBwcm9qZWN0cykgb3IgKipVc2VyIElEKiogKGZvciBwZXJzb25hbCBwcm9qZWN0cykuIERlZmF1bHRzIHRvIGVtcHR5IHN0cmluZy5cbiAgICAgICAgICogQHR5cGUge1N0cmluZ31cbiAgICAgICAgICovXG4gICAgICAgIGFjY291bnQ6IHVuZGVmaW5lZCxcblxuICAgICAgICAvKipcbiAgICAgICAgICogVGhlIGFjY2VzcyB0b2tlbiB0byB1c2Ugd2hlbiBzZWFyY2hpbmcgZm9yIGVuZCB1c2Vycy4gKFNlZSBbbW9yZSBiYWNrZ3JvdW5kIG9uIGFjY2VzcyB0b2tlbnNdKC4uLy4uLy4uL3Byb2plY3RfYWNjZXNzLykpLlxuICAgICAgICAgKiBAdHlwZSB7U3RyaW5nfVxuICAgICAgICAgKi9cbiAgICAgICAgdG9rZW46IHVuZGVmaW5lZCxcblxuICAgICAgICAvKipcbiAgICAgICAgICogT3B0aW9ucyB0byBwYXNzIG9uIHRvIHRoZSB1bmRlcmx5aW5nIHRyYW5zcG9ydCBsYXllci4gQWxsIGpxdWVyeS5hamF4IG9wdGlvbnMgYXQgaHR0cDovL2FwaS5qcXVlcnkuY29tL2pRdWVyeS5hamF4LyBhcmUgYXZhaWxhYmxlLiBEZWZhdWx0cyB0byBlbXB0eSBvYmplY3QuXG4gICAgICAgICAqIEB0eXBlIHtPYmplY3R9XG4gICAgICAgICAqL1xuICAgICAgICB0cmFuc3BvcnQ6IHt9XG4gICAgfTtcblxuICAgIHRoaXMuc2Vzc2lvbk1hbmFnZXIgPSBuZXcgU2Vzc2lvbk1hbmFnZXIoKTtcbiAgICB2YXIgc2VydmljZU9wdGlvbnMgPSB0aGlzLnNlc3Npb25NYW5hZ2VyLmdldE1lcmdlZE9wdGlvbnMoZGVmYXVsdHMsIGNvbmZpZyk7XG4gICAgdmFyIHVybENvbmZpZyA9IG5ldyBDb25maWdTZXJ2aWNlKHNlcnZpY2VPcHRpb25zKS5nZXQoJ3NlcnZlcicpO1xuICAgIHZhciB0cmFuc3BvcnRPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sIHNlcnZpY2VPcHRpb25zLnRyYW5zcG9ydCwge1xuICAgICAgICB1cmw6IHVybENvbmZpZy5nZXRBUElQYXRoKCd1c2VyJylcbiAgICB9KTtcblxuICAgIGlmIChzZXJ2aWNlT3B0aW9ucy50b2tlbikge1xuICAgICAgICB0cmFuc3BvcnRPcHRpb25zLmhlYWRlcnMgPSB7XG4gICAgICAgICAgICBBdXRob3JpemF0aW9uOiAnQmVhcmVyICcgKyBzZXJ2aWNlT3B0aW9ucy50b2tlblxuICAgICAgICB9O1xuICAgIH1cblxuICAgIHZhciBodHRwID0gbmV3IFRyYW5zcG9ydEZhY3RvcnkodHJhbnNwb3J0T3B0aW9ucyk7XG5cbiAgICB2YXIgcHVibGljQVBJID0ge1xuXG4gICAgICAgIC8qKlxuICAgICAgICAqIFJldHJpZXZlIGRldGFpbHMgYWJvdXQgcGFydGljdWxhciBlbmQgdXNlcnMgaW4geW91ciB0ZWFtLCBiYXNlZCBvbiB1c2VyIG5hbWUgb3IgdXNlciBpZC5cbiAgICAgICAgKlxuICAgICAgICAqICoqRXhhbXBsZSoqXG4gICAgICAgICpcbiAgICAgICAgKiAgICAgICB2YXIgdWEgPSBuZXcgRi5zZXJ2aWNlLlVzZXIoe1xuICAgICAgICAqICAgICAgICAgICBhY2NvdW50OiAnYWNtZS1zaW11bGF0aW9ucycsXG4gICAgICAgICogICAgICAgICAgIHRva2VuOiAndXNlci1vci1wcm9qZWN0LWFjY2Vzcy10b2tlbidcbiAgICAgICAgKiAgICAgICB9KTtcbiAgICAgICAgKiAgICAgICB1YS5nZXQoeyB1c2VyTmFtZTogJ2pzbWl0aCcgfSk7XG4gICAgICAgICogICAgICAgdWEuZ2V0KHsgaWQ6IFsnNDI4MzZkNGItNWI2MS00ZmU0LTgwZWItMzEzNmU5NTZlZTVjJyxcbiAgICAgICAgKiAgICAgICAgICAgICAgICAgICAnNGVhNzU2MzEtNGM4ZC00ODcyLTlkODAtYjQ2MDAxNDY0NzhlJ10gfSk7XG4gICAgICAgICpcbiAgICAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAqIEBwYXJhbSB7b2JqZWN0fSBmaWx0ZXIgT2JqZWN0IHdpdGggZmllbGQgYHVzZXJOYW1lYCBhbmQgdmFsdWUgb2YgdGhlIHVzZXJuYW1lLiBBbHRlcm5hdGl2ZWx5LCBvYmplY3Qgd2l0aCBmaWVsZCBgaWRgIGFuZCB2YWx1ZSBvZiBhbiBhcnJheSBvZiB1c2VyIGlkcy5cbiAgICAgICAgKiBAcGFyYW0ge29iamVjdH0gb3B0aW9ucyAoT3B0aW9uYWwpIE92ZXJyaWRlcyBmb3IgY29uZmlndXJhdGlvbiBvcHRpb25zLlxuICAgICAgICAqIEByZXR1cm4ge1Byb21pc2V9XG4gICAgICAgICovXG5cbiAgICAgICAgZ2V0OiBmdW5jdGlvbiAoZmlsdGVyLCBvcHRpb25zKSB7XG4gICAgICAgICAgICBvcHRpb25zID0gb3B0aW9ucyB8fCB7fTtcbiAgICAgICAgICAgIGZpbHRlciA9IGZpbHRlciB8fCB7fTtcblxuICAgICAgICAgICAgdmFyIGdldE9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSxcbiAgICAgICAgICAgICAgICBzZXJ2aWNlT3B0aW9ucyxcbiAgICAgICAgICAgICAgICBvcHRpb25zXG4gICAgICAgICAgICApO1xuXG4gICAgICAgICAgICB2YXIgdG9RRmlsdGVyID0gZnVuY3Rpb24gKGZpbHRlcikge1xuICAgICAgICAgICAgICAgIHZhciByZXMgPSB7fTtcblxuICAgICAgICAgICAgICAgIC8vIEFQSSBvbmx5IHN1cHBvcnRzIGZpbHRlcmluZyBieSB1c2VybmFtZSBmb3Igbm93XG4gICAgICAgICAgICAgICAgaWYgKGZpbHRlci51c2VyTmFtZSkge1xuICAgICAgICAgICAgICAgICAgICByZXMucSA9IGZpbHRlci51c2VyTmFtZTtcbiAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICByZXR1cm4gcmVzO1xuICAgICAgICAgICAgfTtcblxuICAgICAgICAgICAgdmFyIHRvSWRGaWx0ZXJzID0gZnVuY3Rpb24gKGlkKSB7XG4gICAgICAgICAgICAgICAgaWYgKCFpZCkge1xuICAgICAgICAgICAgICAgICAgICByZXR1cm4gJyc7XG4gICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgaWQgPSAkLmlzQXJyYXkoaWQpID8gaWQgOiBbaWRdO1xuICAgICAgICAgICAgICAgIHJldHVybiAnaWQ9JyArIGlkLmpvaW4oJyZpZD0nKTtcbiAgICAgICAgICAgIH07XG5cbiAgICAgICAgICAgIHZhciBnZXRGaWx0ZXJzID0gW1xuICAgICAgICAgICAgICAgICdhY2NvdW50PScgKyBnZXRPcHRpb25zLmFjY291bnQsXG4gICAgICAgICAgICAgICAgdG9JZEZpbHRlcnMoZmlsdGVyLmlkKSxcbiAgICAgICAgICAgICAgICBxdXRpbC50b1F1ZXJ5Rm9ybWF0KHRvUUZpbHRlcihmaWx0ZXIpKVxuICAgICAgICAgICAgXS5qb2luKCcmJyk7XG5cbiAgICAgICAgICAgIC8vIHNwZWNpYWwgY2FzZSBmb3IgcXVlcmllcyB3aXRoIGxhcmdlIG51bWJlciBvZiBpZHNcbiAgICAgICAgICAgIC8vIG1ha2UgaXQgYXMgYSBwb3N0IHdpdGggR0VUIHNlbWFudGljc1xuICAgICAgICAgICAgdmFyIHRocmVzaG9sZCA9IDMwO1xuICAgICAgICAgICAgaWYgKGZpbHRlci5pZCAmJiAkLmlzQXJyYXkoZmlsdGVyLmlkKSAmJiBmaWx0ZXIuaWQubGVuZ3RoID49IHRocmVzaG9sZCkge1xuICAgICAgICAgICAgICAgIGdldE9wdGlvbnMudXJsID0gdXJsQ29uZmlnLmdldEFQSVBhdGgoJ3VzZXInKSArICc/X21ldGhvZD1HRVQnO1xuICAgICAgICAgICAgICAgIHJldHVybiBodHRwLnBvc3QoeyBpZDogZmlsdGVyLmlkIH0sIGdldE9wdGlvbnMpO1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gaHR0cC5nZXQoZ2V0RmlsdGVycywgZ2V0T3B0aW9ucyk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH0sXG5cbiAgICAgICAgLyoqXG4gICAgICAgICogUmV0cmlldmUgZGV0YWlscyBhYm91dCBhIHNpbmdsZSBlbmQgdXNlciBpbiB5b3VyIHRlYW0sIGJhc2VkIG9uIHVzZXIgaWQuXG4gICAgICAgICpcbiAgICAgICAgKiAqKkV4YW1wbGUqKlxuICAgICAgICAqXG4gICAgICAgICogICAgICAgdmFyIHVhID0gbmV3IEYuc2VydmljZS5Vc2VyKHtcbiAgICAgICAgKiAgICAgICAgICAgYWNjb3VudDogJ2FjbWUtc2ltdWxhdGlvbnMnLFxuICAgICAgICAqICAgICAgICAgICB0b2tlbjogJ3VzZXItb3ItcHJvamVjdC1hY2Nlc3MtdG9rZW4nXG4gICAgICAgICogICAgICAgfSk7XG4gICAgICAgICogICAgICAgdWEuZ2V0QnlJZCgnNDI4MzZkNGItNWI2MS00ZmU0LTgwZWItMzEzNmU5NTZlZTVjJyk7XG4gICAgICAgICpcbiAgICAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAqIEBwYXJhbSB7c3RyaW5nfSB1c2VySWQgVGhlIHVzZXIgaWQgZm9yIHRoZSBlbmQgdXNlciBpbiB5b3VyIHRlYW0uXG4gICAgICAgICogQHBhcmFtIHtvYmplY3R9IG9wdGlvbnMgKE9wdGlvbmFsKSBPdmVycmlkZXMgZm9yIGNvbmZpZ3VyYXRpb24gb3B0aW9ucy5cbiAgICAgICAgKiBAcmV0dXJuIHtQcm9taXNlfVxuICAgICAgICAqL1xuXG4gICAgICAgIGdldEJ5SWQ6IGZ1bmN0aW9uICh1c2VySWQsIG9wdGlvbnMpIHtcbiAgICAgICAgICAgIHJldHVybiBwdWJsaWNBUEkuZ2V0KHsgaWQ6IHVzZXJJZCB9LCBvcHRpb25zKTtcbiAgICAgICAgfVxuICAgIH07XG5cbiAgICAkLmV4dGVuZCh0aGlzLCBwdWJsaWNBUEkpO1xufTtcblxuXG4iLCIvKipcbiAqXG4gKiAjIyBWYXJpYWJsZXMgQVBJIFNlcnZpY2VcbiAqXG4gKiBVc2VkIGluIGNvbmp1bmN0aW9uIHdpdGggdGhlIFtSdW4gQVBJIFNlcnZpY2VdKC4uL3J1bi1hcGktc2VydmljZS8pIHRvIHJlYWQsIHdyaXRlLCBhbmQgc2VhcmNoIGZvciBzcGVjaWZpYyBtb2RlbCB2YXJpYWJsZXMuXG4gKlxuICogICAgIHZhciBybSA9IG5ldyBGLm1hbmFnZXIuUnVuTWFuYWdlcih7XG4gKiAgICAgICAgICAgcnVuOiB7XG4gKiAgICAgICAgICAgICAgIGFjY291bnQ6ICdhY21lLXNpbXVsYXRpb25zJyxcbiAqICAgICAgICAgICAgICAgcHJvamVjdDogJ3N1cHBseS1jaGFpbi1nYW1lJyxcbiAqICAgICAgICAgICAgICAgbW9kZWw6ICdzdXBwbHktY2hhaW4tbW9kZWwuamwnXG4gKiAgICAgICAgICAgfVxuICogICAgICB9KTtcbiAqICAgICBybS5nZXRSdW4oKVxuICogICAgICAgLnRoZW4oZnVuY3Rpb24oKSB7XG4gKiAgICAgICAgICB2YXIgdnMgPSBybS5ydW4udmFyaWFibGVzKCk7XG4gKiAgICAgICAgICB2cy5zYXZlKHtzYW1wbGVfaW50OiA0fSk7XG4gKiAgICAgICAgfSk7XG4gKlxuICovXG5cblxuICd1c2Ugc3RyaWN0JztcblxuIHZhciBUcmFuc3BvcnRGYWN0b3J5ID0gcmVxdWlyZSgnLi4vdHJhbnNwb3J0L2h0dHAtdHJhbnNwb3J0LWZhY3RvcnknKTtcbiB2YXIgcnV0aWwgPSByZXF1aXJlKCcuLi91dGlsL3J1bi11dGlsJyk7XG5cbiBtb2R1bGUuZXhwb3J0cyA9IGZ1bmN0aW9uIChjb25maWcpIHtcbiAgICAgdmFyIGRlZmF1bHRzID0ge1xuICAgICAgICAvKipcbiAgICAgICAgICogVGhlIHJ1bnMgb2JqZWN0IHRvIHdoaWNoIHRoZSB2YXJpYWJsZSBmaWx0ZXJzIGFwcGx5LiBEZWZhdWx0cyB0byBudWxsLlxuICAgICAgICAgKiBAdHlwZSB7cnVuU2VydmljZX1cbiAgICAgICAgICovXG4gICAgICAgICBydW5TZXJ2aWNlOiBudWxsXG4gICAgIH07XG4gICAgIHZhciBzZXJ2aWNlT3B0aW9ucyA9ICQuZXh0ZW5kKHt9LCBkZWZhdWx0cywgY29uZmlnKTtcblxuICAgICB2YXIgZ2V0VVJMID0gZnVuY3Rpb24gKCkge1xuICAgICAgICAvL1RPRE86IFJlcGxhY2Ugd2l0aCBnZXRDdXJyZW50Y29uZmlnIGluc3RlYWQ/XG4gICAgICAgICByZXR1cm4gc2VydmljZU9wdGlvbnMucnVuU2VydmljZS51cmxDb25maWcuZ2V0RmlsdGVyVVJMKCkgKyAndmFyaWFibGVzLyc7XG4gICAgIH07XG5cbiAgICAgdmFyIGFkZEF1dG9SZXN0b3JlSGVhZGVyID0gZnVuY3Rpb24gKG9wdGlvbnMpIHtcbiAgICAgICAgIHJldHVybiBzZXJ2aWNlT3B0aW9ucy5ydW5TZXJ2aWNlLnVybENvbmZpZy5hZGRBdXRvUmVzdG9yZUhlYWRlcihvcHRpb25zKTtcbiAgICAgfTtcblxuICAgICB2YXIgaHR0cE9wdGlvbnMgPSB7XG4gICAgICAgICB1cmw6IGdldFVSTFxuICAgICB9O1xuICAgICBpZiAoc2VydmljZU9wdGlvbnMudG9rZW4pIHtcbiAgICAgICAgIGh0dHBPcHRpb25zLmhlYWRlcnMgPSB7XG4gICAgICAgICAgICAgQXV0aG9yaXphdGlvbjogJ0JlYXJlciAnICsgc2VydmljZU9wdGlvbnMudG9rZW5cbiAgICAgICAgIH07XG4gICAgIH1cbiAgICAgdmFyIGh0dHAgPSBuZXcgVHJhbnNwb3J0RmFjdG9yeShodHRwT3B0aW9ucyk7XG4gICAgIGh0dHAuc3BsaXRHZXQgPSBydXRpbC5zcGxpdEdldEZhY3RvcnkoaHR0cE9wdGlvbnMpO1xuXG4gICAgIHZhciBwdWJsaWNBUEkgPSB7XG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIEdldCB2YWx1ZXMgZm9yIGEgdmFyaWFibGUuXG4gICAgICAgICAqXG4gICAgICAgICAqICoqRXhhbXBsZSoqXG4gICAgICAgICAqXG4gICAgICAgICAqICAgICAgdnMubG9hZCgnc2FtcGxlX2ludCcpXG4gICAgICAgICAqICAgICAgICAgIC50aGVuKGZ1bmN0aW9uKHZhbCl7XG4gICAgICAgICAqICAgICAgICAgICAgICAvLyB2YWwgY29udGFpbnMgdGhlIHZhbHVlIG9mIHNhbXBsZV9pbnRcbiAgICAgICAgICogICAgICAgICAgfSk7XG4gICAgICAgICAqXG4gICAgICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICAgICAqIEBwYXJhbSB7U3RyaW5nfSB2YXJpYWJsZSBOYW1lIG9mIHZhcmlhYmxlIHRvIGxvYWQuXG4gICAgICAgICAqIEBwYXJhbSB7T2JqZWN0fSBvdXRwdXRNb2RpZmllciAoT3B0aW9uYWwpIEF2YWlsYWJsZSBmaWVsZHMgaW5jbHVkZTogYHN0YXJ0cmVjb3JkYCwgYGVuZHJlY29yZGAsIGBzb3J0YCwgYW5kIGBkaXJlY3Rpb25gIChgYXNjYCBvciBgZGVzY2ApLlxuICAgICAgICAgKiBAcGFyYW0ge09iamVjdH0gb3B0aW9ucyAoT3B0aW9uYWwpIE92ZXJyaWRlcyBmb3IgY29uZmlndXJhdGlvbiBvcHRpb25zLlxuICAgICAgICAgKiBAcmV0dXJuIHtQcm9taXNlfVxuICAgICAgICAgKi9cbiAgICAgICAgIGxvYWQ6IGZ1bmN0aW9uICh2YXJpYWJsZSwgb3V0cHV0TW9kaWZpZXIsIG9wdGlvbnMpIHtcbiAgICAgICAgICAgICB2YXIgaHR0cE9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSwgc2VydmljZU9wdGlvbnMsIG9wdGlvbnMpO1xuICAgICAgICAgICAgIGh0dHBPcHRpb25zID0gYWRkQXV0b1Jlc3RvcmVIZWFkZXIoaHR0cE9wdGlvbnMpO1xuICAgICAgICAgICAgIHJldHVybiBodHRwLmdldChvdXRwdXRNb2RpZmllciwgJC5leHRlbmQoe30sIGh0dHBPcHRpb25zLCB7XG4gICAgICAgICAgICAgICAgIHVybDogZ2V0VVJMKCkgKyB2YXJpYWJsZSArICcvJ1xuICAgICAgICAgICAgIH0pKTtcbiAgICAgICAgIH0sXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIFJldHVybnMgcGFydGljdWxhciB2YXJpYWJsZXMsIGJhc2VkIG9uIGNvbmRpdGlvbnMgc3BlY2lmaWVkIGluIHRoZSBgcXVlcnlgIG9iamVjdC5cbiAgICAgICAgICpcbiAgICAgICAgICogKipFeGFtcGxlKipcbiAgICAgICAgICpcbiAgICAgICAgICogICAgICB2cy5xdWVyeShbJ3ByaWNlJywgJ3NhbGVzJ10pXG4gICAgICAgICAqICAgICAgICAgIC50aGVuKGZ1bmN0aW9uKHZhbCkge1xuICAgICAgICAgKiAgICAgICAgICAgICAgLy8gdmFsIGlzIGFuIG9iamVjdCB3aXRoIHRoZSB2YWx1ZXMgb2YgdGhlIHJlcXVlc3RlZCB2YXJpYWJsZXM6IHZhbC5wcmljZSwgdmFsLnNhbGVzXG4gICAgICAgICAqICAgICAgICAgIH0pO1xuICAgICAgICAgKlxuICAgICAgICAgKiAgICAgIHZzLnF1ZXJ5KHsgaW5jbHVkZTpbJ3ByaWNlJywgJ3NhbGVzJ10gfSk7XG4gICAgICAgICAqXG4gICAgICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICAgICAqIEBwYXJhbSB7T2JqZWN0fEFycmF5fSBxdWVyeSBUaGUgbmFtZXMgb2YgdGhlIHZhcmlhYmxlcyByZXF1ZXN0ZWQuXG4gICAgICAgICAqIEBwYXJhbSB7T2JqZWN0fSBvdXRwdXRNb2RpZmllciAoT3B0aW9uYWwpIEF2YWlsYWJsZSBmaWVsZHMgaW5jbHVkZTogYHN0YXJ0cmVjb3JkYCwgYGVuZHJlY29yZGAsIGBzb3J0YCwgYW5kIGBkaXJlY3Rpb25gIChgYXNjYCBvciBgZGVzY2ApLlxuICAgICAgICAgKiBAcGFyYW0ge09iamVjdH0gb3B0aW9ucyAoT3B0aW9uYWwpIE92ZXJyaWRlcyBmb3IgY29uZmlndXJhdGlvbiBvcHRpb25zLlxuICAgICAgICAgKiBAcmV0dXJuIHtQcm9taXNlfVxuICAgICAgICAgKi9cbiAgICAgICAgIHF1ZXJ5OiBmdW5jdGlvbiAocXVlcnksIG91dHB1dE1vZGlmaWVyLCBvcHRpb25zKSB7XG4gICAgICAgICAgICAvL1F1ZXJ5IGFuZCBvdXRwdXRNb2RpZmllciBhcmUgYm90aCBxdWVyeXN0cmluZ3MgaW4gdGhlIHVybDsgb25seSBjYWxsaW5nIHRoZW0gb3V0IHNlcGFyYXRlbHkgaGVyZSB0byBiZSBjb25zaXN0ZW50IHdpdGggdGhlIG90aGVyIGNhbGxzXG4gICAgICAgICAgICAgdmFyIGh0dHBPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sIHNlcnZpY2VPcHRpb25zLCBvcHRpb25zKTtcbiAgICAgICAgICAgICBodHRwT3B0aW9ucyA9IGFkZEF1dG9SZXN0b3JlSGVhZGVyKGh0dHBPcHRpb25zKTtcblxuICAgICAgICAgICAgIGlmICgkLmlzQXJyYXkocXVlcnkpKSB7XG4gICAgICAgICAgICAgICAgIHF1ZXJ5ID0geyBpbmNsdWRlOiBxdWVyeSB9O1xuICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAkLmV4dGVuZChxdWVyeSwgb3V0cHV0TW9kaWZpZXIpO1xuICAgICAgICAgICAgIHJldHVybiBodHRwLnNwbGl0R2V0KHF1ZXJ5LCBodHRwT3B0aW9ucyk7XG4gICAgICAgICB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBTYXZlIHZhbHVlcyB0byBtb2RlbCB2YXJpYWJsZXMuIE92ZXJ3cml0ZXMgZXhpc3RpbmcgdmFsdWVzLiBOb3RlIHRoYXQgeW91IGNhbiBvbmx5IHVwZGF0ZSBtb2RlbCB2YXJpYWJsZXMgaWYgdGhlIHJ1biBpcyBbaW4gbWVtb3J5XSguLi8uLi8uLi9ydW5fcGVyc2lzdGVuY2UvI3J1bnMtaW4tbWVtb3J5KS4gKEFuIGFsdGVybmF0ZSB3YXkgdG8gdXBkYXRlIG1vZGVsIHZhcmlhYmxlcyBpcyB0byBjYWxsIGEgbWV0aG9kIGZyb20gdGhlIG1vZGVsIGFuZCBtYWtlIHN1cmUgdGhhdCB0aGUgbWV0aG9kIHBlcnNpc3RzIHRoZSB2YXJpYWJsZXMuIFNlZSBgZG9gLCBgc2VyaWFsYCwgYW5kIGBwYXJhbGxlbGAgaW4gdGhlIFtSdW4gQVBJIFNlcnZpY2VdKC4uL3J1bi1hcGktc2VydmljZS8pIGZvciBjYWxsaW5nIG1ldGhvZHMgZnJvbSB0aGUgbW9kZWwuKVxuICAgICAgICAgKlxuICAgICAgICAgKiAqKkV4YW1wbGUqKlxuICAgICAgICAgKlxuICAgICAgICAgKiAgICAgIHZzLnNhdmUoJ3ByaWNlJywgNCk7XG4gICAgICAgICAqICAgICAgdnMuc2F2ZSh7IHByaWNlOiA0LCBxdWFudGl0eTogNSwgcHJvZHVjdHM6IFsyLDMsNF0gfSk7XG4gICAgICAgICAqXG4gICAgICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICAgICAqIEBwYXJhbSB7T2JqZWN0fFN0cmluZ30gdmFyaWFibGUgQW4gb2JqZWN0IGNvbXBvc2VkIG9mIHRoZSBtb2RlbCB2YXJpYWJsZXMgYW5kIHRoZSB2YWx1ZXMgdG8gc2F2ZS4gQWx0ZXJuYXRpdmVseSwgYSBzdHJpbmcgd2l0aCB0aGUgbmFtZSBvZiB0aGUgdmFyaWFibGUuXG4gICAgICAgICAqIEBwYXJhbSB7T2JqZWN0fSB2YWwgKE9wdGlvbmFsKSBJZiBwYXNzaW5nIGEgc3RyaW5nIGZvciBgdmFyaWFibGVgLCB1c2UgdGhpcyBhcmd1bWVudCBmb3IgdGhlIHZhbHVlIHRvIHNhdmUuXG4gICAgICAgICAqIEBwYXJhbSB7T2JqZWN0fSBvcHRpb25zIChPcHRpb25hbCkgT3ZlcnJpZGVzIGZvciBjb25maWd1cmF0aW9uIG9wdGlvbnMuXG4gICAgICAgICAqIEByZXR1cm4ge1Byb21pc2V9XG4gICAgICAgICAqL1xuICAgICAgICAgc2F2ZTogZnVuY3Rpb24gKHZhcmlhYmxlLCB2YWwsIG9wdGlvbnMpIHtcbiAgICAgICAgICAgICB2YXIgYXR0cnM7XG4gICAgICAgICAgICAgaWYgKHR5cGVvZiB2YXJpYWJsZSA9PT0gJ29iamVjdCcpIHtcbiAgICAgICAgICAgICAgICAgYXR0cnMgPSB2YXJpYWJsZTtcbiAgICAgICAgICAgICAgICAgb3B0aW9ucyA9IHZhbDtcbiAgICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgICAoYXR0cnMgPSB7fSlbdmFyaWFibGVdID0gdmFsO1xuICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICB2YXIgaHR0cE9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSwgc2VydmljZU9wdGlvbnMsIG9wdGlvbnMpO1xuXG4gICAgICAgICAgICAgcmV0dXJuIGh0dHAucGF0Y2guY2FsbCh0aGlzLCBhdHRycywgaHR0cE9wdGlvbnMpO1xuICAgICAgICAgfVxuXG4gICAgICAgIC8vIE5vdCBBdmFpbGFibGUgdW50aWwgdW5kZXJseWluZyBBUEkgc3VwcG9ydHMgUFVULiBPdGhlcndpc2Ugc2F2ZSB3b3VsZCBiZSBQVVQgYW5kIG1lcmdlIHdvdWxkIGJlIFBBVENIXG4gICAgICAgIC8vICpcbiAgICAgICAgLy8gICogU2F2ZSB2YWx1ZXMgdG8gdGhlIGFwaS4gTWVyZ2VzIGFycmF5cywgYnV0IG90aGVyd2lzZSBzYW1lIGFzIHNhdmVcbiAgICAgICAgLy8gICogQHBhcmFtIHtPYmplY3R8U3RyaW5nfSB2YXJpYWJsZSBPYmplY3Qgd2l0aCBhdHRyaWJ1dGVzLCBvciBzdHJpbmcga2V5XG4gICAgICAgIC8vICAqIEBwYXJhbSB7T2JqZWN0fSB2YWwgT3B0aW9uYWwgaWYgcHJldiBwYXJhbWV0ZXIgd2FzIGEgc3RyaW5nLCBzZXQgdmFsdWUgaGVyZVxuICAgICAgICAvLyAgKiBAcGFyYW0ge09iamVjdH0gb3B0aW9ucyBPdmVycmlkZXMgZm9yIGNvbmZpZ3VyYXRpb24gb3B0aW9uc1xuICAgICAgICAvLyAgKlxuICAgICAgICAvLyAgKiBAZXhhbXBsZVxuICAgICAgICAvLyAgKiAgICAgdnMubWVyZ2UoeyBwcmljZTogNCwgcXVhbnRpdHk6IDUsIHByb2R1Y3RzOiBbMiwzLDRdIH0pXG4gICAgICAgIC8vICAqICAgICB2cy5tZXJnZSgncHJpY2UnLCA0KTtcblxuICAgICAgICAvLyBtZXJnZTogZnVuY3Rpb24gKHZhcmlhYmxlLCB2YWwsIG9wdGlvbnMpIHtcbiAgICAgICAgLy8gICAgIHZhciBhdHRycztcbiAgICAgICAgLy8gICAgIGlmICh0eXBlb2YgdmFyaWFibGUgPT09ICdvYmplY3QnKSB7XG4gICAgICAgIC8vICAgICAgIGF0dHJzID0gdmFyaWFibGU7XG4gICAgICAgIC8vICAgICAgIG9wdGlvbnMgPSB2YWw7XG4gICAgICAgIC8vICAgICB9IGVsc2Uge1xuICAgICAgICAvLyAgICAgICAoYXR0cnMgPSB7fSlbdmFyaWFibGVdID0gdmFsO1xuICAgICAgICAvLyAgICAgfVxuICAgICAgICAvLyAgICAgdmFyIGh0dHBPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sIHNlcnZpY2VPcHRpb25zLCBvcHRpb25zKTtcblxuICAgICAgICAvLyAgICAgcmV0dXJuIGh0dHAucGF0Y2guY2FsbCh0aGlzLCBhdHRycywgaHR0cE9wdGlvbnMpO1xuICAgICAgICAvLyB9XG4gICAgIH07XG4gICAgICQuZXh0ZW5kKHRoaXMsIHB1YmxpY0FQSSk7XG4gfTtcbiIsIi8qKlxuICogIyMgV29ybGQgQVBJIEFkYXB0ZXJcbiAqXG4gKiBBIFtydW5dKC4uLy4uLy4uL2dsb3NzYXJ5LyNydW4pIGlzIGEgY29sbGVjdGlvbiBvZiBlbmQgdXNlciBpbnRlcmFjdGlvbnMgd2l0aCBhIHByb2plY3QgYW5kIGl0cyBtb2RlbCAtLSBpbmNsdWRpbmcgc2V0dGluZyB2YXJpYWJsZXMsIG1ha2luZyBkZWNpc2lvbnMsIGFuZCBjYWxsaW5nIG9wZXJhdGlvbnMuIEZvciBidWlsZGluZyBtdWx0aXBsYXllciBzaW11bGF0aW9ucyB5b3UgdHlwaWNhbGx5IHdhbnQgbXVsdGlwbGUgZW5kIHVzZXJzIHRvIHNoYXJlIHRoZSBzYW1lIHNldCBvZiBpbnRlcmFjdGlvbnMsIGFuZCB3b3JrIHdpdGhpbiBhIGNvbW1vbiBzdGF0ZS4gRXBpY2VudGVyIGFsbG93cyB5b3UgdG8gY3JlYXRlIFwid29ybGRzXCIgdG8gaGFuZGxlIHN1Y2ggY2FzZXMuIE9ubHkgW3RlYW0gcHJvamVjdHNdKC4uLy4uLy4uL2dsb3NzYXJ5LyN0ZWFtKSBjYW4gYmUgbXVsdGlwbGF5ZXIuXG4gKlxuICogVGhlIFdvcmxkIEFQSSBBZGFwdGVyIGFsbG93cyB5b3UgdG8gY3JlYXRlLCBhY2Nlc3MsIGFuZCBtYW5pcHVsYXRlIG11bHRpcGxheWVyIHdvcmxkcyB3aXRoaW4geW91ciBFcGljZW50ZXIgcHJvamVjdC4gWW91IGNhbiB1c2UgdGhpcyB0byBhZGQgYW5kIHJlbW92ZSBlbmQgdXNlcnMgZnJvbSB0aGUgd29ybGQsIGFuZCB0byBjcmVhdGUsIGFjY2VzcywgYW5kIHJlbW92ZSB0aGVpciBydW5zLiBCZWNhdXNlIG9mIHRoaXMsIHR5cGljYWxseSB0aGUgV29ybGQgQWRhcHRlciBpcyB1c2VkIGZvciBmYWNpbGl0YXRvciBwYWdlcyBpbiB5b3VyIHByb2plY3QuIChUaGUgcmVsYXRlZCBbV29ybGQgTWFuYWdlcl0oLi4vd29ybGQtbWFuYWdlci8pIHByb3ZpZGVzIGFuIGVhc3kgd2F5IHRvIGFjY2VzcyBydW5zIGFuZCB3b3JsZHMgZm9yIHBhcnRpY3VsYXIgZW5kIHVzZXJzLCBzbyBpcyB0eXBpY2FsbHkgdXNlZCBpbiBwYWdlcyB0aGF0IGVuZCB1c2VycyB3aWxsIGludGVyYWN0IHdpdGguKVxuICpcbiAqIEFzIHdpdGggYWxsIHRoZSBvdGhlciBbQVBJIEFkYXB0ZXJzXSguLi8uLi8pLCBhbGwgbWV0aG9kcyB0YWtlIGluIGFuIFwib3B0aW9uc1wiIG9iamVjdCBhcyB0aGUgbGFzdCBwYXJhbWV0ZXIuIFRoZSBvcHRpb25zIGNhbiBiZSB1c2VkIHRvIGV4dGVuZC9vdmVycmlkZSB0aGUgV29ybGQgQVBJIFNlcnZpY2UgZGVmYXVsdHMuXG4gKlxuICogVG8gdXNlIHRoZSBXb3JsZCBBZGFwdGVyLCBpbnN0YW50aWF0ZSBpdCBhbmQgdGhlbiBhY2Nlc3MgdGhlIG1ldGhvZHMgcHJvdmlkZWQuIEluc3RhbnRpYXRpbmcgcmVxdWlyZXMgdGhlIGFjY291bnQgaWQgKCoqVGVhbSBJRCoqIGluIHRoZSBFcGljZW50ZXIgdXNlciBpbnRlcmZhY2UpLCBwcm9qZWN0IGlkICgqKlByb2plY3QgSUQqKiksIGFuZCBncm91cCAoKipHcm91cCBOYW1lKiopLlxuICpcbiAqICAgICAgIHZhciB3YSA9IG5ldyBGLnNlcnZpY2UuV29ybGQoe1xuICogICAgICAgICAgYWNjb3VudDogJ2FjbWUtc2ltdWxhdGlvbnMnLFxuICogICAgICAgICAgcHJvamVjdDogJ3N1cHBseS1jaGFpbi1nYW1lJyxcbiAqICAgICAgICAgIGdyb3VwOiAndGVhbTEnIH0pO1xuICogICAgICAgd2EuY3JlYXRlKClcbiAqICAgICAgICAgIC50aGVuKGZ1bmN0aW9uKHdvcmxkKSB7XG4gKiAgICAgICAgICAgICAgLy8gY2FsbCBtZXRob2RzLCBlLmcuIHdhLmFkZFVzZXJzKClcbiAqICAgICAgICAgIH0pO1xuICovXG5cbid1c2Ugc3RyaWN0JztcblxudmFyIENvbmZpZ1NlcnZpY2UgPSByZXF1aXJlKCcuL2NvbmZpZ3VyYXRpb24tc2VydmljZScpO1xuLy8gdmFyIHF1dGlsID0gcmVxdWlyZSgnLi4vdXRpbC9xdWVyeS11dGlsJyk7XG52YXIgVHJhbnNwb3J0RmFjdG9yeSA9IHJlcXVpcmUoJy4uL3RyYW5zcG9ydC9odHRwLXRyYW5zcG9ydC1mYWN0b3J5Jyk7XG52YXIgU2Vzc2lvbk1hbmFnZXIgPSByZXF1aXJlKCcuLi9zdG9yZS9zZXNzaW9uLW1hbmFnZXInKTtcbnZhciBfcGljayA9IHJlcXVpcmUoJy4uL3V0aWwvb2JqZWN0LXV0aWwnKS5fcGljaztcblxudmFyIGFwaUJhc2UgPSAnbXVsdGlwbGF5ZXIvJztcbnZhciBhc3NpZ25tZW50RW5kcG9pbnQgPSBhcGlCYXNlICsgJ2Fzc2lnbic7XG52YXIgYXBpRW5kcG9pbnQgPSBhcGlCYXNlICsgJ3dvcmxkJztcbnZhciBwcm9qZWN0RW5kcG9pbnQgPSBhcGlCYXNlICsgJ3Byb2plY3QnO1xuXG5tb2R1bGUuZXhwb3J0cyA9IGZ1bmN0aW9uIChjb25maWcpIHtcbiAgICB2YXIgZGVmYXVsdHMgPSB7XG4gICAgICAgIC8qKlxuICAgICAgICAgKiBGb3IgcHJvamVjdHMgdGhhdCByZXF1aXJlIGF1dGhlbnRpY2F0aW9uLCBwYXNzIGluIHRoZSB1c2VyIGFjY2VzcyB0b2tlbiAoZGVmYXVsdHMgdG8gZW1wdHkgc3RyaW5nKS4gSWYgdGhlIHVzZXIgaXMgYWxyZWFkeSBsb2dnZWQgaW4gdG8gRXBpY2VudGVyLCB0aGUgdXNlciBhY2Nlc3MgdG9rZW4gaXMgYWxyZWFkeSBzZXQgaW4gYSBjb29raWUgYW5kIGF1dG9tYXRpY2FsbHkgbG9hZGVkIGZyb20gdGhlcmUuIChTZWUgW21vcmUgYmFja2dyb3VuZCBvbiBhY2Nlc3MgdG9rZW5zXSguLi8uLi8uLi9wcm9qZWN0X2FjY2Vzcy8pKS5cbiAgICAgICAgICogQHNlZSBbQXV0aGVudGljYXRpb24gQVBJIFNlcnZpY2VdKC4uL2F1dGgtYXBpLXNlcnZpY2UvKSBmb3IgZ2V0dGluZyB0b2tlbnMuXG4gICAgICAgICAqIEB0eXBlIHtTdHJpbmd9XG4gICAgICAgICAqL1xuICAgICAgICB0b2tlbjogdW5kZWZpbmVkLFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBUaGUgcHJvamVjdCBpZC4gSWYgbGVmdCB1bmRlZmluZWQsIHRha2VuIGZyb20gdGhlIFVSTC5cbiAgICAgICAgICogQHR5cGUge1N0cmluZ31cbiAgICAgICAgICovXG4gICAgICAgIHByb2plY3Q6IHVuZGVmaW5lZCxcblxuICAgICAgICAvKipcbiAgICAgICAgICogVGhlIGFjY291bnQgaWQuIEluIHRoZSBFcGljZW50ZXIgVUksIHRoaXMgaXMgdGhlICoqVGVhbSBJRCoqIChmb3IgdGVhbSBwcm9qZWN0cykuIElmIGxlZnQgdW5kZWZpbmVkLCB0YWtlbiBmcm9tIHRoZSBVUkwuXG4gICAgICAgICAqIEB0eXBlIHtTdHJpbmd9XG4gICAgICAgICAqL1xuICAgICAgICBhY2NvdW50OiB1bmRlZmluZWQsXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIFRoZSBncm91cCBuYW1lLiBEZWZhdWx0cyB0byB1bmRlZmluZWQuXG4gICAgICAgICAqIEB0eXBlIHtTdHJpbmd9XG4gICAgICAgICAqL1xuICAgICAgICBncm91cDogdW5kZWZpbmVkLFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBUaGUgbW9kZWwgZmlsZSB0byB1c2UgdG8gY3JlYXRlIHJ1bnMgaW4gdGhpcyB3b3JsZC4gRGVmYXVsdHMgdG8gdW5kZWZpbmVkLlxuICAgICAgICAgKiBAdHlwZSB7U3RyaW5nfVxuICAgICAgICAgKi9cbiAgICAgICAgbW9kZWw6IHVuZGVmaW5lZCxcblxuICAgICAgICAvKipcbiAgICAgICAgICogQ3JpdGVyaWEgYnkgd2hpY2ggdG8gZmlsdGVyIHdvcmxkLiBDdXJyZW50bHkgb25seSBzdXBwb3J0cyB3b3JsZC1pZHMgYXMgZmlsdGVycy5cbiAgICAgICAgICogQHR5cGUge1N0cmluZ31cbiAgICAgICAgICovXG4gICAgICAgIGZpbHRlcjogJycsXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIENvbnZlbmllbmNlIGFsaWFzIGZvciBmaWx0ZXJcbiAgICAgICAgICogQHR5cGUge1N0cmluZ31cbiAgICAgICAgICovXG4gICAgICAgIGlkOiAnJyxcblxuICAgICAgICAvKipcbiAgICAgICAgICogT3B0aW9ucyB0byBwYXNzIG9uIHRvIHRoZSB1bmRlcmx5aW5nIHRyYW5zcG9ydCBsYXllci4gQWxsIGpxdWVyeS5hamF4IG9wdGlvbnMgYXQgaHR0cDovL2FwaS5qcXVlcnkuY29tL2pRdWVyeS5hamF4LyBhcmUgYXZhaWxhYmxlLiBEZWZhdWx0cyB0byBlbXB0eSBvYmplY3QuXG4gICAgICAgICAqIEB0eXBlIHtPYmplY3R9XG4gICAgICAgICAqL1xuICAgICAgICB0cmFuc3BvcnQ6IHt9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBDYWxsZWQgd2hlbiB0aGUgY2FsbCBjb21wbGV0ZXMgc3VjY2Vzc2Z1bGx5LiBEZWZhdWx0cyB0byBgJC5ub29wYC5cbiAgICAgICAgICogQHR5cGUge2Z1bmN0aW9ufVxuICAgICAgICAgKi9cbiAgICAgICAgc3VjY2VzczogJC5ub29wLFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBDYWxsZWQgd2hlbiB0aGUgY2FsbCBmYWlscy4gRGVmYXVsdHMgdG8gYCQubm9vcGAuXG4gICAgICAgICAqIEB0eXBlIHtmdW5jdGlvbn1cbiAgICAgICAgICovXG4gICAgICAgIGVycm9yOiAkLm5vb3BcbiAgICB9O1xuXG4gICAgdGhpcy5zZXNzaW9uTWFuYWdlciA9IG5ldyBTZXNzaW9uTWFuYWdlcigpO1xuICAgIHZhciBzZXJ2aWNlT3B0aW9ucyA9IHRoaXMuc2Vzc2lvbk1hbmFnZXIuZ2V0TWVyZ2VkT3B0aW9ucyhkZWZhdWx0cywgY29uZmlnKTtcbiAgICBpZiAoc2VydmljZU9wdGlvbnMuaWQpIHtcbiAgICAgICAgc2VydmljZU9wdGlvbnMuZmlsdGVyID0gc2VydmljZU9wdGlvbnMuaWQ7XG4gICAgfVxuXG4gICAgdmFyIHVybENvbmZpZyA9IG5ldyBDb25maWdTZXJ2aWNlKHNlcnZpY2VPcHRpb25zKS5nZXQoJ3NlcnZlcicpO1xuXG4gICAgaWYgKCFzZXJ2aWNlT3B0aW9ucy5hY2NvdW50KSB7XG4gICAgICAgIHNlcnZpY2VPcHRpb25zLmFjY291bnQgPSB1cmxDb25maWcuYWNjb3VudFBhdGg7XG4gICAgfVxuXG4gICAgaWYgKCFzZXJ2aWNlT3B0aW9ucy5wcm9qZWN0KSB7XG4gICAgICAgIHNlcnZpY2VPcHRpb25zLnByb2plY3QgPSB1cmxDb25maWcucHJvamVjdFBhdGg7XG4gICAgfVxuXG4gICAgdmFyIHRyYW5zcG9ydE9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSwgc2VydmljZU9wdGlvbnMudHJhbnNwb3J0LCB7XG4gICAgICAgIHVybDogdXJsQ29uZmlnLmdldEFQSVBhdGgoYXBpRW5kcG9pbnQpXG4gICAgfSk7XG5cbiAgICBpZiAoc2VydmljZU9wdGlvbnMudG9rZW4pIHtcbiAgICAgICAgdHJhbnNwb3J0T3B0aW9ucy5oZWFkZXJzID0ge1xuICAgICAgICAgICAgQXV0aG9yaXphdGlvbjogJ0JlYXJlciAnICsgc2VydmljZU9wdGlvbnMudG9rZW5cbiAgICAgICAgfTtcbiAgICB9XG5cbiAgICB2YXIgaHR0cCA9IG5ldyBUcmFuc3BvcnRGYWN0b3J5KHRyYW5zcG9ydE9wdGlvbnMpO1xuXG4gICAgdmFyIHNldElkRmlsdGVyT3JUaHJvd0Vycm9yID0gZnVuY3Rpb24gKG9wdGlvbnMpIHtcbiAgICAgICAgaWYgKG9wdGlvbnMuaWQpIHtcbiAgICAgICAgICAgIHNlcnZpY2VPcHRpb25zLmZpbHRlciA9IG9wdGlvbnMuaWQ7XG4gICAgICAgIH1cbiAgICAgICAgaWYgKG9wdGlvbnMuZmlsdGVyKSB7XG4gICAgICAgICAgICBzZXJ2aWNlT3B0aW9ucy5maWx0ZXIgPSBvcHRpb25zLmZpbHRlcjtcbiAgICAgICAgfVxuICAgICAgICBpZiAoIXNlcnZpY2VPcHRpb25zLmZpbHRlcikge1xuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdObyB3b3JsZCBpZCBzcGVjaWZpZWQgdG8gYXBwbHkgb3BlcmF0aW9ucyBhZ2FpbnN0LiBUaGlzIGNvdWxkIGhhcHBlbiBpZiB0aGUgdXNlciBpcyBub3QgYXNzaWduZWQgdG8gYSB3b3JsZCBhbmQgaXMgdHJ5aW5nIHRvIHdvcmsgd2l0aCBydW5zIGZyb20gdGhhdCB3b3JsZC4nKTtcbiAgICAgICAgfVxuICAgIH07XG5cbiAgICB2YXIgdmFsaWRhdGVNb2RlbE9yVGhyb3dFcnJvciA9IGZ1bmN0aW9uIChvcHRpb25zKSB7XG4gICAgICAgIGlmICghb3B0aW9ucy5tb2RlbCkge1xuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdObyBtb2RlbCBzcGVjaWZpZWQgdG8gZ2V0IHRoZSBjdXJyZW50IHJ1bicpO1xuICAgICAgICB9XG4gICAgfTtcblxuICAgIHZhciBwdWJsaWNBUEkgPSB7XG5cbiAgICAgICAgLyoqXG4gICAgICAgICogQ3JlYXRlcyBhIG5ldyBXb3JsZC5cbiAgICAgICAgKlxuICAgICAgICAqIFVzaW5nIHRoaXMgbWV0aG9kIGlzIHJhcmUuIEl0IGlzIG1vcmUgY29tbW9uIHRvIGNyZWF0ZSB3b3JsZHMgYXV0b21hdGljYWxseSB3aGlsZSB5b3UgYGF1dG9Bc3NpZ24oKWAgZW5kIHVzZXJzIHRvIHdvcmxkcy4gKEluIHRoaXMgY2FzZSwgY29uZmlndXJhdGlvbiBkYXRhIGZvciB0aGUgd29ybGQsIHN1Y2ggYXMgdGhlIHJvbGVzLCBhcmUgcmVhZCBmcm9tIHRoZSBwcm9qZWN0LWxldmVsIHdvcmxkIGNvbmZpZ3VyYXRpb24gaW5mb3JtYXRpb24sIGZvciBleGFtcGxlIGJ5IGBnZXRQcm9qZWN0U2V0dGluZ3MoKWAuKVxuICAgICAgICAqXG4gICAgICAgICogICoqRXhhbXBsZSoqXG4gICAgICAgICpcbiAgICAgICAgKiAgICAgIHZhciB3YSA9IG5ldyBGLnNlcnZpY2UuV29ybGQoe1xuICAgICAgICAqICAgICAgICAgICBhY2NvdW50OiAnYWNtZS1zaW11bGF0aW9ucycsXG4gICAgICAgICogICAgICAgICAgIHByb2plY3Q6ICdzdXBwbHktY2hhaW4tZ2FtZScsXG4gICAgICAgICogICAgICAgICAgIGdyb3VwOiAndGVhbTEnIH0pO1xuICAgICAgICAqICAgICAgd2EuY3JlYXRlKHtcbiAgICAgICAgKiAgICAgICAgICAgcm9sZXM6IFsnVlAgTWFya2V0aW5nJywgJ1ZQIFNhbGVzJywgJ1ZQIEVuZ2luZWVyaW5nJ11cbiAgICAgICAgKiAgICAgICB9KTtcbiAgICAgICAgKlxuICAgICAgICAqICAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAqIEBwYXJhbSB7b2JqZWN0fSBwYXJhbXMgUGFyYW1ldGVycyB0byBjcmVhdGUgdGhlIHdvcmxkLlxuICAgICAgICAqIEBwYXJhbSB7c3RyaW5nfSBwYXJhbXMuZ3JvdXAgKE9wdGlvbmFsKSBUaGUgKipHcm91cCBOYW1lKiogdG8gY3JlYXRlIHRoaXMgd29ybGQgdW5kZXIuIE9ubHkgZW5kIHVzZXJzIGluIHRoaXMgZ3JvdXAgYXJlIGVsaWdpYmxlIHRvIGpvaW4gdGhlIHdvcmxkLiBPcHRpb25hbCBoZXJlOyByZXF1aXJlZCB3aGVuIGluc3RhbnRpYXRpbmcgdGhlIHNlcnZpY2UgKGBuZXcgRi5zZXJ2aWNlLldvcmxkKClgKS5cbiAgICAgICAgKiBAcGFyYW0ge29iamVjdH0gcGFyYW1zLnJvbGVzIChPcHRpb25hbCkgVGhlIGxpc3Qgb2Ygcm9sZXMgKHN0cmluZ3MpIGZvciB0aGlzIHdvcmxkLiBTb21lIHdvcmxkcyBoYXZlIHNwZWNpZmljIHJvbGVzIHRoYXQgKiptdXN0KiogYmUgZmlsbGVkIGJ5IGVuZCB1c2Vycy4gTGlzdGluZyB0aGUgcm9sZXMgYWxsb3dzIHlvdSB0byBhdXRvYXNzaWduIHVzZXJzIHRvIHdvcmxkcyBhbmQgZW5zdXJlIHRoYXQgYWxsIHJvbGVzIGFyZSBmaWxsZWQgaW4gZWFjaCB3b3JsZC5cbiAgICAgICAgKiBAcGFyYW0ge29iamVjdH0gcGFyYW1zLm9wdGlvbmFsUm9sZXMgKE9wdGlvbmFsKSBUaGUgbGlzdCBvZiBvcHRpb25hbCByb2xlcyAoc3RyaW5ncykgZm9yIHRoaXMgd29ybGQuIFNvbWUgd29ybGRzIGhhdmUgc3BlY2lmaWMgcm9sZXMgdGhhdCAqKm1heSoqIGJlIGZpbGxlZCBieSBlbmQgdXNlcnMuIExpc3RpbmcgdGhlIG9wdGlvbmFsIHJvbGVzIGFzIHBhcnQgb2YgdGhlIHdvcmxkIG9iamVjdCBhbGxvd3MgeW91IHRvIGF1dG9hc3NpZ24gdXNlcnMgdG8gd29ybGRzIGFuZCBlbnN1cmUgdGhhdCBhbGwgcm9sZXMgYXJlIGZpbGxlZCBpbiBlYWNoIHdvcmxkLlxuICAgICAgICAqIEBwYXJhbSB7aW50ZWdlcn0gcGFyYW1zLm1pblVzZXJzIChPcHRpb25hbCkgVGhlIG1pbmltdW0gbnVtYmVyIG9mIHVzZXJzIGZvciB0aGUgd29ybGQuIEluY2x1ZGluZyB0aGlzIG51bWJlciBhbGxvd3MgeW91IHRvIGF1dG9hc3NpZ24gZW5kIHVzZXJzIHRvIHdvcmxkcyBhbmQgZW5zdXJlIHRoYXQgdGhlIGNvcnJlY3QgbnVtYmVyIG9mIHVzZXJzIGFyZSBpbiBlYWNoIHdvcmxkLlxuICAgICAgICAqIEBwYXJhbSB7b2JqZWN0fSBvcHRpb25zIChPcHRpb25hbCkgT3B0aW9ucyBvYmplY3QgdG8gb3ZlcnJpZGUgZ2xvYmFsIG9wdGlvbnMuXG4gICAgICAgICogQHJldHVybiB7UHJvbWlzZX1cbiAgICAgICAgKi9cbiAgICAgICAgY3JlYXRlOiBmdW5jdGlvbiAocGFyYW1zLCBvcHRpb25zKSB7XG4gICAgICAgICAgICB2YXIgY3JlYXRlT3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LCBzZXJ2aWNlT3B0aW9ucywgb3B0aW9ucywgeyB1cmw6IHVybENvbmZpZy5nZXRBUElQYXRoKGFwaUVuZHBvaW50KSB9KTtcbiAgICAgICAgICAgIHZhciB3b3JsZEFwaVBhcmFtcyA9IFsnc2NvcGUnLCAnZmlsZXMnLCAncm9sZXMnLCAnb3B0aW9uYWxSb2xlcycsICdtaW5Vc2VycycsICdncm91cCcsICduYW1lJ107XG4gICAgICAgICAgICB2YXIgdmFsaWRQYXJhbXMgPSBfcGljayhzZXJ2aWNlT3B0aW9ucywgWydhY2NvdW50JywgJ3Byb2plY3QnLCAnZ3JvdXAnXSk7XG4gICAgICAgICAgICAvLyB3aGl0ZWxpc3QgdGhlIGZpZWxkcyB0aGF0IHdlIGFjdHVhbGx5IGNhbiBzZW5kIHRvIHRoZSBhcGlcbiAgICAgICAgICAgIHBhcmFtcyA9IF9waWNrKHBhcmFtcywgd29ybGRBcGlQYXJhbXMpO1xuXG4gICAgICAgICAgICAvLyBhY2NvdW50IGFuZCBwcm9qZWN0IGdvIGluIHRoZSBib2R5LCBub3QgaW4gdGhlIHVybFxuICAgICAgICAgICAgcGFyYW1zID0gJC5leHRlbmQoe30sIHZhbGlkUGFyYW1zLCBwYXJhbXMpO1xuXG4gICAgICAgICAgICB2YXIgb2xkU3VjY2VzcyA9IGNyZWF0ZU9wdGlvbnMuc3VjY2VzcztcbiAgICAgICAgICAgIGNyZWF0ZU9wdGlvbnMuc3VjY2VzcyA9IGZ1bmN0aW9uIChyZXNwb25zZSkge1xuICAgICAgICAgICAgICAgIHNlcnZpY2VPcHRpb25zLmZpbHRlciA9IHJlc3BvbnNlLmlkOyAvL2FsbCBmdXR1cmUgY2hhaW5lZCBjYWxscyB0byBvcGVyYXRlIG9uIHRoaXMgaWRcbiAgICAgICAgICAgICAgICByZXR1cm4gb2xkU3VjY2Vzcy5hcHBseSh0aGlzLCBhcmd1bWVudHMpO1xuICAgICAgICAgICAgfTtcblxuICAgICAgICAgICAgcmV0dXJuIGh0dHAucG9zdChwYXJhbXMsIGNyZWF0ZU9wdGlvbnMpO1xuICAgICAgICB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAqIFVwZGF0ZXMgYSBXb3JsZCwgZm9yIGV4YW1wbGUgdG8gcmVwbGFjZSB0aGUgcm9sZXMgaW4gdGhlIHdvcmxkLlxuICAgICAgICAqXG4gICAgICAgICogVHlwaWNhbGx5LCB5b3UgY29tcGxldGUgd29ybGQgY29uZmlndXJhdGlvbiBhdCB0aGUgcHJvamVjdCBsZXZlbCwgcmF0aGVyIHRoYW4gYXQgdGhlIHdvcmxkIGxldmVsLiBGb3IgZXhhbXBsZSwgZWFjaCB3b3JsZCBpbiB5b3VyIHByb2plY3QgcHJvYmFibHkgaGFzIHRoZSBzYW1lIHJvbGVzIGZvciBlbmQgdXNlcnMuIEFuZCB5b3VyIHByb2plY3QgaXMgcHJvYmFibHkgZWl0aGVyIGNvbmZpZ3VyZWQgc28gdGhhdCBhbGwgZW5kIHVzZXJzIHNoYXJlIHRoZSBzYW1lIHdvcmxkIChhbmQgcnVuKSwgb3Igc21hbGxlciBzZXRzIG9mIGVuZCB1c2VycyBzaGFyZSB3b3JsZHMg4oCUIGJ1dCBub3QgYm90aC4gSG93ZXZlciwgdGhpcyBtZXRob2QgaXMgYXZhaWxhYmxlIGlmIHlvdSBuZWVkIHRvIHVwZGF0ZSB0aGUgY29uZmlndXJhdGlvbiBvZiBhIHBhcnRpY3VsYXIgd29ybGQuXG4gICAgICAgICpcbiAgICAgICAgKiAgKipFeGFtcGxlKipcbiAgICAgICAgKlxuICAgICAgICAqICAgICAgdmFyIHdhID0gbmV3IEYuc2VydmljZS5Xb3JsZCh7XG4gICAgICAgICogICAgICAgICAgIGFjY291bnQ6ICdhY21lLXNpbXVsYXRpb25zJyxcbiAgICAgICAgKiAgICAgICAgICAgcHJvamVjdDogJ3N1cHBseS1jaGFpbi1nYW1lJyxcbiAgICAgICAgKiAgICAgICAgICAgZ3JvdXA6ICd0ZWFtMScgfSk7XG4gICAgICAgICogICAgICB3YS5jcmVhdGUoKVxuICAgICAgICAqICAgICAgICAgICAudGhlbihmdW5jdGlvbih3b3JsZCkge1xuICAgICAgICAqICAgICAgICAgICAgICAgd2EudXBkYXRlKHsgcm9sZXM6IFsnVlAgTWFya2V0aW5nJywgJ1ZQIFNhbGVzJywgJ1ZQIEVuZ2luZWVyaW5nJ10gfSk7XG4gICAgICAgICogICAgICAgICAgIH0pO1xuICAgICAgICAqXG4gICAgICAgICogICoqUGFyYW1ldGVycyoqXG4gICAgICAgICogQHBhcmFtIHtvYmplY3R9IHBhcmFtcyBQYXJhbWV0ZXJzIHRvIHVwZGF0ZSB0aGUgd29ybGQuXG4gICAgICAgICogQHBhcmFtIHtzdHJpbmd9IHBhcmFtcy5uYW1lIEEgc3RyaW5nIGlkZW50aWZpZXIgZm9yIHRoZSBsaW5rZWQgZW5kIHVzZXJzLCBmb3IgZXhhbXBsZSwgXCJuYW1lXCI6IFwiT3VyIFRlYW1cIi5cbiAgICAgICAgKiBAcGFyYW0ge29iamVjdH0gcGFyYW1zLnJvbGVzIChPcHRpb25hbCkgVGhlIGxpc3Qgb2Ygcm9sZXMgKHN0cmluZ3MpIGZvciB0aGlzIHdvcmxkLiBTb21lIHdvcmxkcyBoYXZlIHNwZWNpZmljIHJvbGVzIHRoYXQgKiptdXN0KiogYmUgZmlsbGVkIGJ5IGVuZCB1c2Vycy4gTGlzdGluZyB0aGUgcm9sZXMgYWxsb3dzIHlvdSB0byBhdXRvYXNzaWduIHVzZXJzIHRvIHdvcmxkcyBhbmQgZW5zdXJlIHRoYXQgYWxsIHJvbGVzIGFyZSBmaWxsZWQgaW4gZWFjaCB3b3JsZC5cbiAgICAgICAgKiBAcGFyYW0ge29iamVjdH0gcGFyYW1zLm9wdGlvbmFsUm9sZXMgKE9wdGlvbmFsKSBUaGUgbGlzdCBvZiBvcHRpb25hbCByb2xlcyAoc3RyaW5ncykgZm9yIHRoaXMgd29ybGQuIFNvbWUgd29ybGRzIGhhdmUgc3BlY2lmaWMgcm9sZXMgdGhhdCAqKm1heSoqIGJlIGZpbGxlZCBieSBlbmQgdXNlcnMuIExpc3RpbmcgdGhlIG9wdGlvbmFsIHJvbGVzIGFzIHBhcnQgb2YgdGhlIHdvcmxkIG9iamVjdCBhbGxvd3MgeW91IHRvIGF1dG9hc3NpZ24gdXNlcnMgdG8gd29ybGRzIGFuZCBlbnN1cmUgdGhhdCBhbGwgcm9sZXMgYXJlIGZpbGxlZCBpbiBlYWNoIHdvcmxkLlxuICAgICAgICAqIEBwYXJhbSB7aW50ZWdlcn0gcGFyYW1zLm1pblVzZXJzIChPcHRpb25hbCkgVGhlIG1pbmltdW0gbnVtYmVyIG9mIHVzZXJzIGZvciB0aGUgd29ybGQuIEluY2x1ZGluZyB0aGlzIG51bWJlciBhbGxvd3MgeW91IHRvIGF1dG9hc3NpZ24gZW5kIHVzZXJzIHRvIHdvcmxkcyBhbmQgZW5zdXJlIHRoYXQgdGhlIGNvcnJlY3QgbnVtYmVyIG9mIHVzZXJzIGFyZSBpbiBlYWNoIHdvcmxkLlxuICAgICAgICAqIEBwYXJhbSB7b2JqZWN0fSBvcHRpb25zIChPcHRpb25hbCkgT3B0aW9ucyBvYmplY3QgdG8gb3ZlcnJpZGUgZ2xvYmFsIG9wdGlvbnMuXG4gICAgICAgICogQHJldHVybiB7UHJvbWlzZX1cbiAgICAgICAgKi9cbiAgICAgICAgdXBkYXRlOiBmdW5jdGlvbiAocGFyYW1zLCBvcHRpb25zKSB7XG4gICAgICAgICAgICB2YXIgd2hpdGVsaXN0ID0gWydyb2xlcycsICdvcHRpb25hbFJvbGVzJywgJ21pblVzZXJzJ107XG4gICAgICAgICAgICBvcHRpb25zID0gb3B0aW9ucyB8fCB7fTtcbiAgICAgICAgICAgIHNldElkRmlsdGVyT3JUaHJvd0Vycm9yKG9wdGlvbnMpO1xuXG4gICAgICAgICAgICB2YXIgdXBkYXRlT3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LFxuICAgICAgICAgICAgICAgIHNlcnZpY2VPcHRpb25zLFxuICAgICAgICAgICAgICAgIG9wdGlvbnMsXG4gICAgICAgICAgICAgICAgeyB1cmw6IHVybENvbmZpZy5nZXRBUElQYXRoKGFwaUVuZHBvaW50KSArIHNlcnZpY2VPcHRpb25zLmZpbHRlciB9XG4gICAgICAgICAgICApO1xuXG4gICAgICAgICAgICBwYXJhbXMgPSBfcGljayhwYXJhbXMgfHwge30sIHdoaXRlbGlzdCk7XG5cbiAgICAgICAgICAgIHJldHVybiBodHRwLnBhdGNoKHBhcmFtcywgdXBkYXRlT3B0aW9ucyk7XG4gICAgICAgIH0sXG5cbiAgICAgICAgLyoqXG4gICAgICAgICogRGVsZXRlcyBhbiBleGlzdGluZyB3b3JsZC5cbiAgICAgICAgKlxuICAgICAgICAqIFRoaXMgZnVuY3Rpb24gb3B0aW9uYWxseSB0YWtlcyBvbmUgYXJndW1lbnQuIElmIHRoZSBhcmd1bWVudCBpcyBhIHN0cmluZywgaXQgaXMgdGhlIGlkIG9mIHRoZSB3b3JsZCB0byBkZWxldGUuIElmIHRoZSBhcmd1bWVudCBpcyBhbiBvYmplY3QsIGl0IGlzIHRoZSBvdmVycmlkZSBmb3IgZ2xvYmFsIG9wdGlvbnMuXG4gICAgICAgICpcbiAgICAgICAgKiAgKipFeGFtcGxlKipcbiAgICAgICAgKlxuICAgICAgICAqICAgICAgdmFyIHdhID0gbmV3IEYuc2VydmljZS5Xb3JsZCh7XG4gICAgICAgICogICAgICAgICAgIGFjY291bnQ6ICdhY21lLXNpbXVsYXRpb25zJyxcbiAgICAgICAgKiAgICAgICAgICAgcHJvamVjdDogJ3N1cHBseS1jaGFpbi1nYW1lJyxcbiAgICAgICAgKiAgICAgICAgICAgZ3JvdXA6ICd0ZWFtMScgfSk7XG4gICAgICAgICogICAgICB3YS5jcmVhdGUoKVxuICAgICAgICAqICAgICAgICAgICAudGhlbihmdW5jdGlvbih3b3JsZCkge1xuICAgICAgICAqICAgICAgICAgICAgICAgd2EuZGVsZXRlKCk7XG4gICAgICAgICogICAgICAgICAgIH0pO1xuICAgICAgICAqXG4gICAgICAgICogICoqUGFyYW1ldGVycyoqXG4gICAgICAgICogQHBhcmFtIHtTdHJpbmd8T2JqZWN0fSBvcHRpb25zIChPcHRpb25hbCkgVGhlIGlkIG9mIHRoZSB3b3JsZCB0byBkZWxldGUsIG9yIG9wdGlvbnMgb2JqZWN0IHRvIG92ZXJyaWRlIGdsb2JhbCBvcHRpb25zLlxuICAgICAgICAqIEByZXR1cm4ge1Byb21pc2V9XG4gICAgICAgICovXG4gICAgICAgIGRlbGV0ZTogZnVuY3Rpb24gKG9wdGlvbnMpIHtcbiAgICAgICAgICAgIG9wdGlvbnMgPSAob3B0aW9ucyAmJiAodHlwZW9mIG9wdGlvbnMgPT09ICdzdHJpbmcnKSkgPyB7IGZpbHRlcjogb3B0aW9ucyB9IDoge307XG4gICAgICAgICAgICBzZXRJZEZpbHRlck9yVGhyb3dFcnJvcihvcHRpb25zKTtcblxuICAgICAgICAgICAgdmFyIGRlbGV0ZU9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSxcbiAgICAgICAgICAgICAgICBzZXJ2aWNlT3B0aW9ucyxcbiAgICAgICAgICAgICAgICBvcHRpb25zLFxuICAgICAgICAgICAgICAgIHsgdXJsOiB1cmxDb25maWcuZ2V0QVBJUGF0aChhcGlFbmRwb2ludCkgKyBzZXJ2aWNlT3B0aW9ucy5maWx0ZXIgfVxuICAgICAgICAgICAgKTtcblxuICAgICAgICAgICAgcmV0dXJuIGh0dHAuZGVsZXRlKG51bGwsIGRlbGV0ZU9wdGlvbnMpO1xuICAgICAgICB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAqIFVwZGF0ZXMgdGhlIGNvbmZpZ3VyYXRpb24gZm9yIHRoZSBjdXJyZW50IGluc3RhbmNlIG9mIHRoZSBXb3JsZCBBUEkgQWRhcHRlciAoaW5jbHVkaW5nIGFsbCBzdWJzZXF1ZW50IGZ1bmN0aW9uIGNhbGxzLCB1bnRpbCB0aGUgY29uZmlndXJhdGlvbiBpcyB1cGRhdGVkIGFnYWluKS5cbiAgICAgICAgKlxuICAgICAgICAqICoqRXhhbXBsZSoqXG4gICAgICAgICpcbiAgICAgICAgKiAgICAgIHZhciB3YSA9IG5ldyBGLnNlcnZpY2UuV29ybGQoey4uLn0pLnVwZGF0ZUNvbmZpZyh7IGZpbHRlcjogJzEyMycgfSkuYWRkVXNlcih7IHVzZXJJZDogJzEyMycgfSk7XG4gICAgICAgICpcbiAgICAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAqIEBwYXJhbSB7b2JqZWN0fSBjb25maWcgVGhlIGNvbmZpZ3VyYXRpb24gb2JqZWN0IHRvIHVzZSBpbiB1cGRhdGluZyBleGlzdGluZyBjb25maWd1cmF0aW9uLlxuICAgICAgICAqIEByZXR1cm4ge09iamVjdH0gcmVmZXJlbmNlIHRvIGN1cnJlbnQgaW5zdGFuY2VcbiAgICAgICAgKi9cbiAgICAgICAgdXBkYXRlQ29uZmlnOiBmdW5jdGlvbiAoY29uZmlnKSB7XG4gICAgICAgICAgICAkLmV4dGVuZChzZXJ2aWNlT3B0aW9ucywgY29uZmlnKTtcblxuICAgICAgICAgICAgcmV0dXJuIHRoaXM7XG4gICAgICAgIH0sXG5cbiAgICAgICAgLyoqXG4gICAgICAgICogTGlzdHMgYWxsIHdvcmxkcyBmb3IgYSBnaXZlbiBhY2NvdW50LCBwcm9qZWN0LCBhbmQgZ3JvdXAuIEFsbCB0aHJlZSBhcmUgcmVxdWlyZWQsIGFuZCBpZiBub3Qgc3BlY2lmaWVkIGFzIHBhcmFtZXRlcnMsIGFyZSByZWFkIGZyb20gdGhlIHNlcnZpY2UuXG4gICAgICAgICpcbiAgICAgICAgKiAgKipFeGFtcGxlKipcbiAgICAgICAgKlxuICAgICAgICAqICAgICAgdmFyIHdhID0gbmV3IEYuc2VydmljZS5Xb3JsZCh7XG4gICAgICAgICogICAgICAgICAgIGFjY291bnQ6ICdhY21lLXNpbXVsYXRpb25zJyxcbiAgICAgICAgKiAgICAgICAgICAgcHJvamVjdDogJ3N1cHBseS1jaGFpbi1nYW1lJyxcbiAgICAgICAgKiAgICAgICAgICAgZ3JvdXA6ICd0ZWFtMScgfSk7XG4gICAgICAgICogICAgICB3YS5jcmVhdGUoKVxuICAgICAgICAqICAgICAgICAgICAudGhlbihmdW5jdGlvbih3b3JsZCkge1xuICAgICAgICAqICAgICAgICAgICAgICAgLy8gbGlzdHMgYWxsIHdvcmxkcyBpbiBncm91cCBcInRlYW0xXCJcbiAgICAgICAgKiAgICAgICAgICAgICAgIHdhLmxpc3QoKTtcbiAgICAgICAgKlxuICAgICAgICAqICAgICAgICAgICAgICAgLy8gbGlzdHMgYWxsIHdvcmxkcyBpbiBncm91cCBcIm90aGVyLWdyb3VwLW5hbWVcIlxuICAgICAgICAqICAgICAgICAgICAgICAgd2EubGlzdCh7IGdyb3VwOiAnb3RoZXItZ3JvdXAtbmFtZScgfSk7XG4gICAgICAgICogICAgICAgICAgIH0pO1xuICAgICAgICAqXG4gICAgICAgICogICoqUGFyYW1ldGVycyoqXG4gICAgICAgICogQHBhcmFtIHtvYmplY3R9IG9wdGlvbnMgKE9wdGlvbmFsKSBPcHRpb25zIG9iamVjdCB0byBvdmVycmlkZSBnbG9iYWwgb3B0aW9ucy5cbiAgICAgICAgKiBAcmV0dXJuIHtQcm9taXNlfVxuICAgICAgICAqL1xuICAgICAgICBsaXN0OiBmdW5jdGlvbiAob3B0aW9ucykge1xuICAgICAgICAgICAgb3B0aW9ucyA9IG9wdGlvbnMgfHwge307XG5cbiAgICAgICAgICAgIHZhciBnZXRPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sXG4gICAgICAgICAgICAgICAgc2VydmljZU9wdGlvbnMsXG4gICAgICAgICAgICAgICAgb3B0aW9ucyxcbiAgICAgICAgICAgICAgICB7IHVybDogdXJsQ29uZmlnLmdldEFQSVBhdGgoYXBpRW5kcG9pbnQpIH1cbiAgICAgICAgICAgICk7XG5cbiAgICAgICAgICAgIHZhciBmaWx0ZXJzID0gX3BpY2soZ2V0T3B0aW9ucywgWydhY2NvdW50JywgJ3Byb2plY3QnLCAnZ3JvdXAnXSk7XG5cbiAgICAgICAgICAgIHJldHVybiBodHRwLmdldChmaWx0ZXJzLCBnZXRPcHRpb25zKTtcbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgKiBHZXRzIGFsbCB3b3JsZHMgdGhhdCBhbiBlbmQgdXNlciBiZWxvbmdzIHRvIGZvciBhIGdpdmVuIGFjY291bnQgKHRlYW0pLCBwcm9qZWN0LCBhbmQgZ3JvdXAuXG4gICAgICAgICpcbiAgICAgICAgKiAgKipFeGFtcGxlKipcbiAgICAgICAgKlxuICAgICAgICAqICAgICAgdmFyIHdhID0gbmV3IEYuc2VydmljZS5Xb3JsZCh7XG4gICAgICAgICogICAgICAgICAgIGFjY291bnQ6ICdhY21lLXNpbXVsYXRpb25zJyxcbiAgICAgICAgKiAgICAgICAgICAgcHJvamVjdDogJ3N1cHBseS1jaGFpbi1nYW1lJyxcbiAgICAgICAgKiAgICAgICAgICAgZ3JvdXA6ICd0ZWFtMScgfSk7XG4gICAgICAgICogICAgICB3YS5jcmVhdGUoKVxuICAgICAgICAqICAgICAgICAgICAudGhlbihmdW5jdGlvbih3b3JsZCkge1xuICAgICAgICAqICAgICAgICAgICAgICAgd2EuZ2V0V29ybGRzRm9yVXNlcignYjFjMTlkZGEtMmQyZS00Nzc3LWFkNWQtMzkyOWYxN2U4NmQzJylcbiAgICAgICAgKiAgICAgICAgICAgfSk7XG4gICAgICAgICpcbiAgICAgICAgKiAqKiBQYXJhbWV0ZXJzICoqXG4gICAgICAgICogQHBhcmFtIHtzdHJpbmd9IHVzZXJJZCBUaGUgYHVzZXJJZGAgb2YgdGhlIHVzZXIgd2hvc2Ugd29ybGRzIGFyZSBiZWluZyByZXRyaWV2ZWQuXG4gICAgICAgICogQHBhcmFtIHtvYmplY3R9IG9wdGlvbnMgKE9wdGlvbmFsKSBPcHRpb25zIG9iamVjdCB0byBvdmVycmlkZSBnbG9iYWwgb3B0aW9ucy5cbiAgICAgICAgKiBAcmV0dXJuIHtQcm9taXNlfVxuICAgICAgICAqL1xuICAgICAgICBnZXRXb3JsZHNGb3JVc2VyOiBmdW5jdGlvbiAodXNlcklkLCBvcHRpb25zKSB7XG4gICAgICAgICAgICBvcHRpb25zID0gb3B0aW9ucyB8fCB7fTtcblxuICAgICAgICAgICAgdmFyIGdldE9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSxcbiAgICAgICAgICAgICAgICBzZXJ2aWNlT3B0aW9ucyxcbiAgICAgICAgICAgICAgICBvcHRpb25zLFxuICAgICAgICAgICAgICAgIHsgdXJsOiB1cmxDb25maWcuZ2V0QVBJUGF0aChhcGlFbmRwb2ludCkgfVxuICAgICAgICAgICAgKTtcblxuICAgICAgICAgICAgdmFyIGZpbHRlcnMgPSAkLmV4dGVuZChcbiAgICAgICAgICAgICAgICBfcGljayhnZXRPcHRpb25zLCBbJ2FjY291bnQnLCAncHJvamVjdCcsICdncm91cCddKSxcbiAgICAgICAgICAgICAgICB7IHVzZXJJZDogdXNlcklkIH1cbiAgICAgICAgICAgICk7XG5cbiAgICAgICAgICAgIHJldHVybiBodHRwLmdldChmaWx0ZXJzLCBnZXRPcHRpb25zKTtcbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgICogTG9hZCBpbmZvcm1hdGlvbiBmb3IgYSBzcGVjaWZpYyB3b3JsZC4gQWxsIGZ1cnRoZXIgY2FsbHMgdG8gdGhlIHdvcmxkIHNlcnZpY2Ugd2lsbCB1c2UgdGhlIGlkIHByb3ZpZGVkLlxuICAgICAgICAgKlxuICAgICAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAgKiBAcGFyYW0ge1N0cmluZ30gd29ybGRJZCBUaGUgaWQgb2YgdGhlIHdvcmxkIHRvIGxvYWQuXG4gICAgICAgICAqIEBwYXJhbSB7T2JqZWN0fSBvcHRpb25zIChPcHRpb25hbCkgT3B0aW9ucyBvYmplY3QgdG8gb3ZlcnJpZGUgZ2xvYmFsIG9wdGlvbnMuXG4gICAgICAgICAqIEByZXR1cm4ge1Byb21pc2V9XG4gICAgICAgICAqL1xuICAgICAgICBsb2FkOiBmdW5jdGlvbiAod29ybGRJZCwgb3B0aW9ucykge1xuICAgICAgICAgICAgaWYgKHdvcmxkSWQpIHtcbiAgICAgICAgICAgICAgICBzZXJ2aWNlT3B0aW9ucy5maWx0ZXIgPSB3b3JsZElkO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgaWYgKCFzZXJ2aWNlT3B0aW9ucy5maWx0ZXIpIHtcbiAgICAgICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ1BsZWFzZSBwcm92aWRlIGEgd29ybGRpZCB0byBsb2FkJyk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICB2YXIgaHR0cE9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSwgc2VydmljZU9wdGlvbnMsIG9wdGlvbnMsIHsgdXJsOiB1cmxDb25maWcuZ2V0QVBJUGF0aChhcGlFbmRwb2ludCkgKyBzZXJ2aWNlT3B0aW9ucy5maWx0ZXIgKyAnLycgfSk7XG4gICAgICAgICAgICByZXR1cm4gaHR0cC5nZXQoJycsIGh0dHBPcHRpb25zKTtcbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgKiBBZGRzIGFuIGVuZCB1c2VyIG9yIGxpc3Qgb2YgZW5kIHVzZXJzIHRvIGEgZ2l2ZW4gd29ybGQuIFRoZSBlbmQgdXNlciBtdXN0IGJlIGEgbWVtYmVyIG9mIHRoZSBgZ3JvdXBgIHRoYXQgaXMgYXNzb2NpYXRlZCB3aXRoIHRoaXMgd29ybGQuXG4gICAgICAgICpcbiAgICAgICAgKiAgKipFeGFtcGxlKipcbiAgICAgICAgKlxuICAgICAgICAqICAgICAgdmFyIHdhID0gbmV3IEYuc2VydmljZS5Xb3JsZCh7XG4gICAgICAgICogICAgICAgICAgIGFjY291bnQ6ICdhY21lLXNpbXVsYXRpb25zJyxcbiAgICAgICAgKiAgICAgICAgICAgcHJvamVjdDogJ3N1cHBseS1jaGFpbi1nYW1lJyxcbiAgICAgICAgKiAgICAgICAgICAgZ3JvdXA6ICd0ZWFtMScgfSk7XG4gICAgICAgICogICAgICB3YS5jcmVhdGUoKVxuICAgICAgICAqICAgICAgICAgICAudGhlbihmdW5jdGlvbih3b3JsZCkge1xuICAgICAgICAqICAgICAgICAgICAgICAgLy8gYWRkIG9uZSB1c2VyXG4gICAgICAgICogICAgICAgICAgICAgICB3YS5hZGRVc2VycygnYjFjMTlkZGEtMmQyZS00Nzc3LWFkNWQtMzkyOWYxN2U4NmQzJyk7XG4gICAgICAgICogICAgICAgICAgICAgICB3YS5hZGRVc2VycyhbJ2IxYzE5ZGRhLTJkMmUtNDc3Ny1hZDVkLTM5MjlmMTdlODZkMyddKTtcbiAgICAgICAgKiAgICAgICAgICAgICAgIHdhLmFkZFVzZXJzKHsgdXNlcklkOiAnYjFjMTlkZGEtMmQyZS00Nzc3LWFkNWQtMzkyOWYxN2U4NmQzJywgcm9sZTogJ1ZQIFNhbGVzJyB9KTtcbiAgICAgICAgKlxuICAgICAgICAqICAgICAgICAgICAgICAgLy8gYWRkIHNldmVyYWwgdXNlcnNcbiAgICAgICAgKiAgICAgICAgICAgICAgIHdhLmFkZFVzZXJzKFtcbiAgICAgICAgKiAgICAgICAgICAgICAgICAgICB7IHVzZXJJZDogJ2E2ZmUwYzFlLWY0YjgtNGYwMS05ZjVmLTAxY2NmNGMyZWQ0NCcsXG4gICAgICAgICogICAgICAgICAgICAgICAgICAgICByb2xlOiAnVlAgTWFya2V0aW5nJyB9LFxuICAgICAgICAqICAgICAgICAgICAgICAgICAgIHsgdXNlcklkOiAnOGYyNjA0Y2YtOTZjZC00NDlmLTgyZmEtZTMzMTUzMDczNGVlJyxcbiAgICAgICAgKiAgICAgICAgICAgICAgICAgICAgIHJvbGU6ICdWUCBFbmdpbmVlcmluZycgfVxuICAgICAgICAqICAgICAgICAgICAgICAgXSk7XG4gICAgICAgICpcbiAgICAgICAgKiAgICAgICAgICAgICAgIC8vIGFkZCBvbmUgdXNlciB0byBhIHNwZWNpZmljIHdvcmxkXG4gICAgICAgICogICAgICAgICAgICAgICB3YS5hZGRVc2VycygnYjFjMTlkZGEtMmQyZS00Nzc3LWFkNWQtMzkyOWYxN2U4NmQzJywgd29ybGQuaWQpO1xuICAgICAgICAqICAgICAgICAgICAgICAgd2EuYWRkVXNlcnMoJ2IxYzE5ZGRhLTJkMmUtNDc3Ny1hZDVkLTM5MjlmMTdlODZkMycsIHsgZmlsdGVyOiB3b3JsZC5pZCB9KTtcbiAgICAgICAgKiAgICAgICAgICAgfSk7XG4gICAgICAgICpcbiAgICAgICAgKiAqKiBQYXJhbWV0ZXJzICoqXG4gICAgICAgICogQHBhcmFtIHtzdHJpbmd8b2JqZWN0fGFycmF5fSB1c2VycyBVc2VyIGlkLCBhcnJheSBvZiB1c2VyIGlkcywgb2JqZWN0LCBvciBhcnJheSBvZiBvYmplY3RzIG9mIHRoZSB1c2VycyB0byBhZGQgdG8gdGhpcyB3b3JsZC5cbiAgICAgICAgKiBAcGFyYW0ge3N0cmluZ30gdXNlcnMucm9sZSBUaGUgYHJvbGVgIHRoZSB1c2VyIHNob3VsZCBoYXZlIGluIHRoZSB3b3JsZC4gSXQgaXMgdXAgdG8gdGhlIGNhbGxlciB0byBlbnN1cmUsIGlmIG5lZWRlZCwgdGhhdCB0aGUgYHJvbGVgIHBhc3NlZCBpbiBpcyBvbmUgb2YgdGhlIGByb2xlc2Agb3IgYG9wdGlvbmFsUm9sZXNgIG9mIHRoaXMgd29ybGQuXG4gICAgICAgICogQHBhcmFtIHtzdHJpbmd9IHdvcmxkSWQgVGhlIHdvcmxkIHRvIHdoaWNoIHRoZSB1c2VycyBzaG91bGQgYmUgYWRkZWQuIElmIG5vdCBzcGVjaWZpZWQsIHRoZSBmaWx0ZXIgcGFyYW1ldGVyIG9mIHRoZSBgb3B0aW9uc2Agb2JqZWN0IGlzIHVzZWQuXG4gICAgICAgICogQHBhcmFtIHtvYmplY3R9IG9wdGlvbnMgKE9wdGlvbmFsKSBPcHRpb25zIG9iamVjdCB0byBvdmVycmlkZSBnbG9iYWwgb3B0aW9ucy5cbiAgICAgICAgKiBAcmV0dXJuIHtQcm9taXNlfVxuICAgICAgICAqL1xuICAgICAgICBhZGRVc2VyczogZnVuY3Rpb24gKHVzZXJzLCB3b3JsZElkLCBvcHRpb25zKSB7XG5cbiAgICAgICAgICAgIGlmICghdXNlcnMpIHtcbiAgICAgICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ1BsZWFzZSBwcm92aWRlIGEgbGlzdCBvZiB1c2VycyB0byBhZGQgdG8gdGhlIHdvcmxkJyk7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIC8vIG5vcm1hbGl6ZSB0aGUgbGlzdCBvZiB1c2VycyB0byBhbiBhcnJheSBvZiB1c2VyIG9iamVjdHNcbiAgICAgICAgICAgIHVzZXJzID0gJC5tYXAoW10uY29uY2F0KHVzZXJzKSwgZnVuY3Rpb24gKHUpIHtcbiAgICAgICAgICAgICAgICB2YXIgaXNPYmplY3QgPSAkLmlzUGxhaW5PYmplY3QodSk7XG5cbiAgICAgICAgICAgICAgICBpZiAodHlwZW9mIHUgIT09ICdzdHJpbmcnICYmICFpc09iamVjdCkge1xuICAgICAgICAgICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ1NvbWUgb2YgdGhlIHVzZXJzIGluIHRoZSBsaXN0IGFyZSBub3QgaW4gdGhlIHZhbGlkIGZvcm1hdDogJyArIHUpO1xuICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgIHJldHVybiBpc09iamVjdCA/IHUgOiB7IHVzZXJJZDogdSB9O1xuICAgICAgICAgICAgfSk7XG5cbiAgICAgICAgICAgIC8vIGNoZWNrIGlmIG9wdGlvbnMgd2VyZSBwYXNzZWQgYXMgdGhlIHNlY29uZCBwYXJhbWV0ZXJcbiAgICAgICAgICAgIGlmICgkLmlzUGxhaW5PYmplY3Qod29ybGRJZCkgJiYgIW9wdGlvbnMpIHtcbiAgICAgICAgICAgICAgICBvcHRpb25zID0gd29ybGRJZDtcbiAgICAgICAgICAgICAgICB3b3JsZElkID0gbnVsbDtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgb3B0aW9ucyA9IG9wdGlvbnMgfHwge307XG5cbiAgICAgICAgICAgIC8vIHdlIG11c3QgaGF2ZSBvcHRpb25zIGJ5IG5vd1xuICAgICAgICAgICAgaWYgKHR5cGVvZiB3b3JsZElkID09PSAnc3RyaW5nJykge1xuICAgICAgICAgICAgICAgIG9wdGlvbnMuZmlsdGVyID0gd29ybGRJZDtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgc2V0SWRGaWx0ZXJPclRocm93RXJyb3Iob3B0aW9ucyk7XG5cbiAgICAgICAgICAgIHZhciB1cGRhdGVPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sXG4gICAgICAgICAgICAgICAgc2VydmljZU9wdGlvbnMsXG4gICAgICAgICAgICAgICAgb3B0aW9ucyxcbiAgICAgICAgICAgICAgICB7IHVybDogdXJsQ29uZmlnLmdldEFQSVBhdGgoYXBpRW5kcG9pbnQpICsgc2VydmljZU9wdGlvbnMuZmlsdGVyICsgJy91c2VycycgfVxuICAgICAgICAgICAgKTtcblxuICAgICAgICAgICAgcmV0dXJuIGh0dHAucG9zdCh1c2VycywgdXBkYXRlT3B0aW9ucyk7XG4gICAgICAgIH0sXG5cbiAgICAgICAgLyoqXG4gICAgICAgICogVXBkYXRlcyB0aGUgcm9sZSBvZiBhbiBlbmQgdXNlciBpbiBhIGdpdmVuIHdvcmxkLiAoWW91IGNhbiBvbmx5IHVwZGF0ZSBvbmUgZW5kIHVzZXIgYXQgYSB0aW1lLilcbiAgICAgICAgKlxuICAgICAgICAqICoqRXhhbXBsZSoqXG4gICAgICAgICpcbiAgICAgICAgKiAgICAgIHZhciB3YSA9IG5ldyBGLnNlcnZpY2UuV29ybGQoe1xuICAgICAgICAqICAgICAgICAgICBhY2NvdW50OiAnYWNtZS1zaW11bGF0aW9ucycsXG4gICAgICAgICogICAgICAgICAgIHByb2plY3Q6ICdzdXBwbHktY2hhaW4tZ2FtZScsXG4gICAgICAgICogICAgICAgICAgIGdyb3VwOiAndGVhbTEnIH0pO1xuICAgICAgICAqXG4gICAgICAgICogICAgICB3YS5jcmVhdGUoKS50aGVuKGZ1bmN0aW9uKHdvcmxkKSB7XG4gICAgICAgICogICAgICAgICAgIHdhLmFkZFVzZXJzKCdiMWMxOWRkYS0yZDJlLTQ3NzctYWQ1ZC0zOTI5ZjE3ZTg2ZDMnKTtcbiAgICAgICAgKiAgICAgICAgICAgd2EudXBkYXRlVXNlcih7IHVzZXJJZDogJ2IxYzE5ZGRhLTJkMmUtNDc3Ny1hZDVkLTM5MjlmMTdlODZkMycsIHJvbGU6ICdsZWFkZXInIH0pO1xuICAgICAgICAqICAgICAgfSk7XG4gICAgICAgICpcbiAgICAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAqIEBwYXJhbSB7b2JqZWN0fSB1c2VyIFVzZXIgb2JqZWN0IHdpdGggYHVzZXJJZGAgYW5kIHRoZSBuZXcgYHJvbGVgLlxuICAgICAgICAqIEBwYXJhbSB7b2JqZWN0fSBvcHRpb25zIChPcHRpb25hbCkgT3B0aW9ucyBvYmplY3QgdG8gb3ZlcnJpZGUgZ2xvYmFsIG9wdGlvbnMuXG4gICAgICAgICogQHJldHVybiB7UHJvbWlzZX1cbiAgICAgICAgKi9cbiAgICAgICAgdXBkYXRlVXNlcjogZnVuY3Rpb24gKHVzZXIsIG9wdGlvbnMpIHtcbiAgICAgICAgICAgIG9wdGlvbnMgPSBvcHRpb25zIHx8IHt9O1xuXG4gICAgICAgICAgICBpZiAoIXVzZXIgfHwgIXVzZXIudXNlcklkKSB7XG4gICAgICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdZb3UgbmVlZCB0byBwYXNzIGEgdXNlcklkIHRvIHVwZGF0ZSBmcm9tIHRoZSB3b3JsZCcpO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICBzZXRJZEZpbHRlck9yVGhyb3dFcnJvcihvcHRpb25zKTtcblxuICAgICAgICAgICAgdmFyIHBhdGNoT3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LFxuICAgICAgICAgICAgICAgIHNlcnZpY2VPcHRpb25zLFxuICAgICAgICAgICAgICAgIG9wdGlvbnMsXG4gICAgICAgICAgICAgICAgeyB1cmw6IHVybENvbmZpZy5nZXRBUElQYXRoKGFwaUVuZHBvaW50KSArIHNlcnZpY2VPcHRpb25zLmZpbHRlciArICcvdXNlcnMvJyArIHVzZXIudXNlcklkIH1cbiAgICAgICAgICAgICk7XG5cbiAgICAgICAgICAgIHJldHVybiBodHRwLnBhdGNoKF9waWNrKHVzZXIsICdyb2xlJyksIHBhdGNoT3B0aW9ucyk7XG4gICAgICAgIH0sXG5cbiAgICAgICAgLyoqXG4gICAgICAgICogUmVtb3ZlcyBhbiBlbmQgdXNlciBmcm9tIGEgZ2l2ZW4gd29ybGQuXG4gICAgICAgICpcbiAgICAgICAgKiAgKipFeGFtcGxlKipcbiAgICAgICAgKlxuICAgICAgICAqICAgICAgdmFyIHdhID0gbmV3IEYuc2VydmljZS5Xb3JsZCh7XG4gICAgICAgICogICAgICAgICAgIGFjY291bnQ6ICdhY21lLXNpbXVsYXRpb25zJyxcbiAgICAgICAgKiAgICAgICAgICAgcHJvamVjdDogJ3N1cHBseS1jaGFpbi1nYW1lJyxcbiAgICAgICAgKiAgICAgICAgICAgZ3JvdXA6ICd0ZWFtMScgfSk7XG4gICAgICAgICogICAgICB3YS5jcmVhdGUoKVxuICAgICAgICAqICAgICAgICAgICAudGhlbihmdW5jdGlvbih3b3JsZCkge1xuICAgICAgICAqICAgICAgICAgICAgICAgd2EuYWRkVXNlcnMoWydhNmZlMGMxZS1mNGI4LTRmMDEtOWY1Zi0wMWNjZjRjMmVkNDQnLCAnOGYyNjA0Y2YtOTZjZC00NDlmLTgyZmEtZTMzMTUzMDczNGVlJ10pO1xuICAgICAgICAqICAgICAgICAgICAgICAgd2EucmVtb3ZlVXNlcignYTZmZTBjMWUtZjRiOC00ZjAxLTlmNWYtMDFjY2Y0YzJlZDQ0Jyk7XG4gICAgICAgICogICAgICAgICAgICAgICB3YS5yZW1vdmVVc2VyKHsgdXNlcklkOiAnOGYyNjA0Y2YtOTZjZC00NDlmLTgyZmEtZTMzMTUzMDczNGVlJyB9KTtcbiAgICAgICAgKiAgICAgICAgICAgfSk7XG4gICAgICAgICpcbiAgICAgICAgKiAqKiBQYXJhbWV0ZXJzICoqXG4gICAgICAgICogQHBhcmFtIHtvYmplY3R8c3RyaW5nfSB1c2VyIFRoZSBgdXNlcklkYCBvZiB0aGUgdXNlciB0byByZW1vdmUgZnJvbSB0aGUgd29ybGQsIG9yIGFuIG9iamVjdCBjb250YWluaW5nIHRoZSBgdXNlcklkYCBmaWVsZC5cbiAgICAgICAgKiBAcGFyYW0ge29iamVjdH0gb3B0aW9ucyAoT3B0aW9uYWwpIE9wdGlvbnMgb2JqZWN0IHRvIG92ZXJyaWRlIGdsb2JhbCBvcHRpb25zLlxuICAgICAgICAqIEByZXR1cm4ge1Byb21pc2V9XG4gICAgICAgICovXG4gICAgICAgIHJlbW92ZVVzZXI6IGZ1bmN0aW9uICh1c2VyLCBvcHRpb25zKSB7XG4gICAgICAgICAgICBvcHRpb25zID0gb3B0aW9ucyB8fCB7fTtcblxuICAgICAgICAgICAgaWYgKHR5cGVvZiB1c2VyID09PSAnc3RyaW5nJykge1xuICAgICAgICAgICAgICAgIHVzZXIgPSB7IHVzZXJJZDogdXNlciB9O1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICBpZiAoIXVzZXIudXNlcklkKSB7XG4gICAgICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdZb3UgbmVlZCB0byBwYXNzIGEgdXNlcklkIHRvIHJlbW92ZSBmcm9tIHRoZSB3b3JsZCcpO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICBzZXRJZEZpbHRlck9yVGhyb3dFcnJvcihvcHRpb25zKTtcblxuICAgICAgICAgICAgdmFyIGdldE9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSxcbiAgICAgICAgICAgICAgICBzZXJ2aWNlT3B0aW9ucyxcbiAgICAgICAgICAgICAgICBvcHRpb25zLFxuICAgICAgICAgICAgICAgIHsgdXJsOiB1cmxDb25maWcuZ2V0QVBJUGF0aChhcGlFbmRwb2ludCkgKyBzZXJ2aWNlT3B0aW9ucy5maWx0ZXIgKyAnL3VzZXJzLycgKyB1c2VyLnVzZXJJZCB9XG4gICAgICAgICAgICApO1xuXG4gICAgICAgICAgICByZXR1cm4gaHR0cC5kZWxldGUobnVsbCwgZ2V0T3B0aW9ucyk7XG4gICAgICAgIH0sXG5cbiAgICAgICAgLyoqXG4gICAgICAgICogR2V0cyB0aGUgcnVuIGlkIG9mIGN1cnJlbnQgcnVuIGZvciB0aGUgZ2l2ZW4gd29ybGQuIElmIHRoZSB3b3JsZCBkb2VzIG5vdCBoYXZlIGEgcnVuLCBjcmVhdGVzIGEgbmV3IG9uZSBhbmQgcmV0dXJucyB0aGUgcnVuIGlkLlxuICAgICAgICAqXG4gICAgICAgICogUmVtZW1iZXIgdGhhdCBhIFtydW5dKC4uLy4uL2dsb3NzYXJ5LyNydW4pIGlzIGEgY29sbGVjdGlvbiBvZiBpbnRlcmFjdGlvbnMgd2l0aCBhIHByb2plY3QgYW5kIGl0cyBtb2RlbC4gSW4gdGhlIGNhc2Ugb2YgbXVsdGlwbGF5ZXIgcHJvamVjdHMsIHRoZSBydW4gaXMgc2hhcmVkIGJ5IGFsbCBlbmQgdXNlcnMgaW4gdGhlIHdvcmxkLlxuICAgICAgICAqXG4gICAgICAgICogICoqRXhhbXBsZSoqXG4gICAgICAgICpcbiAgICAgICAgKiAgICAgIHZhciB3YSA9IG5ldyBGLnNlcnZpY2UuV29ybGQoe1xuICAgICAgICAqICAgICAgICAgICBhY2NvdW50OiAnYWNtZS1zaW11bGF0aW9ucycsXG4gICAgICAgICogICAgICAgICAgIHByb2plY3Q6ICdzdXBwbHktY2hhaW4tZ2FtZScsXG4gICAgICAgICogICAgICAgICAgIGdyb3VwOiAndGVhbTEnIH0pO1xuICAgICAgICAqICAgICAgd2EuY3JlYXRlKClcbiAgICAgICAgKiAgICAgICAgICAgLnRoZW4oZnVuY3Rpb24od29ybGQpIHtcbiAgICAgICAgKiAgICAgICAgICAgICAgIHdhLmdldEN1cnJlbnRSdW5JZCh7IG1vZGVsOiAnbW9kZWwucHknIH0pO1xuICAgICAgICAqICAgICAgICAgICB9KTtcbiAgICAgICAgKlxuICAgICAgICAqICoqIFBhcmFtZXRlcnMgKipcbiAgICAgICAgKiBAcGFyYW0ge29iamVjdH0gb3B0aW9ucyAoT3B0aW9uYWwpIE9wdGlvbnMgb2JqZWN0IHRvIG92ZXJyaWRlIGdsb2JhbCBvcHRpb25zLlxuICAgICAgICAqIEBwYXJhbSB7b2JqZWN0fSBvcHRpb25zLm1vZGVsIFRoZSBtb2RlbCBmaWxlIHRvIHVzZSB0byBjcmVhdGUgYSBydW4gaWYgbmVlZGVkLlxuICAgICAgICAqIEByZXR1cm4ge1Byb21pc2V9XG4gICAgICAgICovXG4gICAgICAgIGdldEN1cnJlbnRSdW5JZDogZnVuY3Rpb24gKG9wdGlvbnMpIHtcbiAgICAgICAgICAgIG9wdGlvbnMgPSBvcHRpb25zIHx8IHt9O1xuXG4gICAgICAgICAgICBzZXRJZEZpbHRlck9yVGhyb3dFcnJvcihvcHRpb25zKTtcblxuICAgICAgICAgICAgdmFyIGdldE9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSxcbiAgICAgICAgICAgICAgICBzZXJ2aWNlT3B0aW9ucyxcbiAgICAgICAgICAgICAgICBvcHRpb25zLFxuICAgICAgICAgICAgICAgIHsgdXJsOiB1cmxDb25maWcuZ2V0QVBJUGF0aChhcGlFbmRwb2ludCkgKyBzZXJ2aWNlT3B0aW9ucy5maWx0ZXIgKyAnL3J1bicgfVxuICAgICAgICAgICAgKTtcblxuICAgICAgICAgICAgdmFsaWRhdGVNb2RlbE9yVGhyb3dFcnJvcihnZXRPcHRpb25zKTtcbiAgICAgICAgICAgIHJldHVybiBodHRwLnBvc3QoX3BpY2soZ2V0T3B0aW9ucywgJ21vZGVsJyksIGdldE9wdGlvbnMpO1xuICAgICAgICB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAqIEdldHMgdGhlIGN1cnJlbnQgKG1vc3QgcmVjZW50KSB3b3JsZCBmb3IgdGhlIGdpdmVuIGVuZCB1c2VyIGluIHRoZSBnaXZlbiBncm91cC4gQnJpbmdzIHRoaXMgbW9zdCByZWNlbnQgd29ybGQgaW50byBtZW1vcnkgaWYgbmVlZGVkLlxuICAgICAgICAqXG4gICAgICAgICogICoqRXhhbXBsZSoqXG4gICAgICAgICpcbiAgICAgICAgKiAgICAgIHZhciB3YSA9IG5ldyBGLnNlcnZpY2UuV29ybGQoe1xuICAgICAgICAqICAgICAgICAgICBhY2NvdW50OiAnYWNtZS1zaW11bGF0aW9ucycsXG4gICAgICAgICogICAgICAgICAgIHByb2plY3Q6ICdzdXBwbHktY2hhaW4tZ2FtZScsXG4gICAgICAgICogICAgICAgICAgIGdyb3VwOiAndGVhbTEnIH0pO1xuICAgICAgICAqICAgICAgd2EuZ2V0Q3VycmVudFdvcmxkRm9yVXNlcignOGYyNjA0Y2YtOTZjZC00NDlmLTgyZmEtZTMzMTUzMDczNGVlJylcbiAgICAgICAgKiAgICAgICAgICAgLnRoZW4oZnVuY3Rpb24od29ybGQpIHtcbiAgICAgICAgKiAgICAgICAgICAgICAgIC8vIHVzZSBkYXRhIGZyb20gd29ybGRcbiAgICAgICAgKiAgICAgICAgICAgfSk7XG4gICAgICAgICpcbiAgICAgICAgKiAqKiBQYXJhbWV0ZXJzICoqXG4gICAgICAgICogQHBhcmFtIHtzdHJpbmd9IHVzZXJJZCBUaGUgYHVzZXJJZGAgb2YgdGhlIHVzZXIgd2hvc2UgY3VycmVudCAobW9zdCByZWNlbnQpIHdvcmxkIGlzIGJlaW5nIHJldHJpZXZlZC5cbiAgICAgICAgKiBAcGFyYW0ge3N0cmluZ30gZ3JvdXBOYW1lIChPcHRpb25hbCkgVGhlIG5hbWUgb2YgdGhlIGdyb3VwLiBJZiBub3QgcHJvdmlkZWQsIGRlZmF1bHRzIHRvIHRoZSBncm91cCB1c2VkIHRvIGNyZWF0ZSB0aGUgc2VydmljZS5cbiAgICAgICAgKiBAcmV0dXJuIHtQcm9taXNlfVxuICAgICAgICAqL1xuICAgICAgICBnZXRDdXJyZW50V29ybGRGb3JVc2VyOiBmdW5jdGlvbiAodXNlcklkLCBncm91cE5hbWUpIHtcbiAgICAgICAgICAgIHZhciBkdGQgPSAkLkRlZmVycmVkKCk7XG4gICAgICAgICAgICB2YXIgbWUgPSB0aGlzO1xuICAgICAgICAgICAgdGhpcy5nZXRXb3JsZHNGb3JVc2VyKHVzZXJJZCwgeyBncm91cDogZ3JvdXBOYW1lIH0pXG4gICAgICAgICAgICAgICAgLnRoZW4oZnVuY3Rpb24gKHdvcmxkcykge1xuICAgICAgICAgICAgICAgICAgICAvLyBhc3N1bWUgdGhlIG1vc3QgcmVjZW50IHdvcmxkIGFzIHRoZSAnYWN0aXZlJyB3b3JsZFxuICAgICAgICAgICAgICAgICAgICB3b3JsZHMuc29ydChmdW5jdGlvbiAoYSwgYikgeyByZXR1cm4gbmV3IERhdGUoYi5sYXN0TW9kaWZpZWQpIC0gbmV3IERhdGUoYS5sYXN0TW9kaWZpZWQpOyB9KTtcbiAgICAgICAgICAgICAgICAgICAgdmFyIGN1cnJlbnRXb3JsZCA9IHdvcmxkc1swXTtcblxuICAgICAgICAgICAgICAgICAgICBpZiAoY3VycmVudFdvcmxkKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBzZXJ2aWNlT3B0aW9ucy5maWx0ZXIgPSBjdXJyZW50V29ybGQuaWQ7XG4gICAgICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgICAgICBkdGQucmVzb2x2ZVdpdGgobWUsIFtjdXJyZW50V29ybGRdKTtcbiAgICAgICAgICAgICAgICB9KVxuICAgICAgICAgICAgICAgIC5mYWlsKGR0ZC5yZWplY3QpO1xuXG4gICAgICAgICAgICByZXR1cm4gZHRkLnByb21pc2UoKTtcbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgKiBEZWxldGVzIHRoZSBjdXJyZW50IHJ1biBmcm9tIHRoZSB3b3JsZC5cbiAgICAgICAgKlxuICAgICAgICAqIChOb3RlIHRoYXQgdGhlIHdvcmxkIGlkIHJlbWFpbnMgcGFydCBvZiB0aGUgcnVuIHJlY29yZCwgaW5kaWNhdGluZyB0aGF0IHRoZSBydW4gd2FzIGZvcm1lcmx5IGFuIGFjdGl2ZSBydW4gZm9yIHRoZSB3b3JsZC4pXG4gICAgICAgICpcbiAgICAgICAgKiAgKipFeGFtcGxlKipcbiAgICAgICAgKlxuICAgICAgICAqICAgICAgdmFyIHdhID0gbmV3IEYuc2VydmljZS5Xb3JsZCh7XG4gICAgICAgICogICAgICAgICAgIGFjY291bnQ6ICdhY21lLXNpbXVsYXRpb25zJyxcbiAgICAgICAgKiAgICAgICAgICAgcHJvamVjdDogJ3N1cHBseS1jaGFpbi1nYW1lJyxcbiAgICAgICAgKiAgICAgICAgICAgZ3JvdXA6ICd0ZWFtMScgfSk7XG4gICAgICAgICpcbiAgICAgICAgKiAgICAgIHdhLmRlbGV0ZVJ1bignc2FtcGxlLXdvcmxkLWlkJyk7XG4gICAgICAgICpcbiAgICAgICAgKiAgKipQYXJhbWV0ZXJzKipcbiAgICAgICAgKiBAcGFyYW0ge3N0cmluZ30gd29ybGRJZCBUaGUgYHdvcmxkSWRgIG9mIHRoZSB3b3JsZCBmcm9tIHdoaWNoIHRoZSBjdXJyZW50IHJ1biBpcyBiZWluZyBkZWxldGVkLlxuICAgICAgICAqIEBwYXJhbSB7b2JqZWN0fSBvcHRpb25zIChPcHRpb25hbCkgT3B0aW9ucyBvYmplY3QgdG8gb3ZlcnJpZGUgZ2xvYmFsIG9wdGlvbnMuXG4gICAgICAgICogQHJldHVybiB7UHJvbWlzZX1cbiAgICAgICAgKi9cbiAgICAgICAgZGVsZXRlUnVuOiBmdW5jdGlvbiAod29ybGRJZCwgb3B0aW9ucykge1xuICAgICAgICAgICAgb3B0aW9ucyA9IG9wdGlvbnMgfHwge307XG5cbiAgICAgICAgICAgIGlmICh3b3JsZElkKSB7XG4gICAgICAgICAgICAgICAgb3B0aW9ucy5maWx0ZXIgPSB3b3JsZElkO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICBzZXRJZEZpbHRlck9yVGhyb3dFcnJvcihvcHRpb25zKTtcblxuICAgICAgICAgICAgdmFyIGRlbGV0ZU9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSxcbiAgICAgICAgICAgICAgICBzZXJ2aWNlT3B0aW9ucyxcbiAgICAgICAgICAgICAgICBvcHRpb25zLFxuICAgICAgICAgICAgICAgIHsgdXJsOiB1cmxDb25maWcuZ2V0QVBJUGF0aChhcGlFbmRwb2ludCkgKyBzZXJ2aWNlT3B0aW9ucy5maWx0ZXIgKyAnL3J1bicgfVxuICAgICAgICAgICAgKTtcblxuICAgICAgICAgICAgcmV0dXJuIGh0dHAuZGVsZXRlKG51bGwsIGRlbGV0ZU9wdGlvbnMpO1xuICAgICAgICB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAqIENyZWF0ZXMgYSBuZXcgcnVuIGZvciB0aGUgd29ybGQuXG4gICAgICAgICpcbiAgICAgICAgKiAgKipFeGFtcGxlKipcbiAgICAgICAgKlxuICAgICAgICAqICAgICAgdmFyIHdhID0gbmV3IEYuc2VydmljZS5Xb3JsZCh7XG4gICAgICAgICogICAgICAgICAgIGFjY291bnQ6ICdhY21lLXNpbXVsYXRpb25zJyxcbiAgICAgICAgKiAgICAgICAgICAgcHJvamVjdDogJ3N1cHBseS1jaGFpbi1nYW1lJyxcbiAgICAgICAgKiAgICAgICAgICAgZ3JvdXA6ICd0ZWFtMScgfSk7XG4gICAgICAgICpcbiAgICAgICAgKiAgICAgIHdhLmdldEN1cnJlbnRXb3JsZEZvclVzZXIoJzhmMjYwNGNmLTk2Y2QtNDQ5Zi04MmZhLWUzMzE1MzA3MzRlZScpXG4gICAgICAgICogICAgICAgICAgIC50aGVuKGZ1bmN0aW9uICh3b3JsZCkge1xuICAgICAgICAqICAgICAgICAgICAgICAgICAgIHdhLm5ld1J1bkZvcldvcmxkKHdvcmxkLmlkKTtcbiAgICAgICAgKiAgICAgICAgICAgfSk7XG4gICAgICAgICpcbiAgICAgICAgKiAgKipQYXJhbWV0ZXJzKipcbiAgICAgICAgKiBAcGFyYW0ge3N0cmluZ30gd29ybGRJZCB3b3JsZElkIGluIHdoaWNoIHdlIGNyZWF0ZSB0aGUgbmV3IHJ1bi5cbiAgICAgICAgKiBAcGFyYW0ge29iamVjdH0gb3B0aW9ucyAoT3B0aW9uYWwpIE9wdGlvbnMgb2JqZWN0IHRvIG92ZXJyaWRlIGdsb2JhbCBvcHRpb25zLlxuICAgICAgICAqIEBwYXJhbSB7b2JqZWN0fSBvcHRpb25zLm1vZGVsIFRoZSBtb2RlbCBmaWxlIHRvIHVzZSB0byBjcmVhdGUgYSBydW4gaWYgbmVlZGVkLlxuICAgICAgICAqIEByZXR1cm4ge1Byb21pc2V9XG4gICAgICAgICovXG4gICAgICAgIG5ld1J1bkZvcldvcmxkOiBmdW5jdGlvbiAod29ybGRJZCwgb3B0aW9ucykge1xuICAgICAgICAgICAgdmFyIGN1cnJlbnRSdW5PcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sXG4gICAgICAgICAgICAgICAgc2VydmljZU9wdGlvbnMsXG4gICAgICAgICAgICAgICAgb3B0aW9ucyxcbiAgICAgICAgICAgICAgICB7IGZpbHRlcjogd29ybGRJZCB8fCBzZXJ2aWNlT3B0aW9ucy5maWx0ZXIgfVxuICAgICAgICAgICAgKTtcbiAgICAgICAgICAgIHZhciBtZSA9IHRoaXM7XG5cbiAgICAgICAgICAgIHZhbGlkYXRlTW9kZWxPclRocm93RXJyb3IoY3VycmVudFJ1bk9wdGlvbnMpO1xuXG4gICAgICAgICAgICByZXR1cm4gdGhpcy5kZWxldGVSdW4od29ybGRJZCwgb3B0aW9ucylcbiAgICAgICAgICAgICAgICAudGhlbihmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICAgICAgICAgIHJldHVybiBtZS5nZXRDdXJyZW50UnVuSWQoY3VycmVudFJ1bk9wdGlvbnMpO1xuICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAqIEFzc2lnbnMgZW5kIHVzZXJzIHRvIHdvcmxkcywgY3JlYXRpbmcgbmV3IHdvcmxkcyBhcyBhcHByb3ByaWF0ZSwgYXV0b21hdGljYWxseS4gQXNzaWducyBhbGwgZW5kIHVzZXJzIGluIHRoZSBncm91cCwgYW5kIGNyZWF0ZXMgbmV3IHdvcmxkcyBhcyBuZWVkZWQgYmFzZWQgb24gdGhlIHByb2plY3QtbGV2ZWwgd29ybGQgY29uZmlndXJhdGlvbiAocm9sZXMsIG9wdGlvbmFsIHJvbGVzLCBhbmQgbWluaW11bSBlbmQgdXNlcnMgcGVyIHdvcmxkKS5cbiAgICAgICAgKlxuICAgICAgICAqICoqRXhhbXBsZSoqXG4gICAgICAgICpcbiAgICAgICAgKiAgICAgIHZhciB3YSA9IG5ldyBGLnNlcnZpY2UuV29ybGQoe1xuICAgICAgICAqICAgICAgICAgICBhY2NvdW50OiAnYWNtZS1zaW11bGF0aW9ucycsXG4gICAgICAgICogICAgICAgICAgIHByb2plY3Q6ICdzdXBwbHktY2hhaW4tZ2FtZScsXG4gICAgICAgICogICAgICAgICAgIGdyb3VwOiAndGVhbTEnIH0pO1xuICAgICAgICAqXG4gICAgICAgICogICAgICB3YS5hdXRvQXNzaWduKCk7XG4gICAgICAgICpcbiAgICAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAqIEBwYXJhbSB7b2JqZWN0fSBvcHRpb25zIChPcHRpb25hbCkgT3B0aW9ucyBvYmplY3QgdG8gb3ZlcnJpZGUgZ2xvYmFsIG9wdGlvbnMuXG4gICAgICAgICogQHBhcmFtIHtudW1iZXJ9IG9wdGlvbnMubWF4VXNlcnMgU2V0cyB0aGUgbWF4aW11bSBudW1iZXIgb2YgdXNlcnMgaW4gYSB3b3JsZC5cbiAgICAgICAgKiBAcGFyYW0ge3N0cmluZ1tdfSBvcHRpb25zLnVzZXJJZHMgQSBsaXN0IG9mIHVzZXJzIHRvIGJlIGFzc2lnbmVkIGJlIGFzc2lnbmVkIGluc3RlYWQgb2YgYWxsIGVuZCB1c2VycyBpbiB0aGUgZ3JvdXAuXG4gICAgICAgICogQHJldHVybiB7UHJvbWlzZX1cbiAgICAgICAgKlxuICAgICAgICAqL1xuICAgICAgICBhdXRvQXNzaWduOiBmdW5jdGlvbiAob3B0aW9ucykge1xuICAgICAgICAgICAgb3B0aW9ucyA9IG9wdGlvbnMgfHwge307XG5cbiAgICAgICAgICAgIHZhciBvcHQgPSAkLmV4dGVuZCh0cnVlLCB7fSxcbiAgICAgICAgICAgICAgICBzZXJ2aWNlT3B0aW9ucyxcbiAgICAgICAgICAgICAgICBvcHRpb25zLFxuICAgICAgICAgICAgICAgIHsgdXJsOiB1cmxDb25maWcuZ2V0QVBJUGF0aChhc3NpZ25tZW50RW5kcG9pbnQpIH1cbiAgICAgICAgICAgICk7XG5cbiAgICAgICAgICAgIHZhciBwYXJhbXMgPSB7XG4gICAgICAgICAgICAgICAgYWNjb3VudDogb3B0LmFjY291bnQsXG4gICAgICAgICAgICAgICAgcHJvamVjdDogb3B0LnByb2plY3QsXG4gICAgICAgICAgICAgICAgZ3JvdXA6IG9wdC5ncm91cFxuICAgICAgICAgICAgfTtcblxuICAgICAgICAgICAgaWYgKG9wdC5tYXhVc2Vycykge1xuICAgICAgICAgICAgICAgIHBhcmFtcy5tYXhVc2VycyA9IG9wdC5tYXhVc2VycztcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgaWYgKG9wdC51c2VySWRzKSB7XG4gICAgICAgICAgICAgICAgcGFyYW1zLnVzZXJJZHMgPSBvcHQudXNlcklkcztcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgcmV0dXJuIGh0dHAucG9zdChwYXJhbXMsIG9wdCk7XG4gICAgICAgIH0sXG5cbiAgICAgICAgLyoqXG4gICAgICAgICogR2V0cyB0aGUgcHJvamVjdCdzIHdvcmxkIGNvbmZpZ3VyYXRpb24uXG4gICAgICAgICpcbiAgICAgICAgKiBUeXBpY2FsbHksIGV2ZXJ5IGludGVyYWN0aW9uIHdpdGggeW91ciBwcm9qZWN0IHVzZXMgdGhlIHNhbWUgY29uZmlndXJhdGlvbiBvZiBlYWNoIHdvcmxkLiBGb3IgZXhhbXBsZSwgZWFjaCB3b3JsZCBpbiB5b3VyIHByb2plY3QgcHJvYmFibHkgaGFzIHRoZSBzYW1lIHJvbGVzIGZvciBlbmQgdXNlcnMuIEFuZCB5b3VyIHByb2plY3QgaXMgcHJvYmFibHkgZWl0aGVyIGNvbmZpZ3VyZWQgc28gdGhhdCBhbGwgZW5kIHVzZXJzIHNoYXJlIHRoZSBzYW1lIHdvcmxkIChhbmQgcnVuKSwgb3Igc21hbGxlciBzZXRzIG9mIGVuZCB1c2VycyBzaGFyZSB3b3JsZHMg4oCUIGJ1dCBub3QgYm90aC5cbiAgICAgICAgKlxuICAgICAgICAqIChUaGUgW011bHRpcGxheWVyIFByb2plY3QgUkVTVCBBUEldKC4uLy4uLy4uL3Jlc3RfYXBpcy9tdWx0aXBsYXllci9tdWx0aXBsYXllcl9wcm9qZWN0LykgYWxsb3dzIHlvdSB0byBzZXQgdGhlc2UgcHJvamVjdC1sZXZlbCB3b3JsZCBjb25maWd1cmF0aW9ucy4gVGhlIFdvcmxkIEFkYXB0ZXIgc2ltcGx5IHJldHJpZXZlcyB0aGVtLCBmb3IgZXhhbXBsZSBzbyB0aGV5IGNhbiBiZSB1c2VkIGluIGF1dG8tYXNzaWdubWVudCBvZiBlbmQgdXNlcnMgdG8gd29ybGRzLilcbiAgICAgICAgKlxuICAgICAgICAqICoqRXhhbXBsZSoqXG4gICAgICAgICpcbiAgICAgICAgKiAgICAgIHZhciB3YSA9IG5ldyBGLnNlcnZpY2UuV29ybGQoe1xuICAgICAgICAqICAgICAgICAgICBhY2NvdW50OiAnYWNtZS1zaW11bGF0aW9ucycsXG4gICAgICAgICogICAgICAgICAgIHByb2plY3Q6ICdzdXBwbHktY2hhaW4tZ2FtZScsXG4gICAgICAgICogICAgICAgICAgIGdyb3VwOiAndGVhbTEnIH0pO1xuICAgICAgICAqXG4gICAgICAgICogICAgICB3YS5nZXRQcm9qZWN0U2V0dGluZ3MoKVxuICAgICAgICAqICAgICAgICAgICAudGhlbihmdW5jdGlvbihzZXR0aW5ncykge1xuICAgICAgICAqICAgICAgICAgICAgICAgY29uc29sZS5sb2coc2V0dGluZ3Mucm9sZXMpO1xuICAgICAgICAqICAgICAgICAgICAgICAgY29uc29sZS5sb2coc2V0dGluZ3Mub3B0aW9uYWxSb2xlcyk7XG4gICAgICAgICogICAgICAgICAgIH0pO1xuICAgICAgICAqXG4gICAgICAgICogKipQYXJhbWV0ZXJzKipcbiAgICAgICAgKiBAcGFyYW0ge29iamVjdH0gb3B0aW9ucyAoT3B0aW9uYWwpIE9wdGlvbnMgb2JqZWN0IHRvIG92ZXJyaWRlIGdsb2JhbCBvcHRpb25zLlxuICAgICAgICAqIEByZXR1cm4ge1Byb21pc2V9XG4gICAgICAgICovXG4gICAgICAgIGdldFByb2plY3RTZXR0aW5nczogZnVuY3Rpb24gKG9wdGlvbnMpIHtcbiAgICAgICAgICAgIG9wdGlvbnMgPSBvcHRpb25zIHx8IHt9O1xuXG4gICAgICAgICAgICB2YXIgb3B0ID0gJC5leHRlbmQodHJ1ZSwge30sXG4gICAgICAgICAgICAgICAgc2VydmljZU9wdGlvbnMsXG4gICAgICAgICAgICAgICAgb3B0aW9ucyxcbiAgICAgICAgICAgICAgICB7IHVybDogdXJsQ29uZmlnLmdldEFQSVBhdGgocHJvamVjdEVuZHBvaW50KSB9XG4gICAgICAgICAgICApO1xuXG4gICAgICAgICAgICBvcHQudXJsICs9IFtvcHQuYWNjb3VudCwgb3B0LnByb2plY3RdLmpvaW4oJy8nKTtcbiAgICAgICAgICAgIHJldHVybiBodHRwLmdldChudWxsLCBvcHQpO1xuICAgICAgICB9XG5cbiAgICB9O1xuXG4gICAgJC5leHRlbmQodGhpcywgcHVibGljQVBJKTtcbn07XG4iLCIvKipcbiAqIEBjbGFzcyBDb29raWUgU3RvcmFnZSBTZXJ2aWNlXG4gKlxuICogQGV4YW1wbGVcbiAqICAgICAgdmFyIHBlb3BsZSA9IHJlcXVpcmUoJ2Nvb2tpZS1zdG9yZScpKHsgcm9vdDogJ3Blb3BsZScgfSk7XG4gICAgICAgIHBlb3BsZVxuICAgICAgICAgICAgLnNhdmUoe2xhc3ROYW1lOiAnc21pdGgnIH0pXG5cbiAqL1xuXG5cbid1c2Ugc3RyaWN0JztcblxuLy8gVGhpbiBkb2N1bWVudC5jb29raWUgd3JhcHBlciB0byBhbGxvdyB1bml0IHRlc3RpbmdcbnZhciBDb29raWUgPSBmdW5jdGlvbiAoKSB7XG4gICAgdGhpcy5nZXQgPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHJldHVybiBkb2N1bWVudC5jb29raWU7XG4gICAgfTtcblxuICAgIHRoaXMuc2V0ID0gZnVuY3Rpb24gKG5ld0Nvb2tpZSkge1xuICAgICAgICBkb2N1bWVudC5jb29raWUgPSBuZXdDb29raWU7XG4gICAgfTtcbn07XG5cbm1vZHVsZS5leHBvcnRzID0gZnVuY3Rpb24gKGNvbmZpZykge1xuICAgIHZhciBob3N0ID0gd2luZG93LmxvY2F0aW9uLmhvc3RuYW1lO1xuICAgIHZhciB2YWxpZEhvc3QgPSBob3N0LnNwbGl0KCcuJykubGVuZ3RoID4gMTtcbiAgICB2YXIgZG9tYWluID0gdmFsaWRIb3N0ID8gJy4nICsgaG9zdCA6IG51bGw7XG5cbiAgICB2YXIgZGVmYXVsdHMgPSB7XG4gICAgICAgIC8qKlxuICAgICAgICAgKiBOYW1lIG9mIGNvbGxlY3Rpb25cbiAgICAgICAgICogQHR5cGUgeyBzdHJpbmd9XG4gICAgICAgICAqL1xuICAgICAgICByb290OiAnLycsXG5cbiAgICAgICAgZG9tYWluOiBkb21haW4sXG4gICAgICAgIGNvb2tpZTogbmV3IENvb2tpZSgpXG4gICAgfTtcbiAgICB0aGlzLnNlcnZpY2VPcHRpb25zID0gJC5leHRlbmQoe30sIGRlZmF1bHRzLCBjb25maWcpO1xuXG4gICAgdmFyIHB1YmxpY0FQSSA9IHtcbiAgICAgICAgLy8gKiBUQkRcbiAgICAgICAgLy8gICogUXVlcnkgY29sbGVjdGlvbjsgdXNlcyBNb25nb0RCIHN5bnRheFxuICAgICAgICAvLyAgKiBAc2VlICA8VEJEOiBEYXRhIEFQSSBVUkw+XG4gICAgICAgIC8vICAqXG4gICAgICAgIC8vICAqIEBwYXJhbSB7IHN0cmluZ30gcXMgUXVlcnkgRmlsdGVyXG4gICAgICAgIC8vICAqIEBwYXJhbSB7IHN0cmluZ30gbGltaXRlcnMgQHNlZSA8VEJEOiB1cmwgZm9yIGxpbWl0cywgcGFnaW5nIGV0Yz5cbiAgICAgICAgLy8gICpcbiAgICAgICAgLy8gICogQGV4YW1wbGVcbiAgICAgICAgLy8gICogICAgIGNzLnF1ZXJ5KFxuICAgICAgICAvLyAgKiAgICAgIHsgbmFtZTogJ0pvaG4nLCBjbGFzc05hbWU6ICdDU0MxMDEnIH0sXG4gICAgICAgIC8vICAqICAgICAge2xpbWl0OiAxMH1cbiAgICAgICAgLy8gICogICAgIClcblxuICAgICAgICAvLyBxdWVyeTogZnVuY3Rpb24gKHFzLCBsaW1pdGVycykge1xuXG4gICAgICAgIC8vIH0sXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIFNhdmUgY29va2llIHZhbHVlXG4gICAgICAgICAqIEBwYXJhbSAgeyBzdHJpbmd8T2JqZWN0fSBrZXkgICBJZiBnaXZlbiBhIGtleSBzYXZlIHZhbHVlcyB1bmRlciBpdCwgaWYgZ2l2ZW4gYW4gb2JqZWN0IGRpcmVjdGx5LCBzYXZlIHRvIHRvcC1sZXZlbCBhcGlcbiAgICAgICAgICogQHBhcmFtICB7T2JqZWN0fSB2YWx1ZSAoT3B0aW9uYWwpXG4gICAgICAgICAqIEBwYXJhbSB7T2JqZWN0fSBvcHRpb25zIE92ZXJyaWRlcyBmb3Igc2VydmljZSBvcHRpb25zXG4gICAgICAgICAqXG4gICAgICAgICAqIEByZXR1cm4geyp9IFRoZSBzYXZlZCB2YWx1ZVxuICAgICAgICAgKlxuICAgICAgICAgKiBAZXhhbXBsZVxuICAgICAgICAgKiAgICAgY3Muc2V0KCdwZXJzb24nLCB7IGZpcnN0TmFtZTogJ2pvaG4nLCBsYXN0TmFtZTogJ3NtaXRoJyB9KTtcbiAgICAgICAgICogICAgIGNzLnNldCh7IG5hbWU6J3NtaXRoJywgYWdlOiczMicgfSk7XG4gICAgICAgICAqL1xuICAgICAgICBzZXQ6IGZ1bmN0aW9uIChrZXksIHZhbHVlLCBvcHRpb25zKSB7XG4gICAgICAgICAgICB2YXIgc2V0T3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LCB0aGlzLnNlcnZpY2VPcHRpb25zLCBvcHRpb25zKTtcblxuICAgICAgICAgICAgdmFyIGRvbWFpbiA9IHNldE9wdGlvbnMuZG9tYWluO1xuICAgICAgICAgICAgdmFyIHBhdGggPSBzZXRPcHRpb25zLnJvb3Q7XG4gICAgICAgICAgICB2YXIgY29va2llID0gc2V0T3B0aW9ucy5jb29raWU7XG5cbiAgICAgICAgICAgIGNvb2tpZS5zZXQoZW5jb2RlVVJJQ29tcG9uZW50KGtleSkgKyAnPScgK1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBlbmNvZGVVUklDb21wb25lbnQodmFsdWUpICtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKGRvbWFpbiA/ICc7IGRvbWFpbj0nICsgZG9tYWluIDogJycpICtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKHBhdGggPyAnOyBwYXRoPScgKyBwYXRoIDogJycpXG4gICAgICAgICAgICApO1xuXG4gICAgICAgICAgICByZXR1cm4gdmFsdWU7XG4gICAgICAgIH0sXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIExvYWQgY29va2llIHZhbHVlXG4gICAgICAgICAqIEBwYXJhbSAgeyBzdHJpbmd8T2JqZWN0fSBrZXkgICBJZiBnaXZlbiBhIGtleSBzYXZlIHZhbHVlcyB1bmRlciBpdCwgaWYgZ2l2ZW4gYW4gb2JqZWN0IGRpcmVjdGx5LCBzYXZlIHRvIHRvcC1sZXZlbCBhcGlcbiAgICAgICAgICogQHJldHVybiB7Kn0gVGhlIHZhbHVlIHN0b3JlZFxuICAgICAgICAgKlxuICAgICAgICAgKiBAZXhhbXBsZVxuICAgICAgICAgKiAgICAgY3MuZ2V0KCdwZXJzb24nKTtcbiAgICAgICAgICovXG4gICAgICAgIGdldDogZnVuY3Rpb24gKGtleSkge1xuICAgICAgICAgICAgdmFyIGNvb2tpZSA9IHRoaXMuc2VydmljZU9wdGlvbnMuY29va2llO1xuICAgICAgICAgICAgdmFyIGNvb2tpZVJlZyA9IG5ldyBSZWdFeHAoJyg/Ol58OylcXFxccyonICsgZW5jb2RlVVJJQ29tcG9uZW50KGtleSkucmVwbGFjZSgvW1xcLVxcLlxcK1xcKl0vZywgJ1xcXFwkJicpICsgJ1xcXFxzKlxcXFw9XFxcXHMqKFteO10qKS4qJCcpO1xuICAgICAgICAgICAgdmFyIHJlcyA9IGNvb2tpZVJlZy5leGVjKGNvb2tpZS5nZXQoKSk7XG4gICAgICAgICAgICB2YXIgdmFsID0gcmVzID8gZGVjb2RlVVJJQ29tcG9uZW50KHJlc1sxXSkgOiBudWxsO1xuICAgICAgICAgICAgcmV0dXJuIHZhbDtcbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgICogUmVtb3ZlcyBrZXkgZnJvbSBjb2xsZWN0aW9uXG4gICAgICAgICAqIEBwYXJhbSB7IHN0cmluZ30ga2V5IGtleSB0byByZW1vdmVcbiAgICAgICAgICogQHBhcmFtIHtvYmplY3R9IG9wdGlvbnMgKG9wdGlvbmFsKSBvdmVycmlkZXMgZm9yIHNlcnZpY2Ugb3B0aW9uc1xuICAgICAgICAgKiBAcmV0dXJuIHsgc3RyaW5nfSBrZXkgVGhlIGtleSByZW1vdmVkXG4gICAgICAgICAqXG4gICAgICAgICAqIEBleGFtcGxlXG4gICAgICAgICAqICAgICBjcy5yZW1vdmUoJ3BlcnNvbicpO1xuICAgICAgICAgKi9cbiAgICAgICAgcmVtb3ZlOiBmdW5jdGlvbiAoa2V5LCBvcHRpb25zKSB7XG4gICAgICAgICAgICB2YXIgcmVtT3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LCB0aGlzLnNlcnZpY2VPcHRpb25zLCBvcHRpb25zKTtcblxuICAgICAgICAgICAgdmFyIGRvbWFpbiA9IHJlbU9wdGlvbnMuZG9tYWluO1xuICAgICAgICAgICAgdmFyIHBhdGggPSByZW1PcHRpb25zLnJvb3Q7XG4gICAgICAgICAgICB2YXIgY29va2llID0gcmVtT3B0aW9ucy5jb29raWU7XG5cbiAgICAgICAgICAgIGNvb2tpZS5zZXQoZW5jb2RlVVJJQ29tcG9uZW50KGtleSkgK1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICc9OyBleHBpcmVzPVRodSwgMDEgSmFuIDE5NzAgMDA6MDA6MDAgR01UJyArXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgKGRvbWFpbiA/ICc7IGRvbWFpbj0nICsgZG9tYWluIDogJycpICtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAocGF0aCA/ICc7IHBhdGg9JyArIHBhdGggOiAnJylcbiAgICAgICAgICAgICk7XG4gICAgICAgICAgICByZXR1cm4ga2V5O1xuICAgICAgICB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBSZW1vdmVzIGNvbGxlY3Rpb24gYmVpbmcgcmVmZXJlbmNlZFxuICAgICAgICAgKiBAcmV0dXJuIHsgYXJyYXl9IGtleXMgQWxsIHRoZSBrZXlzIHJlbW92ZWRcbiAgICAgICAgICovXG4gICAgICAgIGRlc3Ryb3k6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIHZhciBjb29raWUgPSB0aGlzLnNlcnZpY2VPcHRpb25zLmNvb2tpZTtcbiAgICAgICAgICAgIHZhciBhS2V5cyA9IGNvb2tpZS5nZXQoKS5yZXBsYWNlKC8oKD86XnxcXHMqOylbXlxcPV0rKSg/PTt8JCl8Xlxccyp8XFxzKig/OlxcPVteO10qKT8oPzpcXDF8JCkvZywgJycpLnNwbGl0KC9cXHMqKD86XFw9W147XSopPztcXHMqLyk7XG4gICAgICAgICAgICBmb3IgKHZhciBuSWR4ID0gMDsgbklkeCA8IGFLZXlzLmxlbmd0aDsgbklkeCsrKSB7XG4gICAgICAgICAgICAgICAgdmFyIGNvb2tpZUtleSA9IGRlY29kZVVSSUNvbXBvbmVudChhS2V5c1tuSWR4XSk7XG4gICAgICAgICAgICAgICAgdGhpcy5yZW1vdmUoY29va2llS2V5KTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHJldHVybiBhS2V5cztcbiAgICAgICAgfVxuICAgIH07XG5cbiAgICAkLmV4dGVuZCh0aGlzLCBwdWJsaWNBUEkpO1xufTtcbiIsIid1c2Ugc3RyaWN0JztcblxudmFyIGtleU5hbWVzID0gcmVxdWlyZSgnLi4vbWFuYWdlcnMva2V5LW5hbWVzJyk7XG52YXIgU3RvcmFnZUZhY3RvcnkgPSByZXF1aXJlKCcuL3N0b3JlLWZhY3RvcnknKTtcbnZhciBvcHRpb25VdGlscyA9IHJlcXVpcmUoJy4uL3V0aWwvb3B0aW9uLXV0aWxzJyk7XG5cbnZhciBFUElfU0VTU0lPTl9LRVkgPSBrZXlOYW1lcy5FUElfU0VTU0lPTl9LRVk7XG52YXIgRVBJX01BTkFHRVJfS0VZID0gJ2VwaWNlbnRlci50b2tlbic7IC8vY2FuJ3QgYmUgdW5kZXIga2V5LW5hbWVzLCBvciBsb2dvdXQgd2lsbCBjbGVhciB0aGlzIHRvb1xuXG52YXIgZGVmYXVsdHMgPSB7XG4gICAgLyoqXG4gICAgICogV2hlcmUgdG8gc3RvcmUgdXNlciBhY2Nlc3MgdG9rZW5zIGZvciB0ZW1wb3JhcnkgYWNjZXNzLiBEZWZhdWx0cyB0byBzdG9yaW5nIGluIGEgY29va2llIGluIHRoZSBicm93c2VyLlxuICAgICAqIEB0eXBlIHtzdHJpbmd9XG4gICAgICovXG4gICAgc3RvcmU6IHsgc3luY2hyb25vdXM6IHRydWUgfVxufTtcblxudmFyIFNlc3Npb25NYW5hZ2VyID0gZnVuY3Rpb24gKG1hbmFnZXJPcHRpb25zKSB7XG4gICAgbWFuYWdlck9wdGlvbnMgPSBtYW5hZ2VyT3B0aW9ucyB8fCB7fTtcbiAgICBmdW5jdGlvbiBnZXRCYXNlT3B0aW9ucyhvdmVycmlkZXMpIHtcbiAgICAgICAgb3ZlcnJpZGVzID0gb3ZlcnJpZGVzIHx8IHt9O1xuICAgICAgICB2YXIgbGliT3B0aW9ucyA9IG9wdGlvblV0aWxzLmdldE9wdGlvbnMoKTtcbiAgICAgICAgdmFyIGZpbmFsT3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LCBkZWZhdWx0cywgbGliT3B0aW9ucywgbWFuYWdlck9wdGlvbnMsIG92ZXJyaWRlcyk7XG4gICAgICAgIHJldHVybiBmaW5hbE9wdGlvbnM7XG4gICAgfVxuXG4gICAgZnVuY3Rpb24gZ2V0U3RvcmUob3ZlcnJpZGVzKSB7XG4gICAgICAgIHZhciBiYXNlT3B0aW9ucyA9IGdldEJhc2VPcHRpb25zKG92ZXJyaWRlcyk7XG4gICAgICAgIHZhciBzdG9yZU9wdHMgPSBiYXNlT3B0aW9ucy5zdG9yZSB8fCB7fTtcbiAgICAgICAgdmFyIGlzRXBpY2VudGVyRG9tYWluID0gIWJhc2VPcHRpb25zLmlzTG9jYWwgJiYgIWJhc2VPcHRpb25zLmlzQ3VzdG9tRG9tYWluO1xuICAgICAgICBpZiAoc3RvcmVPcHRzLnJvb3QgPT09IHVuZGVmaW5lZCAmJiBiYXNlT3B0aW9ucy5hY2NvdW50ICYmIGJhc2VPcHRpb25zLnByb2plY3QgJiYgaXNFcGljZW50ZXJEb21haW4pIHtcbiAgICAgICAgICAgIHN0b3JlT3B0cy5yb290ID0gJy9hcHAvJyArIGJhc2VPcHRpb25zLmFjY291bnQgKyAnLycgKyBiYXNlT3B0aW9ucy5wcm9qZWN0O1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiBuZXcgU3RvcmFnZUZhY3Rvcnkoc3RvcmVPcHRzKTtcbiAgICB9XG5cbiAgICB2YXIgcHVibGljQVBJID0ge1xuICAgICAgICBzYXZlU2Vzc2lvbjogZnVuY3Rpb24gKHVzZXJJbmZvLCBvcHRpb25zKSB7XG4gICAgICAgICAgICB2YXIgc2VyaWFsaXplZCA9IEpTT04uc3RyaW5naWZ5KHVzZXJJbmZvKTtcbiAgICAgICAgICAgIGdldFN0b3JlKG9wdGlvbnMpLnNldChFUElfU0VTU0lPTl9LRVksIHNlcmlhbGl6ZWQpO1xuICAgICAgICB9LFxuICAgICAgICBnZXRTZXNzaW9uOiBmdW5jdGlvbiAob3B0aW9ucykge1xuICAgICAgICAgICAgdmFyIHN0b3JlID0gZ2V0U3RvcmUob3B0aW9ucyk7XG4gICAgICAgICAgICB2YXIgZmluYWxPcHRzID0gc3RvcmUuc2VydmljZU9wdGlvbnM7XG4gICAgICAgICAgICB2YXIgc2VyaWFsaXplZCA9IHN0b3JlLmdldChFUElfU0VTU0lPTl9LRVkpIHx8ICd7fSc7XG4gICAgICAgICAgICB2YXIgc2Vzc2lvbiA9IEpTT04ucGFyc2Uoc2VyaWFsaXplZCk7XG4gICAgICAgICAgICAvLyBJZiB0aGUgdXJsIGNvbnRhaW5zIHRoZSBwcm9qZWN0IGFuZCBhY2NvdW50XG4gICAgICAgICAgICAvLyB2YWxpZGF0ZSB0aGUgYWNjb3VudCBhbmQgcHJvamVjdCBpbiB0aGUgc2Vzc2lvblxuICAgICAgICAgICAgLy8gYW5kIG92ZXJyaWRlIHByb2plY3QsIGdyb3VwTmFtZSwgZ3JvdXBJZCBhbmQgaXNGYWNcbiAgICAgICAgICAgIC8vIE90aGVyd2lzZSAoaS5lLiBsb2NhbGhvc3QpIHVzZSB0aGUgc2F2ZWQgc2Vzc2lvbiB2YWx1ZXNcbiAgICAgICAgICAgIHZhciBhY2NvdW50ID0gZmluYWxPcHRzLmFjY291bnQ7XG4gICAgICAgICAgICB2YXIgcHJvamVjdCA9IGZpbmFsT3B0cy5wcm9qZWN0O1xuICAgICAgICAgICAgaWYgKGFjY291bnQgJiYgc2Vzc2lvbi5hY2NvdW50ICE9PSBhY2NvdW50KSB7XG4gICAgICAgICAgICAgICAgLy8gVGhpcyBtZWFucyB0aGF0IHRoZSB0b2tlbiB3YXMgbm90IHVzZWQgdG8gbG9naW4gdG8gdGhlIHNhbWUgYWNjb3VudFxuICAgICAgICAgICAgICAgIHJldHVybiB7fTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGlmIChzZXNzaW9uLmdyb3VwcyAmJiBhY2NvdW50ICYmIHByb2plY3QpIHtcbiAgICAgICAgICAgICAgICB2YXIgZ3JvdXAgPSBzZXNzaW9uLmdyb3Vwc1twcm9qZWN0XSB8fCB7IGdyb3VwSWQ6ICcnLCBncm91cE5hbWU6ICcnLCBpc0ZhYzogZmFsc2UgfTtcbiAgICAgICAgICAgICAgICAkLmV4dGVuZChzZXNzaW9uLCB7IHByb2plY3Q6IHByb2plY3QgfSwgZ3JvdXApO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgcmV0dXJuIHNlc3Npb247XG4gICAgICAgIH0sXG4gICAgICAgIHJlbW92ZVNlc3Npb246IGZ1bmN0aW9uIChvcHRpb25zKSB7XG4gICAgICAgICAgICB2YXIgc3RvcmUgPSBnZXRTdG9yZShvcHRpb25zKTtcbiAgICAgICAgICAgIE9iamVjdC5rZXlzKGtleU5hbWVzKS5mb3JFYWNoKGZ1bmN0aW9uIChjb29raWVLZXkpIHtcbiAgICAgICAgICAgICAgICB2YXIgY29va2llTmFtZSA9IGtleU5hbWVzW2Nvb2tpZUtleV07XG4gICAgICAgICAgICAgICAgc3RvcmUucmVtb3ZlKGNvb2tpZU5hbWUpO1xuICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICByZXR1cm4gdHJ1ZTtcbiAgICAgICAgfSxcbiAgICAgICAgZ2V0U3RvcmU6IGZ1bmN0aW9uIChvcHRpb25zKSB7XG4gICAgICAgICAgICByZXR1cm4gZ2V0U3RvcmUob3B0aW9ucyk7XG4gICAgICAgIH0sXG5cbiAgICAgICAgZ2V0TWVyZ2VkT3B0aW9uczogZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgdmFyIGFyZ3MgPSBBcnJheS5wcm90b3R5cGUuc2xpY2UuY2FsbChhcmd1bWVudHMpO1xuICAgICAgICAgICAgdmFyIG92ZXJyaWRlcyA9ICQuZXh0ZW5kLmFwcGx5KCQsIFt0cnVlLCB7fV0uY29uY2F0KGFyZ3MpKTtcbiAgICAgICAgICAgIHZhciBiYXNlT3B0aW9ucyA9IGdldEJhc2VPcHRpb25zKG92ZXJyaWRlcyk7XG4gICAgICAgICAgICB2YXIgc2Vzc2lvbiA9IHRoaXMuZ2V0U2Vzc2lvbihvdmVycmlkZXMpO1xuXG4gICAgICAgICAgICB2YXIgdG9rZW4gPSBzZXNzaW9uLmF1dGhfdG9rZW47XG4gICAgICAgICAgICBpZiAoIXRva2VuKSB7XG4gICAgICAgICAgICAgICAgdmFyIGZhY3RvcnkgPSBuZXcgU3RvcmFnZUZhY3RvcnkoKTtcbiAgICAgICAgICAgICAgICB0b2tlbiA9IGZhY3RvcnkuZ2V0KEVQSV9NQU5BR0VSX0tFWSk7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIHZhciBzZXNzaW9uRGVmYXVsdHMgPSB7XG4gICAgICAgICAgICAgICAgLyoqXG4gICAgICAgICAgICAgICAgICogRm9yIHByb2plY3RzIHRoYXQgcmVxdWlyZSBhdXRoZW50aWNhdGlvbiwgcGFzcyBpbiB0aGUgdXNlciBhY2Nlc3MgdG9rZW4gKGRlZmF1bHRzIHRvIGVtcHR5IHN0cmluZykuIElmIHRoZSB1c2VyIGlzIGFscmVhZHkgbG9nZ2VkIGluIHRvIEVwaWNlbnRlciwgdGhlIHVzZXIgYWNjZXNzIHRva2VuIGlzIGFscmVhZHkgc2V0IGluIGEgY29va2llIGFuZCBhdXRvbWF0aWNhbGx5IGxvYWRlZCBmcm9tIHRoZXJlLiAoU2VlIFttb3JlIGJhY2tncm91bmQgb24gYWNjZXNzIHRva2Vuc10oLi4vLi4vLi4vcHJvamVjdF9hY2Nlc3MvKSkuXG4gICAgICAgICAgICAgICAgICogQHNlZSBbQXV0aGVudGljYXRpb24gQVBJIFNlcnZpY2VdKC4uL2F1dGgtYXBpLXNlcnZpY2UvKSBmb3IgZ2V0dGluZyB0b2tlbnMuXG4gICAgICAgICAgICAgICAgICogQHR5cGUge1N0cmluZ31cbiAgICAgICAgICAgICAgICAgKi9cbiAgICAgICAgICAgICAgICB0b2tlbjogdG9rZW4sXG5cbiAgICAgICAgICAgICAgICAvKipcbiAgICAgICAgICAgICAgICAgKiBUaGUgYWNjb3VudC4gSWYgbGVmdCB1bmRlZmluZWQsIHRha2VuIGZyb20gdGhlIGNvb2tpZSBzZXNzaW9uLlxuICAgICAgICAgICAgICAgICAqIEB0eXBlIHtTdHJpbmd9XG4gICAgICAgICAgICAgICAgICovXG4gICAgICAgICAgICAgICAgYWNjb3VudDogc2Vzc2lvbi5hY2NvdW50LFxuXG4gICAgICAgICAgICAgICAgLyoqXG4gICAgICAgICAgICAgICAgICogVGhlIHByb2plY3QuIElmIGxlZnQgdW5kZWZpbmVkLCB0YWtlbiBmcm9tIHRoZSBjb29raWUgc2Vzc2lvbi5cbiAgICAgICAgICAgICAgICAgKiBAdHlwZSB7U3RyaW5nfVxuICAgICAgICAgICAgICAgICAqL1xuICAgICAgICAgICAgICAgIHByb2plY3Q6IHNlc3Npb24ucHJvamVjdCxcblxuXG4gICAgICAgICAgICAgICAgLyoqXG4gICAgICAgICAgICAgICAgICogVGhlIGdyb3VwIG5hbWUuIElmIGxlZnQgdW5kZWZpbmVkLCB0YWtlbiBmcm9tIHRoZSBjb29raWUgc2Vzc2lvbi5cbiAgICAgICAgICAgICAgICAgKiBAdHlwZSB7U3RyaW5nfVxuICAgICAgICAgICAgICAgICAqL1xuICAgICAgICAgICAgICAgIGdyb3VwOiBzZXNzaW9uLmdyb3VwTmFtZSxcbiAgICAgICAgICAgICAgICAvKipcbiAgICAgICAgICAgICAgICAgKiBBbGlhcyBmb3IgZ3JvdXAuIFxuICAgICAgICAgICAgICAgICAqIEB0eXBlIHtTdHJpbmd9XG4gICAgICAgICAgICAgICAgICovXG4gICAgICAgICAgICAgICAgZ3JvdXBOYW1lOiBzZXNzaW9uLmdyb3VwTmFtZSwgLy9JdCdzIGEgbGl0dGxlIHdlaXJkIHRoYXQgaXQncyBjYWxsZWQgZ3JvdXBOYW1lIGluIHRoZSBjb29raWUsIGJ1dCAnZ3JvdXAnIGluIGFsbCB0aGUgc2VydmljZSBvcHRpb25zLCBzbyBub3JtYWxpemUgZm9yIGJvdGhcbiAgICAgICAgICAgICAgICAvKipcbiAgICAgICAgICAgICAgICAgKiBUaGUgZ3JvdXAgaWQuIElmIGxlZnQgdW5kZWZpbmVkLCB0YWtlbiBmcm9tIHRoZSBjb29raWUgc2Vzc2lvbi5cbiAgICAgICAgICAgICAgICAgKiBAdHlwZSB7U3RyaW5nfVxuICAgICAgICAgICAgICAgICAqL1xuICAgICAgICAgICAgICAgIGdyb3VwSWQ6IHNlc3Npb24uZ3JvdXBJZCxcbiAgICAgICAgICAgICAgICB1c2VySWQ6IHNlc3Npb24udXNlcklkLFxuICAgICAgICAgICAgICAgIHVzZXJOYW1lOiBzZXNzaW9uLnVzZXJOYW1lLFxuICAgICAgICAgICAgfTtcbiAgICAgICAgICAgIHJldHVybiAkLmV4dGVuZCh0cnVlLCBzZXNzaW9uRGVmYXVsdHMsIGJhc2VPcHRpb25zKTtcbiAgICAgICAgfVxuICAgIH07XG4gICAgJC5leHRlbmQodGhpcywgcHVibGljQVBJKTtcbn07XG5cbm1vZHVsZS5leHBvcnRzID0gU2Vzc2lvbk1hbmFnZXI7IiwiLyoqXG4gICAgRGVjaWRlcyB0eXBlIG9mIHN0b3JlIHRvIHByb3ZpZGVcbiovXG5cbid1c2Ugc3RyaWN0Jztcbi8vIHZhciBpc05vZGUgPSBmYWxzZTsgRklYTUU6IEJyb3dzZXJpZnkvbWluaWZ5aWZ5IGhhcyBpc3N1ZXMgd2l0aCB0aGUgbmV4dCBsaW5rXG4vLyB2YXIgc3RvcmUgPSAoaXNOb2RlKSA/IHJlcXVpcmUoJy4vc2Vzc2lvbi1zdG9yZScpIDogcmVxdWlyZSgnLi9jb29raWUtc3RvcmUnKTtcbnZhciBzdG9yZSA9IHJlcXVpcmUoJy4vY29va2llLXN0b3JlJyk7XG5cbm1vZHVsZS5leHBvcnRzID0gc3RvcmU7XG4iLCIndXNlIHN0cmljdCc7XG5cbnZhciBxdXRpbHMgPSByZXF1aXJlKCcuLi91dGlsL3F1ZXJ5LXV0aWwnKTtcblxubW9kdWxlLmV4cG9ydHMgPSBmdW5jdGlvbiAoY29uZmlnKSB7XG5cbiAgICB2YXIgZGVmYXVsdHMgPSB7XG4gICAgICAgIHVybDogJycsXG5cbiAgICAgICAgY29udGVudFR5cGU6ICdhcHBsaWNhdGlvbi9qc29uJyxcbiAgICAgICAgaGVhZGVyczoge30sXG4gICAgICAgIHN0YXR1c0NvZGU6IHtcbiAgICAgICAgICAgIDQwNDogJC5ub29wXG4gICAgICAgIH0sXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIE9OTFkgZm9yIHN0cmluZ3MgaW4gdGhlIHVybC4gQWxsIEdFVCAmIERFTEVURSBwYXJhbXMgYXJlIHJ1biB0aHJvdWdoIHRoaXNcbiAgICAgICAgICogQHR5cGUge1t0eXBlXSB9XG4gICAgICAgICAqL1xuICAgICAgICBwYXJhbWV0ZXJQYXJzZXI6IHF1dGlscy50b1F1ZXJ5Rm9ybWF0LFxuXG4gICAgICAgIC8vIFRvIGFsbG93IGVwaWNlbnRlci50b2tlbiBhbmQgb3RoZXIgc2Vzc2lvbiBjb29raWVzIHRvIGJlIHBhc3NlZFxuICAgICAgICAvLyB3aXRoIHRoZSByZXF1ZXN0c1xuICAgICAgICB4aHJGaWVsZHM6IHtcbiAgICAgICAgICAgIHdpdGhDcmVkZW50aWFsczogdHJ1ZVxuICAgICAgICB9XG4gICAgfTtcblxuICAgIHZhciB0cmFuc3BvcnRPcHRpb25zID0gJC5leHRlbmQoe30sIGRlZmF1bHRzLCBjb25maWcpO1xuXG4gICAgdmFyIHJlc3VsdCA9IGZ1bmN0aW9uIChkKSB7XG4gICAgICAgIHJldHVybiAoJC5pc0Z1bmN0aW9uKGQpKSA/IGQoKSA6IGQ7XG4gICAgfTtcblxuICAgIHZhciBjb25uZWN0ID0gZnVuY3Rpb24gKG1ldGhvZCwgcGFyYW1zLCBjb25uZWN0T3B0aW9ucykge1xuICAgICAgICBwYXJhbXMgPSByZXN1bHQocGFyYW1zKTtcbiAgICAgICAgcGFyYW1zID0gKCQuaXNQbGFpbk9iamVjdChwYXJhbXMpIHx8ICQuaXNBcnJheShwYXJhbXMpKSA/IEpTT04uc3RyaW5naWZ5KHBhcmFtcykgOiBwYXJhbXM7XG5cbiAgICAgICAgdmFyIG9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSwgdHJhbnNwb3J0T3B0aW9ucywgY29ubmVjdE9wdGlvbnMsIHtcbiAgICAgICAgICAgIHR5cGU6IG1ldGhvZCxcbiAgICAgICAgICAgIGRhdGE6IHBhcmFtc1xuICAgICAgICB9KTtcbiAgICAgICAgdmFyIEFMTE9XRURfVE9fQkVfRlVOQ1RJT05TID0gWydkYXRhJywgJ3VybCddO1xuICAgICAgICAkLmVhY2gob3B0aW9ucywgZnVuY3Rpb24gKGtleSwgdmFsdWUpIHtcbiAgICAgICAgICAgIGlmICgkLmlzRnVuY3Rpb24odmFsdWUpICYmICQuaW5BcnJheShrZXksIEFMTE9XRURfVE9fQkVfRlVOQ1RJT05TKSAhPT0gLTEpIHtcbiAgICAgICAgICAgICAgICBvcHRpb25zW2tleV0gPSB2YWx1ZSgpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9KTtcblxuICAgICAgICBpZiAob3B0aW9ucy5sb2dMZXZlbCAmJiBvcHRpb25zLmxvZ0xldmVsID09PSAnREVCVUcnKSB7XG4gICAgICAgICAgICBjb25zb2xlLmxvZyhvcHRpb25zLnVybCk7XG4gICAgICAgICAgICB2YXIgb2xkU3VjY2Vzc0ZuID0gb3B0aW9ucy5zdWNjZXNzIHx8ICQubm9vcDtcbiAgICAgICAgICAgIG9wdGlvbnMuc3VjY2VzcyA9IGZ1bmN0aW9uIChyZXNwb25zZSwgYWpheFN0YXR1cywgYWpheFJlcSkge1xuICAgICAgICAgICAgICAgIGNvbnNvbGUubG9nKHJlc3BvbnNlKTtcbiAgICAgICAgICAgICAgICBvbGRTdWNjZXNzRm4uYXBwbHkodGhpcywgYXJndW1lbnRzKTtcbiAgICAgICAgICAgIH07XG4gICAgICAgIH1cblxuICAgICAgICB2YXIgYmVmb3JlU2VuZCA9IG9wdGlvbnMuYmVmb3JlU2VuZDtcbiAgICAgICAgb3B0aW9ucy5iZWZvcmVTZW5kID0gZnVuY3Rpb24gKHhociwgc2V0dGluZ3MpIHtcbiAgICAgICAgICAgIHhoci5yZXF1ZXN0VXJsID0gKGNvbm5lY3RPcHRpb25zIHx8IHt9KS51cmw7XG4gICAgICAgICAgICBpZiAoYmVmb3JlU2VuZCkge1xuICAgICAgICAgICAgICAgIGJlZm9yZVNlbmQuYXBwbHkodGhpcywgYXJndW1lbnRzKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfTtcblxuICAgICAgICByZXR1cm4gJC5hamF4KG9wdGlvbnMpO1xuICAgIH07XG5cbiAgICB2YXIgcHVibGljQVBJID0ge1xuICAgICAgICBnZXQ6IGZ1bmN0aW9uIChwYXJhbXMsIGFqYXhPcHRpb25zKSB7XG4gICAgICAgICAgICB2YXIgb3B0aW9ucyA9ICQuZXh0ZW5kKHt9LCB0cmFuc3BvcnRPcHRpb25zLCBhamF4T3B0aW9ucyk7XG4gICAgICAgICAgICBwYXJhbXMgPSBvcHRpb25zLnBhcmFtZXRlclBhcnNlcihyZXN1bHQocGFyYW1zKSk7XG4gICAgICAgICAgICByZXR1cm4gY29ubmVjdC5jYWxsKHRoaXMsICdHRVQnLCBwYXJhbXMsIG9wdGlvbnMpO1xuICAgICAgICB9LFxuICAgICAgICBzcGxpdEdldDogZnVuY3Rpb24gKCkge1xuXG4gICAgICAgIH0sXG4gICAgICAgIHBvc3Q6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIHJldHVybiBjb25uZWN0LmFwcGx5KHRoaXMsIFsncG9zdCddLmNvbmNhdChbXS5zbGljZS5jYWxsKGFyZ3VtZW50cykpKTtcbiAgICAgICAgfSxcbiAgICAgICAgcGF0Y2g6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIHJldHVybiBjb25uZWN0LmFwcGx5KHRoaXMsIFsncGF0Y2gnXS5jb25jYXQoW10uc2xpY2UuY2FsbChhcmd1bWVudHMpKSk7XG4gICAgICAgIH0sXG4gICAgICAgIHB1dDogZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgcmV0dXJuIGNvbm5lY3QuYXBwbHkodGhpcywgWydwdXQnXS5jb25jYXQoW10uc2xpY2UuY2FsbChhcmd1bWVudHMpKSk7XG4gICAgICAgIH0sXG4gICAgICAgIGRlbGV0ZTogZnVuY3Rpb24gKHBhcmFtcywgYWpheE9wdGlvbnMpIHtcbiAgICAgICAgICAgIC8vREVMRVRFIGRvZXNuJ3Qgc3VwcG9ydCBib2R5IHBhcmFtcywgYnV0IGpRdWVyeSB0aGlua3MgaXQgZG9lcy5cbiAgICAgICAgICAgIHZhciBvcHRpb25zID0gJC5leHRlbmQoe30sIHRyYW5zcG9ydE9wdGlvbnMsIGFqYXhPcHRpb25zKTtcbiAgICAgICAgICAgIHBhcmFtcyA9IG9wdGlvbnMucGFyYW1ldGVyUGFyc2VyKHJlc3VsdChwYXJhbXMpKTtcbiAgICAgICAgICAgIGlmICgkLnRyaW0ocGFyYW1zKSkge1xuICAgICAgICAgICAgICAgIHZhciBkZWxpbWl0ZXIgPSAocmVzdWx0KG9wdGlvbnMudXJsKS5pbmRleE9mKCc/JykgPT09IC0xKSA/ICc/JyA6ICcmJztcbiAgICAgICAgICAgICAgICBvcHRpb25zLnVybCA9IHJlc3VsdChvcHRpb25zLnVybCkgKyBkZWxpbWl0ZXIgKyBwYXJhbXM7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICByZXR1cm4gY29ubmVjdC5jYWxsKHRoaXMsICdERUxFVEUnLCBudWxsLCBvcHRpb25zKTtcbiAgICAgICAgfSxcbiAgICAgICAgaGVhZDogZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgcmV0dXJuIGNvbm5lY3QuYXBwbHkodGhpcywgWydoZWFkJ10uY29uY2F0KFtdLnNsaWNlLmNhbGwoYXJndW1lbnRzKSkpO1xuICAgICAgICB9LFxuICAgICAgICBvcHRpb25zOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICByZXR1cm4gY29ubmVjdC5hcHBseSh0aGlzLCBbJ29wdGlvbnMnXS5jb25jYXQoW10uc2xpY2UuY2FsbChhcmd1bWVudHMpKSk7XG4gICAgICAgIH1cbiAgICB9O1xuXG4gICAgcmV0dXJuICQuZXh0ZW5kKHRoaXMsIHB1YmxpY0FQSSk7XG59O1xuIiwiJ3VzZSBzdHJpY3QnO1xuXG4vLyB2YXIgaXNOb2RlID0gZmFsc2U7IEZJWE1FOiBCcm93c2VyaWZ5L21pbmlmeWlmeSBoYXMgaXNzdWVzIHdpdGggdGhlIG5leHQgbGlua1xuLy8gdmFyIHRyYW5zcG9ydCA9IChpc05vZGUpID8gcmVxdWlyZSgnLi9ub2RlLWh0dHAtdHJhbnNwb3J0JykgOiByZXF1aXJlKCcuL2FqYXgtaHR0cC10cmFuc3BvcnQnKTtcbnZhciB0cmFuc3BvcnQgPSByZXF1aXJlKCcuL2FqYXgtaHR0cC10cmFuc3BvcnQnKTtcbm1vZHVsZS5leHBvcnRzID0gdHJhbnNwb3J0O1xuIiwiLyoqXG4vKiBJbmhlcml0IGZyb20gYSBjbGFzcyAodXNpbmcgcHJvdG90eXBlIGJvcnJvd2luZylcbiovXG4ndXNlIHN0cmljdCc7XG5cbmZ1bmN0aW9uIGluaGVyaXQoQywgUCkge1xuICAgIHZhciBGID0gZnVuY3Rpb24gKCkge307XG4gICAgRi5wcm90b3R5cGUgPSBQLnByb3RvdHlwZTtcbiAgICBDLnByb3RvdHlwZSA9IG5ldyBGKCk7XG4gICAgQy5fX3N1cGVyID0gUC5wcm90b3R5cGU7XG4gICAgQy5wcm90b3R5cGUuY29uc3RydWN0b3IgPSBDO1xufVxuXG4vKipcbiogU2hhbGxvdyBjb3B5IG9mIGFuIG9iamVjdFxuKiBAcGFyYW0ge09iamVjdH0gZGVzdCBvYmplY3QgdG8gZXh0ZW5kXG4qIEByZXR1cm4ge09iamVjdH0gZXh0ZW5kZWQgb2JqZWN0XG4qL1xudmFyIGV4dGVuZCA9IGZ1bmN0aW9uIChkZXN0IC8qLCB2YXJfYXJncyovKSB7XG4gICAgdmFyIG9iaiA9IEFycmF5LnByb3RvdHlwZS5zbGljZS5jYWxsKGFyZ3VtZW50cywgMSk7XG4gICAgdmFyIGN1cnJlbnQ7XG4gICAgZm9yICh2YXIgaiA9IDA7IGogPCBvYmoubGVuZ3RoOyBqKyspIHtcbiAgICAgICAgaWYgKCEoY3VycmVudCA9IG9ialtqXSkpIHsgLy9lc2xpbnQtZGlzYWJsZS1saW5lXG4gICAgICAgICAgICBjb250aW51ZTtcbiAgICAgICAgfVxuXG4gICAgICAgIC8vIGRvIG5vdCB3cmFwIGlubmVyIGluIGRlc3QuaGFzT3duUHJvcGVydHkgb3IgYmFkIHRoaW5ncyB3aWxsIGhhcHBlblxuICAgICAgICBmb3IgKHZhciBrZXkgaW4gY3VycmVudCkgeyAvL2VzbGludC1kaXNhYmxlLWxpbmVcbiAgICAgICAgICAgIGRlc3Rba2V5XSA9IGN1cnJlbnRba2V5XTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIHJldHVybiBkZXN0O1xufTtcblxubW9kdWxlLmV4cG9ydHMgPSBmdW5jdGlvbiAoYmFzZSwgcHJvcHMsIHN0YXRpY1Byb3BzKSB7XG4gICAgdmFyIHBhcmVudCA9IGJhc2U7XG4gICAgdmFyIGNoaWxkO1xuXG4gICAgY2hpbGQgPSBwcm9wcyAmJiBwcm9wcy5oYXNPd25Qcm9wZXJ0eSgnY29uc3RydWN0b3InKSA/IHByb3BzLmNvbnN0cnVjdG9yIDogZnVuY3Rpb24gKCkgeyByZXR1cm4gcGFyZW50LmFwcGx5KHRoaXMsIGFyZ3VtZW50cyk7IH07XG5cbiAgICAvLyBhZGQgc3RhdGljIHByb3BlcnRpZXMgdG8gdGhlIGNoaWxkIGNvbnN0cnVjdG9yIGZ1bmN0aW9uXG4gICAgZXh0ZW5kKGNoaWxkLCBwYXJlbnQsIHN0YXRpY1Byb3BzKTtcblxuICAgIC8vIGFzc29jaWF0ZSBwcm90b3R5cGUgY2hhaW5cbiAgICBpbmhlcml0KGNoaWxkLCBwYXJlbnQpO1xuXG4gICAgLy8gYWRkIGluc3RhbmNlIHByb3BlcnRpZXNcbiAgICBpZiAocHJvcHMpIHtcbiAgICAgICAgZXh0ZW5kKGNoaWxkLnByb3RvdHlwZSwgcHJvcHMpO1xuICAgIH1cblxuICAgIC8vIGRvbmVcbiAgICByZXR1cm4gY2hpbGQ7XG59O1xuIiwiJ3VzZSBzdHJpY3QnO1xuXG5tb2R1bGUuZXhwb3J0cyA9IHtcbiAgICBfcGljazogZnVuY3Rpb24gKG9iaiwgcHJvcHMpIHtcbiAgICAgICAgdmFyIHJlcyA9IHt9O1xuICAgICAgICBmb3IgKHZhciBwIGluIG9iaikge1xuICAgICAgICAgICAgaWYgKHByb3BzLmluZGV4T2YocCkgIT09IC0xKSB7XG4gICAgICAgICAgICAgICAgcmVzW3BdID0gb2JqW3BdO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIHJlcztcbiAgICB9LFxuICAgIGlzRW1wdHk6IGZ1bmN0aW9uIGlzRW1wdHkodmFsdWUpIHtcbiAgICAgICAgcmV0dXJuICghdmFsdWUgfHwgKCQuaXNQbGFpbk9iamVjdCh2YWx1ZSkgJiYgT2JqZWN0LmtleXModmFsdWUpLmxlbmd0aCA9PT0gMCkpO1xuICAgIH1cbn07XG4iLCIndXNlIHN0cmljdCc7XG5cbnZhciBDb25maWdTZXJ2aWNlID0gcmVxdWlyZSgnLi4vc2VydmljZS9jb25maWd1cmF0aW9uLXNlcnZpY2UnKTtcblxudmFyIHVybENvbmZpZyA9IG5ldyBDb25maWdTZXJ2aWNlKCkuZ2V0KCdzZXJ2ZXInKTtcbnZhciBjdXN0b21EZWZhdWx0cyA9IHt9O1xudmFyIGxpYkRlZmF1bHRzID0ge1xuICAgIC8qKlxuICAgICAqIFRoZSBhY2NvdW50IGlkLiBJbiB0aGUgRXBpY2VudGVyIFVJLCB0aGlzIGlzIHRoZSAqKlRlYW0gSUQqKiAoZm9yIHRlYW0gcHJvamVjdHMpIG9yICoqVXNlciBJRCoqIChmb3IgcGVyc29uYWwgcHJvamVjdHMpLiBEZWZhdWx0cyB0byBlbXB0eSBzdHJpbmcuIElmIGxlZnQgdW5kZWZpbmVkLCB0YWtlbiBmcm9tIHRoZSBVUkwuXG4gICAgICogQHR5cGUge1N0cmluZ31cbiAgICAgKi9cbiAgICBhY2NvdW50OiB1cmxDb25maWcuYWNjb3VudFBhdGggfHwgdW5kZWZpbmVkLFxuICAgIC8qKlxuICAgICAqIFRoZSBhY2NvdW50IGlkLiBJbiB0aGUgRXBpY2VudGVyIFVJLCB0aGlzIGlzIHRoZSAqKlRlYW0gSUQqKiAoZm9yIHRlYW0gcHJvamVjdHMpIG9yICoqVXNlciBJRCoqIChmb3IgcGVyc29uYWwgcHJvamVjdHMpLiBEZWZhdWx0cyB0byBlbXB0eSBzdHJpbmcuIElmIGxlZnQgdW5kZWZpbmVkLCB0YWtlbiBmcm9tIHRoZSBVUkwuXG4gICAgICogQHR5cGUge1N0cmluZ31cbiAgICAgKi9cbiAgICBwcm9qZWN0OiB1cmxDb25maWcucHJvamVjdFBhdGggfHwgdW5kZWZpbmVkLFxuICAgIGlzTG9jYWw6IHVybENvbmZpZy5pc0xvY2FsaG9zdCgpLFxuICAgIGlzQ3VzdG9tRG9tYWluOiB1cmxDb25maWcuaXNDdXN0b21Eb21haW4sXG4gICAgc3RvcmU6IHt9XG59O1xuXG52YXIgb3B0aW9uVXRpbHMgPSB7XG4gICAgLyoqXG4gICAgICogR2V0cyB0aGUgZmluYWwgb3B0aW9ucyBieSBvdmVycmlkaW5nIHRoZSBnbG9iYWwgb3B0aW9ucyBzZXQgd2l0aFxuICAgICAqIG9wdGlvblV0aWxzI3NldERlZmF1bHRzKCkgYW5kIHRoZSBsaWIgZGVmYXVsdHMuXG4gICAgICogQHBhcmFtIHtvYmplY3R9IG9wdGlvbnMgVGhlIGZpbmFsIG9wdGlvbnMgb2JqZWN0LlxuICAgICAqIEByZXR1cm4ge29iamVjdH0gRXh0ZW5kZWQgb2JqZWN0XG4gICAgICovXG4gICAgZ2V0T3B0aW9uczogZnVuY3Rpb24gKG9wdGlvbnMpIHtcbiAgICAgICAgcmV0dXJuICQuZXh0ZW5kKHRydWUsIHt9LCBsaWJEZWZhdWx0cywgY3VzdG9tRGVmYXVsdHMsIG9wdGlvbnMpO1xuICAgIH0sXG4gICAgLyoqXG4gICAgICogU2V0cyB0aGUgZ2xvYmFsIGRlZmF1bHRzIGZvciB0aGUgb3B0aW9uVXRpbHMjZ2V0T3B0aW9ucygpIG1ldGhvZC5cbiAgICAgKiBAcGFyYW0ge29iamVjdH0gZGVmYXVsdHMgVGhlIGRlZmF1bHRzIG9iamVjdC5cbiAgICAgKi9cbiAgICBzZXREZWZhdWx0czogZnVuY3Rpb24gKGRlZmF1bHRzKSB7XG4gICAgICAgIGN1c3RvbURlZmF1bHRzID0gZGVmYXVsdHM7XG4gICAgfVxufTtcbm1vZHVsZS5leHBvcnRzID0gb3B0aW9uVXRpbHM7XG4iLCIvKipcbiAqIFV0aWxpdGllcyBmb3Igd29ya2luZyB3aXRoIHF1ZXJ5IHN0cmluZ3NcbiovXG4ndXNlIHN0cmljdCc7XG5cbm1vZHVsZS5leHBvcnRzID0gKGZ1bmN0aW9uICgpIHtcblxuICAgIHJldHVybiB7XG4gICAgICAgIC8qKlxuICAgICAgICAgKiBDb252ZXJ0cyB0byBtYXRyaXggZm9ybWF0XG4gICAgICAgICAqIEBwYXJhbSAge09iamVjdH0gcXMgT2JqZWN0IHRvIGNvbnZlcnQgdG8gcXVlcnkgc3RyaW5nXG4gICAgICAgICAqIEByZXR1cm4geyBzdHJpbmd9ICAgIE1hdHJpeC1mb3JtYXQgcXVlcnkgcGFyYW1ldGVyc1xuICAgICAgICAgKi9cbiAgICAgICAgdG9NYXRyaXhGb3JtYXQ6IGZ1bmN0aW9uIChxcykge1xuICAgICAgICAgICAgaWYgKHFzID09PSBudWxsIHx8IHFzID09PSB1bmRlZmluZWQgfHwgcXMgPT09ICcnKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuICc7JztcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGlmICh0eXBlb2YgcXMgPT09ICdzdHJpbmcnIHx8IHFzIGluc3RhbmNlb2YgU3RyaW5nKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIHFzO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICB2YXIgcmV0dXJuQXJyYXkgPSBbXTtcbiAgICAgICAgICAgIHZhciBPUEVSQVRPUlMgPSBbJzwnLCAnPicsICchJ107XG4gICAgICAgICAgICAkLmVhY2gocXMsIGZ1bmN0aW9uIChrZXksIHZhbHVlKSB7XG4gICAgICAgICAgICAgICAgaWYgKHR5cGVvZiB2YWx1ZSAhPT0gJ3N0cmluZycgfHwgJC5pbkFycmF5KCQudHJpbSh2YWx1ZSkuY2hhckF0KDApLCBPUEVSQVRPUlMpID09PSAtMSkge1xuICAgICAgICAgICAgICAgICAgICB2YWx1ZSA9ICc9JyArIHZhbHVlO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICByZXR1cm5BcnJheS5wdXNoKGtleSArIHZhbHVlKTtcbiAgICAgICAgICAgIH0pO1xuXG4gICAgICAgICAgICB2YXIgbXRyeCA9ICc7JyArIHJldHVybkFycmF5LmpvaW4oJzsnKTtcbiAgICAgICAgICAgIHJldHVybiBtdHJ4O1xuICAgICAgICB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBDb252ZXJ0cyBzdHJpbmdzL2FycmF5cy9vYmplY3RzIHRvIHR5cGUgJ2E9YiZiPWMnXG4gICAgICAgICAqIEBwYXJhbSAgeyBzdHJpbmd8QXJyYXl8T2JqZWN0fSBxc1xuICAgICAgICAgKiBAcmV0dXJuIHsgc3RyaW5nfVxuICAgICAgICAgKi9cbiAgICAgICAgdG9RdWVyeUZvcm1hdDogZnVuY3Rpb24gKHFzKSB7XG4gICAgICAgICAgICBpZiAocXMgPT09IG51bGwgfHwgcXMgPT09IHVuZGVmaW5lZCkge1xuICAgICAgICAgICAgICAgIHJldHVybiAnJztcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGlmICh0eXBlb2YgcXMgPT09ICdzdHJpbmcnIHx8IHFzIGluc3RhbmNlb2YgU3RyaW5nKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIHFzO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICB2YXIgcmV0dXJuQXJyYXkgPSBbXTtcbiAgICAgICAgICAgICQuZWFjaChxcywgZnVuY3Rpb24gKGtleSwgdmFsdWUpIHtcbiAgICAgICAgICAgICAgICBpZiAoJC5pc0FycmF5KHZhbHVlKSkge1xuICAgICAgICAgICAgICAgICAgICB2YWx1ZSA9IHZhbHVlLmpvaW4oJywnKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgaWYgKCQuaXNQbGFpbk9iamVjdCh2YWx1ZSkpIHtcbiAgICAgICAgICAgICAgICAgICAgLy9Nb3N0bHkgZm9yIGRhdGEgYXBpXG4gICAgICAgICAgICAgICAgICAgIHZhbHVlID0gSlNPTi5zdHJpbmdpZnkodmFsdWUpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICByZXR1cm5BcnJheS5wdXNoKGtleSArICc9JyArIHZhbHVlKTtcbiAgICAgICAgICAgIH0pO1xuXG4gICAgICAgICAgICB2YXIgcmVzdWx0ID0gcmV0dXJuQXJyYXkuam9pbignJicpO1xuICAgICAgICAgICAgcmV0dXJuIHJlc3VsdDtcbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgICogQ29udmVydHMgc3RyaW5ncyBvZiB0eXBlICdhPWImYj1jJyB0byB7IGE6YiwgYjpjfVxuICAgICAgICAgKiBAcGFyYW0gIHsgc3RyaW5nfSBxc1xuICAgICAgICAgKiBAcmV0dXJuIHtvYmplY3R9XG4gICAgICAgICAqL1xuICAgICAgICBxc1RvT2JqZWN0OiBmdW5jdGlvbiAocXMpIHtcbiAgICAgICAgICAgIGlmIChxcyA9PT0gbnVsbCB8fCBxcyA9PT0gdW5kZWZpbmVkIHx8IHFzID09PSAnJykge1xuICAgICAgICAgICAgICAgIHJldHVybiB7fTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgdmFyIHFzQXJyYXkgPSBxcy5zcGxpdCgnJicpO1xuICAgICAgICAgICAgdmFyIHJldHVybk9iaiA9IHt9O1xuICAgICAgICAgICAgJC5lYWNoKHFzQXJyYXksIGZ1bmN0aW9uIChpbmRleCwgdmFsdWUpIHtcbiAgICAgICAgICAgICAgICB2YXIgcUtleSA9IHZhbHVlLnNwbGl0KCc9JylbMF07XG4gICAgICAgICAgICAgICAgdmFyIHFWYWwgPSB2YWx1ZS5zcGxpdCgnPScpWzFdO1xuXG4gICAgICAgICAgICAgICAgaWYgKHFWYWwuaW5kZXhPZignLCcpICE9PSAtMSkge1xuICAgICAgICAgICAgICAgICAgICBxVmFsID0gcVZhbC5zcGxpdCgnLCcpO1xuICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgIHJldHVybk9ialtxS2V5XSA9IHFWYWw7XG4gICAgICAgICAgICB9KTtcblxuICAgICAgICAgICAgcmV0dXJuIHJldHVybk9iajtcbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgICogTm9ybWFsaXplcyBhbmQgbWVyZ2VzIHN0cmluZ3Mgb2YgdHlwZSAnYT1iJywgeyBiOmN9IHRvIHsgYTpiLCBiOmN9XG4gICAgICAgICAqIEBwYXJhbSAgeyBzdHJpbmd8QXJyYXl8T2JqZWN0fSBxczFcbiAgICAgICAgICogQHBhcmFtICB7IHN0cmluZ3xBcnJheXxPYmplY3R9IHFzMlxuICAgICAgICAgKiBAcmV0dXJuIHtPYmplY3R9XG4gICAgICAgICAqL1xuICAgICAgICBtZXJnZVFTOiBmdW5jdGlvbiAocXMxLCBxczIpIHtcbiAgICAgICAgICAgIHZhciBvYmoxID0gdGhpcy5xc1RvT2JqZWN0KHRoaXMudG9RdWVyeUZvcm1hdChxczEpKTtcbiAgICAgICAgICAgIHZhciBvYmoyID0gdGhpcy5xc1RvT2JqZWN0KHRoaXMudG9RdWVyeUZvcm1hdChxczIpKTtcbiAgICAgICAgICAgIHJldHVybiAkLmV4dGVuZCh0cnVlLCB7fSwgb2JqMSwgb2JqMik7XG4gICAgICAgIH0sXG5cbiAgICAgICAgYWRkVHJhaWxpbmdTbGFzaDogZnVuY3Rpb24gKHVybCkge1xuICAgICAgICAgICAgaWYgKCF1cmwpIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gJyc7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICByZXR1cm4gKHVybC5jaGFyQXQodXJsLmxlbmd0aCAtIDEpID09PSAnLycpID8gdXJsIDogKHVybCArICcvJyk7XG4gICAgICAgIH1cbiAgICB9O1xufSgpKTtcblxuXG4iLCIvKipcbiAqIFV0aWxpdGllcyBmb3Igd29ya2luZyB3aXRoIHRoZSBydW4gc2VydmljZVxuKi9cbid1c2Ugc3RyaWN0JztcbnZhciBxdXRpbCA9IHJlcXVpcmUoJy4vcXVlcnktdXRpbCcpO1xudmFyIE1BWF9VUkxfTEVOR1RIID0gMjA0ODtcblxubW9kdWxlLmV4cG9ydHMgPSAoZnVuY3Rpb24gKCkge1xuICAgIHJldHVybiB7XG4gICAgICAgIC8qKlxuICAgICAgICAgKiBub3JtYWxpemVzIGRpZmZlcmVudCB0eXBlcyBvZiBvcGVyYXRpb24gaW5wdXRzXG4gICAgICAgICAqIEBwYXJhbSAge09iamVjdHxBcnJheXxTdHJpbmd9IG9wZXJhdGlvbnMgb3BlcmF0aW9ucyB0byBwZXJmb3JtXG4gICAgICAgICAqIEBwYXJhbSAge0FycmF5fSBhcmdzIGFyZ3VtZW50cyBmb3Igb3BlcmF0aW9uXG4gICAgICAgICAqIEByZXR1cm4ge1N0cmluZ30gb3BlcmF0aW9ucyBvZiB0aGUgZm9ybSBgeyBvcHM6IFtdLCBhcmdzOiBbXSB9YFxuICAgICAgICAgKi9cbiAgICAgICAgbm9ybWFsaXplT3BlcmF0aW9uczogZnVuY3Rpb24gKG9wZXJhdGlvbnMsIGFyZ3MpIHtcbiAgICAgICAgICAgIGlmICghYXJncykge1xuICAgICAgICAgICAgICAgIGFyZ3MgPSBbXTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHZhciByZXR1cm5MaXN0ID0ge1xuICAgICAgICAgICAgICAgIG9wczogW10sXG4gICAgICAgICAgICAgICAgYXJnczogW11cbiAgICAgICAgICAgIH07XG5cbiAgICAgICAgICAgIHZhciBfY29uY2F0ID0gZnVuY3Rpb24gKGFycikge1xuICAgICAgICAgICAgICAgIHJldHVybiAoYXJyICE9PSBudWxsICYmIGFyciAhPT0gdW5kZWZpbmVkKSA/IFtdLmNvbmNhdChhcnIpIDogW107XG4gICAgICAgICAgICB9O1xuXG4gICAgICAgICAgICAvL3sgYWRkOiBbMSwyXSwgc3VidHJhY3Q6IFsyLDRdIH1cbiAgICAgICAgICAgIHZhciBfbm9ybWFsaXplUGxhaW5PYmplY3RzID0gZnVuY3Rpb24gKG9wZXJhdGlvbnMsIHJldHVybkxpc3QpIHtcbiAgICAgICAgICAgICAgICBpZiAoIXJldHVybkxpc3QpIHtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuTGlzdCA9IHsgb3BzOiBbXSwgYXJnczogW10gfTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgJC5lYWNoKG9wZXJhdGlvbnMsIGZ1bmN0aW9uIChvcG4sIGFyZykge1xuICAgICAgICAgICAgICAgICAgICByZXR1cm5MaXN0Lm9wcy5wdXNoKG9wbik7XG4gICAgICAgICAgICAgICAgICAgIHJldHVybkxpc3QuYXJncy5wdXNoKF9jb25jYXQoYXJnKSk7XG4gICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgICAgcmV0dXJuIHJldHVybkxpc3Q7XG4gICAgICAgICAgICB9O1xuICAgICAgICAgICAgLy97IG5hbWU6ICdhZGQnLCBwYXJhbXM6IFsxXSB9XG4gICAgICAgICAgICB2YXIgX25vcm1hbGl6ZVN0cnVjdHVyZWRPYmplY3RzID0gZnVuY3Rpb24gKG9wZXJhdGlvbiwgcmV0dXJuTGlzdCkge1xuICAgICAgICAgICAgICAgIGlmICghcmV0dXJuTGlzdCkge1xuICAgICAgICAgICAgICAgICAgICByZXR1cm5MaXN0ID0geyBvcHM6IFtdLCBhcmdzOiBbXSB9O1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICByZXR1cm5MaXN0Lm9wcy5wdXNoKG9wZXJhdGlvbi5uYW1lKTtcbiAgICAgICAgICAgICAgICByZXR1cm5MaXN0LmFyZ3MucHVzaChfY29uY2F0KG9wZXJhdGlvbi5wYXJhbXMpKTtcbiAgICAgICAgICAgICAgICByZXR1cm4gcmV0dXJuTGlzdDtcbiAgICAgICAgICAgIH07XG5cbiAgICAgICAgICAgIHZhciBfbm9ybWFsaXplT2JqZWN0ID0gZnVuY3Rpb24gKG9wZXJhdGlvbiwgcmV0dXJuTGlzdCkge1xuICAgICAgICAgICAgICAgIHJldHVybiAoKG9wZXJhdGlvbi5uYW1lKSA/IF9ub3JtYWxpemVTdHJ1Y3R1cmVkT2JqZWN0cyA6IF9ub3JtYWxpemVQbGFpbk9iamVjdHMpKG9wZXJhdGlvbiwgcmV0dXJuTGlzdCk7XG4gICAgICAgICAgICB9O1xuXG4gICAgICAgICAgICB2YXIgX25vcm1hbGl6ZUxpdGVyYWxzID0gZnVuY3Rpb24gKG9wZXJhdGlvbiwgYXJncywgcmV0dXJuTGlzdCkge1xuICAgICAgICAgICAgICAgIGlmICghcmV0dXJuTGlzdCkge1xuICAgICAgICAgICAgICAgICAgICByZXR1cm5MaXN0ID0geyBvcHM6IFtdLCBhcmdzOiBbXSB9O1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICByZXR1cm5MaXN0Lm9wcy5wdXNoKG9wZXJhdGlvbik7XG4gICAgICAgICAgICAgICAgcmV0dXJuTGlzdC5hcmdzLnB1c2goX2NvbmNhdChhcmdzKSk7XG4gICAgICAgICAgICAgICAgcmV0dXJuIHJldHVybkxpc3Q7XG4gICAgICAgICAgICB9O1xuXG5cbiAgICAgICAgICAgIHZhciBfbm9ybWFsaXplQXJyYXlzID0gZnVuY3Rpb24gKG9wZXJhdGlvbnMsIGFyZywgcmV0dXJuTGlzdCkge1xuICAgICAgICAgICAgICAgIGlmICghcmV0dXJuTGlzdCkge1xuICAgICAgICAgICAgICAgICAgICByZXR1cm5MaXN0ID0geyBvcHM6IFtdLCBhcmdzOiBbXSB9O1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAkLmVhY2gob3BlcmF0aW9ucywgZnVuY3Rpb24gKGluZGV4LCBvcG4pIHtcbiAgICAgICAgICAgICAgICAgICAgaWYgKCQuaXNQbGFpbk9iamVjdChvcG4pKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBfbm9ybWFsaXplT2JqZWN0KG9wbiwgcmV0dXJuTGlzdCk7XG4gICAgICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBfbm9ybWFsaXplTGl0ZXJhbHMob3BuLCBhcmdzW2luZGV4XSwgcmV0dXJuTGlzdCk7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgICByZXR1cm4gcmV0dXJuTGlzdDtcbiAgICAgICAgICAgIH07XG5cbiAgICAgICAgICAgIGlmICgkLmlzUGxhaW5PYmplY3Qob3BlcmF0aW9ucykpIHtcbiAgICAgICAgICAgICAgICBfbm9ybWFsaXplT2JqZWN0KG9wZXJhdGlvbnMsIHJldHVybkxpc3QpO1xuICAgICAgICAgICAgfSBlbHNlIGlmICgkLmlzQXJyYXkob3BlcmF0aW9ucykpIHtcbiAgICAgICAgICAgICAgICBfbm9ybWFsaXplQXJyYXlzKG9wZXJhdGlvbnMsIGFyZ3MsIHJldHVybkxpc3QpO1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICBfbm9ybWFsaXplTGl0ZXJhbHMob3BlcmF0aW9ucywgYXJncywgcmV0dXJuTGlzdCk7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIHJldHVybiByZXR1cm5MaXN0O1xuICAgICAgICB9LFxuXG4gICAgICAgIHNwbGl0R2V0RmFjdG9yeTogZnVuY3Rpb24gKGh0dHBPcHRpb25zKSB7XG4gICAgICAgICAgICByZXR1cm4gZnVuY3Rpb24gKHBhcmFtcywgb3B0aW9ucykge1xuICAgICAgICAgICAgICAgIHZhciBodHRwID0gdGhpczsgLy9lc2xpbnQtZGlzYWJsZS1saW5lXG4gICAgICAgICAgICAgICAgdmFyIGdldFZhbHVlID0gZnVuY3Rpb24gKG5hbWUpIHtcbiAgICAgICAgICAgICAgICAgICAgdmFyIHZhbHVlID0gb3B0aW9uc1tuYW1lXSB8fCBodHRwT3B0aW9uc1tuYW1lXTtcbiAgICAgICAgICAgICAgICAgICAgaWYgKHR5cGVvZiB2YWx1ZSA9PT0gJ2Z1bmN0aW9uJykge1xuICAgICAgICAgICAgICAgICAgICAgICAgdmFsdWUgPSB2YWx1ZSgpO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgIHJldHVybiB2YWx1ZTtcbiAgICAgICAgICAgICAgICB9O1xuICAgICAgICAgICAgICAgIHZhciBnZXRGaW5hbFVybCA9IGZ1bmN0aW9uIChwYXJhbXMpIHtcbiAgICAgICAgICAgICAgICAgICAgdmFyIHVybCA9IGdldFZhbHVlKCd1cmwnLCBvcHRpb25zKTtcbiAgICAgICAgICAgICAgICAgICAgdmFyIGRhdGEgPSBwYXJhbXM7XG4gICAgICAgICAgICAgICAgICAgIC8vIFRoZXJlIGlzIGVhc3kgKG9yIGtub3duKSB3YXkgdG8gZ2V0IHRoZSBmaW5hbCBVUkwganF1ZXJ5IGlzIGdvaW5nIHRvIHNlbmQgc29cbiAgICAgICAgICAgICAgICAgICAgLy8gd2UncmUgcmVwbGljYXRpbmcgaXQuIFRoZSBwcm9jZXNzIG1pZ2h0IGNoYW5nZSBhdCBzb21lIHBvaW50IGJ1dCBpdCBwcm9iYWJseSB3aWxsIG5vdC5cbiAgICAgICAgICAgICAgICAgICAgLy8gMS4gUmVtb3ZlIGhhc2hcbiAgICAgICAgICAgICAgICAgICAgdXJsID0gdXJsLnJlcGxhY2UoLyMuKiQvLCAnJyk7XG4gICAgICAgICAgICAgICAgICAgIC8vIDEuIEFwcGVuZCBxdWVyeSBzdHJpbmdcbiAgICAgICAgICAgICAgICAgICAgdmFyIHF1ZXJ5UGFyYW1zID0gcXV0aWwudG9RdWVyeUZvcm1hdChkYXRhKTtcbiAgICAgICAgICAgICAgICAgICAgdmFyIHF1ZXN0aW9uSWR4ID0gdXJsLmluZGV4T2YoJz8nKTtcbiAgICAgICAgICAgICAgICAgICAgaWYgKHF1ZXJ5UGFyYW1zICYmIHF1ZXN0aW9uSWR4ID4gLTEpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybiB1cmwgKyAnJicgKyBxdWVyeVBhcmFtcztcbiAgICAgICAgICAgICAgICAgICAgfSBlbHNlIGlmIChxdWVyeVBhcmFtcykge1xuICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIHVybCArICc/JyArIHF1ZXJ5UGFyYW1zO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgIHJldHVybiB1cmw7XG4gICAgICAgICAgICAgICAgfTtcbiAgICAgICAgICAgICAgICB2YXIgdXJsID0gZ2V0RmluYWxVcmwocGFyYW1zKTtcbiAgICAgICAgICAgICAgICAvLyBXZSBtdXN0IHNwbGl0IHRoZSBHRVQgaW4gbXVsdGlwbGUgc2hvcnQgVVJMJ3NcbiAgICAgICAgICAgICAgICAvLyBUaGUgb25seSBwcm9wZXJ0eSBhbGxvd2VkIHRvIGJlIHNwbGl0IGlzIFwiaW5jbHVkZVwiXG4gICAgICAgICAgICAgICAgaWYgKHBhcmFtcyAmJiBwYXJhbXMuaW5jbHVkZSAmJiBlbmNvZGVVUkkodXJsKS5sZW5ndGggPiBNQVhfVVJMX0xFTkdUSCkge1xuICAgICAgICAgICAgICAgICAgICB2YXIgZHRkID0gJC5EZWZlcnJlZCgpO1xuICAgICAgICAgICAgICAgICAgICB2YXIgcGFyYW1zQ29weSA9ICQuZXh0ZW5kKHRydWUsIHt9LCBwYXJhbXMpO1xuICAgICAgICAgICAgICAgICAgICBkZWxldGUgcGFyYW1zQ29weS5pbmNsdWRlO1xuICAgICAgICAgICAgICAgICAgICB2YXIgdXJsTm9JbmNsdWRlcyA9IGdldEZpbmFsVXJsKHBhcmFtc0NvcHkpO1xuICAgICAgICAgICAgICAgICAgICB2YXIgZGlmZiA9IE1BWF9VUkxfTEVOR1RIIC0gdXJsTm9JbmNsdWRlcy5sZW5ndGg7XG4gICAgICAgICAgICAgICAgICAgIHZhciBvbGRTdWNjZXNzID0gb3B0aW9ucy5zdWNjZXNzIHx8IGh0dHBPcHRpb25zLnN1Y2Nlc3MgfHwgJC5ub29wO1xuICAgICAgICAgICAgICAgICAgICB2YXIgb2xkRXJyb3IgPSBvcHRpb25zLmVycm9yIHx8IGh0dHBPcHRpb25zLmVycm9yIHx8ICQubm9vcDtcbiAgICAgICAgICAgICAgICAgICAgLy8gcmVtb3ZlIHRoZSBvcmlnaW5hbCBzdWNjZXNzIGFuZCBlcnJvciBjYWxsYmFja3NcbiAgICAgICAgICAgICAgICAgICAgb3B0aW9ucy5zdWNjZXNzID0gJC5ub29wO1xuICAgICAgICAgICAgICAgICAgICBvcHRpb25zLmVycm9yID0gJC5ub29wO1xuXG4gICAgICAgICAgICAgICAgICAgIHZhciBpbmNsdWRlID0gcGFyYW1zLmluY2x1ZGU7XG4gICAgICAgICAgICAgICAgICAgIHZhciBjdXJySW5jbHVkZXMgPSBbXTtcbiAgICAgICAgICAgICAgICAgICAgdmFyIGluY2x1ZGVPcHRzID0gW2N1cnJJbmNsdWRlc107XG4gICAgICAgICAgICAgICAgICAgIHZhciBjdXJyTGVuZ3RoID0gZW5jb2RlVVJJQ29tcG9uZW50KCc/aW5jbHVkZT0nKS5sZW5ndGg7XG4gICAgICAgICAgICAgICAgICAgIHZhciB2YXJpYWJsZSA9IGluY2x1ZGUucG9wKCk7XG4gICAgICAgICAgICAgICAgICAgIHdoaWxlICh2YXJpYWJsZSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgdmFyIHZhckxlbmdodCA9IGVuY29kZVVSSUNvbXBvbmVudCh2YXJpYWJsZSkubGVuZ3RoO1xuICAgICAgICAgICAgICAgICAgICAgICAgLy8gVXNlIGEgZ3JlZWR5IGFwcHJvYWNoIGZvciBub3csIGNhbiBiZSBvcHRpbWl6ZWQgdG8gYmUgc29sdmVkIGluIGEgbW9yZVxuICAgICAgICAgICAgICAgICAgICAgICAgLy8gZWZmaWNpZW50IHdheVxuICAgICAgICAgICAgICAgICAgICAgICAgLy8gKyAxIGlzIHRoZSBjb21tYVxuICAgICAgICAgICAgICAgICAgICAgICAgaWYgKGN1cnJMZW5ndGggKyB2YXJMZW5naHQgKyAxIDwgZGlmZikge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGN1cnJJbmNsdWRlcy5wdXNoKHZhcmlhYmxlKTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBjdXJyTGVuZ3RoICs9IHZhckxlbmdodCArIDE7XG4gICAgICAgICAgICAgICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGN1cnJJbmNsdWRlcyA9IFt2YXJpYWJsZV07XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgaW5jbHVkZU9wdHMucHVzaChjdXJySW5jbHVkZXMpO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGN1cnJMZW5ndGggPSAnP2luY2x1ZGU9Jy5sZW5ndGggKyB2YXJMZW5naHQ7XG4gICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgICAgICB2YXJpYWJsZSA9IGluY2x1ZGUucG9wKCk7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgdmFyIHJlcXMgPSAkLm1hcChpbmNsdWRlT3B0cywgZnVuY3Rpb24gKGluY2x1ZGUpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHZhciByZXFQYXJhbXMgPSAkLmV4dGVuZCh7fSwgcGFyYW1zLCB7IGluY2x1ZGU6IGluY2x1ZGUgfSk7XG4gICAgICAgICAgICAgICAgICAgICAgICByZXR1cm4gaHR0cC5nZXQocmVxUGFyYW1zLCBvcHRpb25zKTtcbiAgICAgICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgICAgICAgICQud2hlbi5hcHBseSgkLCByZXFzKS50aGVuKGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIEVhY2ggYXJndW1lbnQgYXJlIGFycmF5cyBvZiB0aGUgYXJndW1lbnRzIG9mIGVhY2ggZG9uZSByZXF1ZXN0XG4gICAgICAgICAgICAgICAgICAgICAgICAvLyBTbyB0aGUgZmlyc3QgYXJndW1lbnQgb2YgdGhlIGZpcnN0IGFycmF5IG9mIGFyZ3VtZW50cyBpcyB0aGUgZGF0YVxuICAgICAgICAgICAgICAgICAgICAgICAgdmFyIGlzVmFsaWQgPSBhcmd1bWVudHNbMF0gJiYgYXJndW1lbnRzWzBdWzBdO1xuICAgICAgICAgICAgICAgICAgICAgICAgaWYgKCFpc1ZhbGlkKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gU2hvdWxkIG5ldmVyIGhhcHBlbi4uLlxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIG9sZEVycm9yKCk7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIGR0ZC5yZWplY3QoKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgICAgIHZhciBmaXJzdFJlc3BvbnNlID0gYXJndW1lbnRzWzBdWzBdO1xuICAgICAgICAgICAgICAgICAgICAgICAgdmFyIGlzT2JqZWN0ID0gJC5pc1BsYWluT2JqZWN0KGZpcnN0UmVzcG9uc2UpO1xuICAgICAgICAgICAgICAgICAgICAgICAgdmFyIGlzUnVuQVBJID0gKGlzT2JqZWN0ICYmICQuaXNQbGFpbk9iamVjdChmaXJzdFJlc3BvbnNlLnZhcmlhYmxlcykpIHx8ICFpc09iamVjdDtcbiAgICAgICAgICAgICAgICAgICAgICAgIGlmIChpc1J1bkFQSSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmIChpc09iamVjdCkge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBhZ2dyZWdhdGUgdGhlIHZhcmlhYmxlcyBwcm9wZXJ0eSBvbmx5XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHZhciBhZ2dyZWdhdGVSdW4gPSBhcmd1bWVudHNbMF1bMF07XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICQuZWFjaChhcmd1bWVudHMsIGZ1bmN0aW9uIChpZHgsIGFyZ3MpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHZhciBydW4gPSBhcmdzWzBdO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJC5leHRlbmQodHJ1ZSwgYWdncmVnYXRlUnVuLnZhcmlhYmxlcywgcnVuLnZhcmlhYmxlcyk7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBvbGRTdWNjZXNzKGFnZ3JlZ2F0ZVJ1biwgYXJndW1lbnRzWzBdWzFdLCBhcmd1bWVudHNbMF1bMl0pO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkdGQucmVzb2x2ZShhZ2dyZWdhdGVSdW4sIGFyZ3VtZW50c1swXVsxXSwgYXJndW1lbnRzWzBdWzJdKTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBhcnJheSBvZiBydW5zXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIEFncmVnYXRlIHZhcmlhYmxlcyBpbiBlYWNoIHJ1blxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB2YXIgYWdncmVnYXRlZFJ1bnMgPSB7fTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJC5lYWNoKGFyZ3VtZW50cywgZnVuY3Rpb24gKGlkeCwgYXJncykge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdmFyIHJ1bnMgPSBhcmdzWzBdO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWYgKCEkLmlzQXJyYXkocnVucykpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICByZXR1cm47XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAkLmVhY2gocnVucywgZnVuY3Rpb24gKGlkeFJ1biwgcnVuKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWYgKHJ1bi5pZCAmJiAhYWdncmVnYXRlZFJ1bnNbcnVuLmlkXSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBydW4udmFyaWFibGVzID0gcnVuLnZhcmlhYmxlcyB8fCB7fTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYWdncmVnYXRlZFJ1bnNbcnVuLmlkXSA9IHJ1bjtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB9IGVsc2UgaWYgKHJ1bi5pZCkge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAkLmV4dGVuZCh0cnVlLCBhZ2dyZWdhdGVkUnVuc1tydW4uaWRdLnZhcmlhYmxlcywgcnVuLnZhcmlhYmxlcyk7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyB0dXJuIGl0IGludG8gYW4gYXJyYXlcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYWdncmVnYXRlZFJ1bnMgPSAkLm1hcChhZ2dyZWdhdGVkUnVucywgZnVuY3Rpb24gKHJ1bikgeyByZXR1cm4gcnVuOyB9KTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgb2xkU3VjY2VzcyhhZ2dyZWdhdGVkUnVucywgYXJndW1lbnRzWzBdWzFdLCBhcmd1bWVudHNbMF1bMl0pO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkdGQucmVzb2x2ZShhZ2dyZWdhdGVkUnVucywgYXJndW1lbnRzWzBdWzFdLCBhcmd1bWVudHNbMF1bMl0pO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gaXMgdmFyaWFibGVzIEFQSVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIGFnZ3JlZ2F0ZSB0aGUgcmVzcG9uc2VcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB2YXIgYWdncmVnYXRlZFZhcmlhYmxlcyA9IHt9O1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICQuZWFjaChhcmd1bWVudHMsIGZ1bmN0aW9uIChpZHgsIGFyZ3MpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdmFyIHZhcnMgPSBhcmdzWzBdO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAkLmV4dGVuZCh0cnVlLCBhZ2dyZWdhdGVkVmFyaWFibGVzLCB2YXJzKTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBvbGRTdWNjZXNzKGFnZ3JlZ2F0ZWRWYXJpYWJsZXMsIGFyZ3VtZW50c1swXVsxXSwgYXJndW1lbnRzWzBdWzJdKTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBkdGQucmVzb2x2ZShhZ2dyZWdhdGVkVmFyaWFibGVzLCBhcmd1bWVudHNbMF1bMV0sIGFyZ3VtZW50c1swXVsyXSk7XG4gICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgIH0sIGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIG9sZEVycm9yLmFwcGx5KGh0dHAsIGFyZ3VtZW50cyk7XG4gICAgICAgICAgICAgICAgICAgICAgICBkdGQucmVqZWN0LmFwcGx5KGR0ZCwgYXJndW1lbnRzKTtcbiAgICAgICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgICAgICAgIHJldHVybiBkdGQucHJvbWlzZSgpO1xuICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgIHJldHVybiBodHRwLmdldChwYXJhbXMsIG9wdGlvbnMpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH07XG4gICAgICAgIH1cbiAgICB9O1xufSgpKTtcbiJdfQ== diff --git a/dist/epicenter.min.js b/dist/epicenter.min.js index f25368b3..636b8daf 100644 --- a/dist/epicenter.min.js +++ b/dist/epicenter.min.js @@ -34,9 +34,9 @@ var list={"conditional-creation":require("./conditional-creation-strategy"),"new },{"../../service/world-api-adapter":44,"../../util/inherit":50,"./none-strategy":16}],16:[function(require,module,exports){ "use strict";var classFrom=require("../../util/inherit");var Base={};module.exports=classFrom(Base,{constructor:function(options){},reset:function(){return $.Deferred().resolve().promise()},getRun:function(runService){return $.Deferred().resolve(runService).promise()}}); },{"../../util/inherit":50}],17:[function(require,module,exports){ -"use strict";var classFrom=require("../../util/inherit");var IdentityStrategy=require("./none-strategy");var injectFiltersFromSession=require("../strategy-utils").injectFiltersFromSession;var injectScopeFromSession=require("../strategy-utils").injectScopeFromSession;var defaults={filter:{}};var Strategy=classFrom(IdentityStrategy,{constructor:function(options){var strategyOptions=options?options.strategyOptions:{};this.options=$.extend(!0,{},defaults,strategyOptions)},reset:function(runService,userSession,options){var opt=injectScopeFromSession(runService.getCurrentConfig(),userSession);return runService.create(opt,options).then(function(run){return run.freshlyCreated=!0,run})},getRun:function(runService,userSession,runSession,options){var filter=injectFiltersFromSession(this.options.filter,userSession);var me=this;return runService.query(filter,{sort:"created",direction:"desc"}).then(function(runs){return runs.length?runs[0]:me.reset(runService,userSession,options)})}});module.exports=Strategy; +"use strict";var classFrom=require("../../util/inherit");var IdentityStrategy=require("./none-strategy");var injectFiltersFromSession=require("../strategy-utils").injectFiltersFromSession;var injectScopeFromSession=require("../strategy-utils").injectScopeFromSession;var defaults={filter:{}};var Strategy=classFrom(IdentityStrategy,{constructor:function(options){var strategyOptions=options?options.strategyOptions:{};this.options=$.extend(!0,{},defaults,strategyOptions)},reset:function(runService,userSession,options){var opt=injectScopeFromSession(runService.getCurrentConfig(),userSession);return runService.create(opt,options).then(function(run){return run.freshlyCreated=!0,run})},getRun:function(runService,userSession,runSession,options){var filter=injectFiltersFromSession(this.options.filter,userSession);var me=this;return runService.query(filter,{startrecord:0,endrecord:0,sort:"created",direction:"desc"}).then(function(runs){return runs.length?runs[0]:me.reset(runService,userSession,options)})}});module.exports=Strategy; },{"../../util/inherit":50,"../strategy-utils":26,"./none-strategy":16}],18:[function(require,module,exports){ -"use strict";var classFrom=require("../../util/inherit");var injectFiltersFromSession=require("../strategy-utils").injectFiltersFromSession;var injectScopeFromSession=require("../strategy-utils").injectScopeFromSession;var Base={};var defaults={initOperation:[],flag:null};module.exports=classFrom(Base,{constructor:function(options){var strategyOptions=options?options.strategyOptions:{};if(this.options=$.extend(!0,{},defaults,strategyOptions),!this.options.initOperation||!this.options.initOperation.length)throw new Error("Specifying an init function is required for this strategy");this.options.flag||(this.options.flag={isInitComplete:!0})},reset:function(runService,userSession,options){var opt=injectScopeFromSession(runService.getCurrentConfig(),userSession);var me=this;return runService.create(opt,options).then(function(createResponse){return runService.serial([].concat(me.options.initOperation)).then(function(){return createResponse})}).then(function(createResponse){return runService.save(me.options.flag).then(function(patchResponse){return $.extend(!0,{},createResponse,patchResponse)})})},getRun:function(runService,userSession,runSession,options){var sessionFilter=injectFiltersFromSession(this.options.flag,userSession);var runopts=runService.getCurrentConfig();var filter=$.extend(!0,{trashed:!1},sessionFilter,{model:runopts.model});var me=this;return runService.query(filter,{sort:"created",direction:"desc"}).then(function(runs){return runs.length?runs[0]:me.reset(runService,userSession,options)})}}); +"use strict";var classFrom=require("../../util/inherit");var injectFiltersFromSession=require("../strategy-utils").injectFiltersFromSession;var injectScopeFromSession=require("../strategy-utils").injectScopeFromSession;var Base={};var defaults={initOperation:[],flag:null};module.exports=classFrom(Base,{constructor:function(options){var strategyOptions=options?options.strategyOptions:{};if(this.options=$.extend(!0,{},defaults,strategyOptions),!this.options.initOperation||!this.options.initOperation.length)throw new Error("Specifying an init function is required for this strategy");this.options.flag||(this.options.flag={isInitComplete:!0})},reset:function(runService,userSession,options){var opt=injectScopeFromSession(runService.getCurrentConfig(),userSession);var me=this;return runService.create(opt,options).then(function(createResponse){return runService.serial([].concat(me.options.initOperation)).then(function(){return createResponse})}).then(function(createResponse){return runService.save(me.options.flag).then(function(patchResponse){return $.extend(!0,{},createResponse,patchResponse)})})},getRun:function(runService,userSession,runSession,options){var sessionFilter=injectFiltersFromSession(this.options.flag,userSession);var runopts=runService.getCurrentConfig();var filter=$.extend(!0,{trashed:!1},sessionFilter,{model:runopts.model});var me=this;return runService.query(filter,{startrecord:0,endrecord:0,sort:"created",direction:"desc"}).then(function(runs){return runs.length?runs[0]:me.reset(runService,userSession,options)})}}); },{"../../util/inherit":50,"../strategy-utils":26}],19:[function(require,module,exports){ "use strict";var classFrom=require("../../util/inherit");var ConditionalStrategy=require("./conditional-creation-strategy");var __super=ConditionalStrategy.prototype;var Strategy=classFrom(ConditionalStrategy,{constructor:function(options){__super.constructor.call(this,this.createIf,options)},createIf:function(run,headers){return!0}});module.exports=Strategy; },{"../../util/inherit":50,"./conditional-creation-strategy":11}],20:[function(require,module,exports){ @@ -48,7 +48,7 @@ var list={"conditional-creation":require("./conditional-creation-strategy"),"new },{"../service/run-api-service":38,"../service/state-api-adapter":40,"../util/run-util":54,"./run-manager":10,"./run-strategies/none-strategy":16,"./saved-runs-manager":21,"./scenario-strategies/baseline-strategy":23,"./scenario-strategies/reuse-last-unsaved":24,"./strategy-utils":26}],23:[function(require,module,exports){ "use strict";var ReuseinitStrategy=require("../run-strategies/reuse-last-initialized");module.exports=function(options){var defaults={baselineName:"Baseline",initOperation:[{stepTo:"end"}]};var strategyOptions=options?options.strategyOptions:{};var opts=$.extend({},defaults,strategyOptions);return new ReuseinitStrategy({strategyOptions:{initOperation:opts.initOperation,flag:{saved:!0,trashed:!1,name:opts.baselineName}}})}; },{"../run-strategies/reuse-last-initialized":18}],24:[function(require,module,exports){ -"use strict";var classFrom=require("../../util/inherit");var injectFiltersFromSession=require("../strategy-utils").injectFiltersFromSession;var injectScopeFromSession=require("../strategy-utils").injectScopeFromSession;var Base={};module.exports=classFrom(Base,{constructor:function(options){var strategyOptions=options?options.strategyOptions:{};this.options=strategyOptions},reset:function(runService,userSession,options){var opt=injectScopeFromSession(runService.getCurrentConfig(),userSession);return runService.create(opt,options).then(function(createResponse){return $.extend(!0,{},createResponse,{freshlyCreated:!0})})},getRun:function(runService,userSession,opts){var runopts=runService.getCurrentConfig();var filter=injectFiltersFromSession({saved:!1,trashed:!1,model:runopts.model},userSession);var me=this;var outputModifiers={sort:"created",direction:"desc"};return runService.query(filter,outputModifiers).then(function(runs){return runs.length?runs[0]:me.reset(runService,userSession)})}},{requiresAuth:!1}); +"use strict";var classFrom=require("../../util/inherit");var injectFiltersFromSession=require("../strategy-utils").injectFiltersFromSession;var injectScopeFromSession=require("../strategy-utils").injectScopeFromSession;var Base={};module.exports=classFrom(Base,{constructor:function(options){var strategyOptions=options?options.strategyOptions:{};this.options=strategyOptions},reset:function(runService,userSession,options){var opt=injectScopeFromSession(runService.getCurrentConfig(),userSession);return runService.create(opt,options).then(function(createResponse){return $.extend(!0,{},createResponse,{freshlyCreated:!0})})},getRun:function(runService,userSession,opts){var runopts=runService.getCurrentConfig();var filter=injectFiltersFromSession({saved:!1,trashed:!1,model:runopts.model},userSession);var me=this;var outputModifiers={startrecord:0,endrecord:0,sort:"created",direction:"desc"};return runService.query(filter,outputModifiers).then(function(runs){return runs.length?runs[0]:me.reset(runService,userSession)})}},{requiresAuth:!1}); },{"../../util/inherit":50,"../strategy-utils":26}],25:[function(require,module,exports){ "use strict";module.exports={reset:function(params,options,manager){return manager.reset(options)}}; },{}],26:[function(require,module,exports){ diff --git a/dist/epicenter.min.js.map b/dist/epicenter.min.js.map index e4915c77..2646cd59 100644 --- a/dist/epicenter.min.js.map +++ b/dist/epicenter.min.js.map @@ -1 +1 @@ -{"version":3,"sources":["node_modules/browser-pack/_prelude.js","src/api-version.json","node_modules/Base64/base64.js","node_modules/object-assign/index.js","src/app.js","src/env-load.js","src/managers/auth-manager.js","src/managers/channel-manager.js","src/managers/epicenter-channel-manager.js","src/managers/key-names.js","src/managers/run-manager.js","src/managers/run-strategies/conditional-creation-strategy.js","src/managers/run-strategies/deprecated/new-if-initialized-strategy.js","src/managers/run-strategies/deprecated/new-if-persisted-strategy.js","src/managers/run-strategies/index.js","src/managers/run-strategies/multiplayer-strategy.js","src/managers/run-strategies/none-strategy.js","src/managers/run-strategies/reuse-across-sessions.js","src/managers/run-strategies/reuse-last-initialized.js","src/managers/run-strategies/reuse-never.js","src/managers/run-strategies/reuse-per-session.js","src/managers/saved-runs-manager.js","src/managers/scenario-manager.js","src/managers/scenario-strategies/baseline-strategy.js","src/managers/scenario-strategies/reuse-last-unsaved.js","src/managers/special-operations.js","src/managers/strategy-utils.js","src/managers/world-manager.js","src/service/admin-file-service.js","src/service/asset-api-adapter.js","src/service/auth-api-service.js","src/service/channel-service.js","src/service/configuration-service.js","src/service/data-api-service.js","src/service/group-api-service.js","src/service/introspection-api-service.js","src/service/member-api-adapter.js","src/service/presence-api-service.js","src/service/run-api-service.js","src/service/service-utils.js","src/service/state-api-adapter.js","src/service/url-config-service.js","src/service/user-api-adapter.js","src/service/variables-api-service.js","src/service/world-api-adapter.js","src/store/cookie-store.js","src/store/session-manager.js","src/store/store-factory.js","src/transport/ajax-http-transport.js","src/transport/http-transport-factory.js","src/util/inherit.js","src/util/object-util.js","src/util/option-utils.js","src/util/query-util.js","src/util/run-util.js"],"names":["InvalidCharacterError","message","this","object","exports","self","chars","prototype","Error","name","btoa","input","str","String","block","charCode","idx","map","output","charAt","charCodeAt","atob","replace","length","bs","buffer","bc","fromCharCode","indexOf","toObject","val","undefined","TypeError","Object","shouldUseNative","assign","test1","getOwnPropertyNames","test2","i","order2","n","join","test3","split","forEach","letter","keys","e","hasOwnProperty","propIsEnumerable","propertyIsEnumerable","module","target","source","from","to","symbols","s","arguments","key","call","getOwnPropertySymbols","F","_private","util","factory","transport","store","service","manager","strategy","load","require","global","SKIP_ENV_LOAD","query","run","classFrom","strategyutils","Transport","Ajax","URL","Config","Run","File","Variables","Data","Auth","World","State","User","Member","Asset","Group","Introspect","Presence","Cookie","Store","ScenarioManager","RunManager","AuthManager","WorldManager","SavedRunsManager","strategies","list","ChannelManager","Channel","version","api","constants","URLConfigService","envLoad","callback","urlService","infoUrl","getAPIPath","envPromise","$","ajax","url","async","then","res","overrides","defaults","extend","fail","options","sessionManager","SessionManager","getMergedOptions","authAdapter","AuthAdapter","MemberAdapter","GroupService","_pick","objectAssign","window","requiresGroup","_findUserInGroup","members","id","j","userId","login","me","$d","Deferred","adapterOptions","success","noop","error","outSuccess","outError","groupId","decodeToken","token","encoded","JSON","parse","handleGroupError","statusCode","data","type","logout","statusText","status","reject","handleSuccess","response","access_token","userInfo","oldGroups","getSession","groups","userGroupOpts","auth","user","project","isTeamMember","parent_account_id","userName","user_name","sessionInfo","auth_token","account","user_id","saveSession","apply","resolve","handleGroupList","groupList","userGroups","group","filteredGroups","grep","resGroup","isFac","role","groupData","groupName","sessionInfoWithGroup","opts","groupService","getGroups","getUserGroups","promise","removeCookieFn","removeSession","getToken","httpOptions","session","params","memberInfo","memberAdapter","server","getGroupsForUser","isLoggedIn","getCurrentUserSessionInfo","addGroups","isArray","Array","each","index","extendedGroup","validProps","cometd","logLevel","websocketEnabled","ackEnabled","shareConnection","channel","handshake","defaultCometOptions","currentSubscriptions","_cometd","CometD","isConnected","connectionBroken","trigger","connectionSucceeded","configure","addListener","wasConnected","successful","bind","batch","subs","resubscribe","getChannel","isPlainObject","base","subscribe","subid","concat","unsubs","unsubscribe","removed","splice","on","event","off","ConfigService","validTypes","world","general","chat","getFromSessionOrError","value","sessionKeyName","settings","isPresenceData","payload","__super","EpicenterChannelManager","constructor","urlConfig","get","userProp","ext","authorization","channelOpts","allowAllChannels","baseParts","channelType","getGroupChannel","baseTopic","oldsubs","topic","context","callbackWithoutPresenceData","getWorldChannel","worldid","getUserChannel","userid","getPresenceChannel","callbackWithOnlyPresenceData","getDataChannel","collection","callbackWithCleanData","meta","path","subType","date","dataPath","actualData","EPI_SESSION_KEY","STRATEGY_SESSION_KEY","patchRunService","patched","orig","do","operation","reservedOps","specialOperations","sessionKeyFromOptions","runService","config","getCurrentConfig","sessionKey","isFunction","setRunInSession","variables","getStore","set","stringify","RunService","isEmpty","getBestStrategy","keyNames","baseKey","reduce","accum","getRun","sessionStore","sessionContents","runSession","runId","authSession","requiresAuth","console","updateConfig","filter","results","catch","err","reset","Base","Strategy","condition","userSession","opt","scope","create","freshlyCreated","loadAndCheck","shouldCreate","msg","headers","ConditionalStrategy","createIf","warn","getResponseHeader","initialized","conditional-creation","new-if-initialized","new-if-persisted","none","multiplayer","reuse-never","reuse-per-session","reuse-across-sessions","reuse-last-initialized","byName","strategyName","strategyOptions","initOperation","StrategyCtor","strategyInstance","register","IdentityStrategy","WorldApiAdapter","worldApi","curUserId","curGroupName","getCurrentWorldForUser","newRunForWorld","runid","model","dtd","loadRunFromWorld","getCurrentRunId","serverError","injectFiltersFromSession","injectScopeFromSession","sort","direction","runs","flag","isInitComplete","createResponse","serial","save","patchResponse","sessionFilter","runopts","trashed","scopeByGroup","scopeByUser","otherFields","param","saved","mark","remove","toMark","rs","existingOptions","proms","r","when","autoRestore","getRuns","modifiers","scopedFilter","opModifiers","include","cookieNameFromOptions","prefix","advanceOperation","BaselineStrategyToUse","includeBaseLine","BaselineStrategy","NoneStrategy","baseline","strategyUtils","mergeRunOptions","baselineName","runName","savedRuns","origGetRuns","args","current","LastUnsavedStrategy","saveAndAdvance","metadata","clone","sa","StateService","advanceOpns","rutil","normalizeOperations","exclude","ops","markSaved","savedResponse","advance","ReuseinitStrategy","stepTo","outputModifiers","currentFilter","currentParams","buildStrategy","worldId","resolveWith","WorldApi","_auth","getCurrentWorld","getCurrentRun","getAndRestoreLatestRun","currentWorldId","runOpts","rm","TransportFactory","uploadBody","fileName","contents","boundary","body","uploadFileOptions","filePath","pop","serviceOptions","folderType","extraParams","FormData","processData","contentType","upload","accountPath","projectPath","Authorization","http","publicAsyncAPI","getContents","put","replaceExisting","prom","post","xhr","conflictStatus","delete","rename","newName","patch","apiEndpoint","fullUrl","transportOptions","assetApiParams","scopeConfig","validateFilename","filename","validateUrlParams","partKeys","buildUrl","parts","method","toLowerCase","urlOptions","createOptions","publicAPI","getServiceOptions","getOptions","files","fullPathFiles","file","assetUrl","password","resp","statusMessage","postParams","topicResolver","channelOptions","makeName","channelName","topics","subscriptionIds","push","publish","returnObjs","setEnv","env","property","qutil","root","getURL","addTrailingSlash","outputModifier","q","attrs","saveAs","serviceUtils","getDefaultOptions","finalOpts","finalParams","getApiUrl","byModel","modelFile","byRunID","runID","getFinalParams","patchUserActiveField","active","isString","objParams","getParms","getGroupDetails","makeUserActive","makeUserInactive","markOnline","markOffline","getStatus","cm","VariablesService","IntrospectionService","updateURLConfig","getFilterURL","filterMatrix","toMatrixFormat","addAutoRestoreHeader","isFilterRunId","autorestoreOpts","X-AutoRestore","updateHTTPConfig","splitGet","splitGetFactory","setFilterOrThrowError","runApiParams","oldSuccess","qs","filters","removeFromMemory","attributes","opsArgs","postOptions","result","prms","operations","opParams","responses","doSingleOp","op","shift","arg","parallel","queue","slice","actualResponse","a","introspect","introspectionConfig","introspection","publicSyncAPI","vs","rest","parseRunIdOrError","httpParams","replay","replayOptions","action","getLocalHost","existingFn","host","localHostFn","isLocal","epiVersion","location","pathname","UrlConfigService","envConf","isLocalhost","actingHost","API_PROTOCOL","HOST_API_MAPPING","forio.com","foriodev.com","publicExports","protocol","apiHost","isCustomDomain","pathHasApp","appPath","accnt","prj","versionPath","PROJECT_APIS","apiMapping","actualProtocol","configProtocol","apiPath","inArray","toQFilter","toIdFilters","getFilters","toQueryFormat","threshold","getById","variable","apiBase","assignmentEndpoint","projectEndpoint","setIdFilterOrThrowError","validateModelOrThrowError","worldApiParams","validParams","update","whitelist","updateOptions","deleteOptions","getWorldsForUser","addUsers","users","u","isObject","updateUser","patchOptions","removeUser","worlds","b","Date","lastModified","currentWorld","deleteRun","currentRunOptions","autoAssign","maxUsers","userIds","getProjectSettings","document","cookie","newCookie","hostname","validHost","domain","setOptions","encodeURIComponent","cookieReg","RegExp","exec","decodeURIComponent","remOptions","destroy","aKeys","nIdx","cookieKey","StorageFactory","optionUtils","EPI_MANAGER_KEY","synchronous","managerOptions","getBaseOptions","libOptions","finalOptions","baseOptions","storeOpts","isEpicenterDomain","serialized","cookieName","sessionDefaults","qutils","404","parameterParser","xhrFields","withCredentials","d","connect","connectOptions","ALLOWED_TO_BE_FUNCTIONS","log","oldSuccessFn","ajaxStatus","ajaxReq","beforeSend","requestUrl","ajaxOptions","trim","delimiter","head","inherit","C","P","dest","obj","props","staticProps","parent","child","p","customDefaults","libDefaults","setDefaults","returnArray","OPERATORS","mtrx","qsToObject","qsArray","returnObj","qKey","qVal","mergeQS","qs1","qs2","obj1","obj2","MAX_URL_LENGTH","returnList","_concat","arr","_normalizePlainObjects","opn","_normalizeStructuredObjects","_normalizeObject","_normalizeLiterals","_normalizeArrays","getValue","getFinalUrl","queryParams","questionIdx","encodeURI","paramsCopy","urlNoIncludes","diff","oldError","currIncludes","includeOpts","currLength","varLenght","reqs","reqParams","isValid","firstResponse","isRunAPI","aggregateRun","aggregatedRuns","idxRun","aggregatedVariables","vars"],"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> 8 - idx % 1 * 8)\n ) {\n charCode = str.charCodeAt(idx += 3/4);\n if (charCode > 0xFF) {\n throw new InvalidCharacterError(\"'btoa' failed: The string to be encoded contains characters outside of the Latin1 range.\");\n }\n block = block << 8 | charCode;\n }\n return output;\n });\n\n // decoder\n // [https://gist.github.com/1020396] by [https://github.com/atk]\n object.atob || (\n object.atob = function (input) {\n var str = String(input).replace(/=+$/, '');\n if (str.length % 4 == 1) {\n throw new InvalidCharacterError(\"'atob' failed: The string to be decoded is not correctly encoded.\");\n }\n for (\n // initialize result and counters\n var bc = 0, bs, buffer, idx = 0, output = '';\n // get next character\n buffer = str.charAt(idx++);\n // character found in table? initialize bit storage and add its ascii value;\n ~buffer && (bs = bc % 4 ? bs * 64 + buffer : buffer,\n // and if not first of each 4 characters,\n // convert the first 8 bits to one ascii character\n bc++ % 4) ? output += String.fromCharCode(255 & bs >> (-2 * bc & 6)) : 0\n ) {\n // try to find character in table (0-63, not found => -1)\n buffer = chars.indexOf(buffer);\n }\n return output;\n });\n\n}());\n","'use strict';\n/* eslint-disable no-unused-vars */\nvar hasOwnProperty = Object.prototype.hasOwnProperty;\nvar propIsEnumerable = Object.prototype.propertyIsEnumerable;\n\nfunction toObject(val) {\n\tif (val === null || val === undefined) {\n\t\tthrow new TypeError('Object.assign cannot be called with null or undefined');\n\t}\n\n\treturn Object(val);\n}\n\nfunction shouldUseNative() {\n\ttry {\n\t\tif (!Object.assign) {\n\t\t\treturn false;\n\t\t}\n\n\t\t// Detect buggy property enumeration order in older V8 versions.\n\n\t\t// https://bugs.chromium.org/p/v8/issues/detail?id=4118\n\t\tvar test1 = new String('abc'); // eslint-disable-line\n\t\ttest1[5] = 'de';\n\t\tif (Object.getOwnPropertyNames(test1)[0] === '5') {\n\t\t\treturn false;\n\t\t}\n\n\t\t// https://bugs.chromium.org/p/v8/issues/detail?id=3056\n\t\tvar test2 = {};\n\t\tfor (var i = 0; i < 10; i++) {\n\t\t\ttest2['_' + String.fromCharCode(i)] = i;\n\t\t}\n\t\tvar order2 = Object.getOwnPropertyNames(test2).map(function (n) {\n\t\t\treturn test2[n];\n\t\t});\n\t\tif (order2.join('') !== '0123456789') {\n\t\t\treturn false;\n\t\t}\n\n\t\t// https://bugs.chromium.org/p/v8/issues/detail?id=3056\n\t\tvar test3 = {};\n\t\t'abcdefghijklmnopqrst'.split('').forEach(function (letter) {\n\t\t\ttest3[letter] = letter;\n\t\t});\n\t\tif (Object.keys(Object.assign({}, test3)).join('') !==\n\t\t\t\t'abcdefghijklmnopqrst') {\n\t\t\treturn false;\n\t\t}\n\n\t\treturn true;\n\t} catch (e) {\n\t\t// We don't expect any of the above to throw, but better to be safe.\n\t\treturn false;\n\t}\n}\n\nmodule.exports = shouldUseNative() ? Object.assign : function (target, source) {\n\tvar from;\n\tvar to = toObject(target);\n\tvar symbols;\n\n\tfor (var s = 1; s < arguments.length; s++) {\n\t\tfrom = Object(arguments[s]);\n\n\t\tfor (var key in from) {\n\t\t\tif (hasOwnProperty.call(from, key)) {\n\t\t\t\tto[key] = from[key];\n\t\t\t}\n\t\t}\n\n\t\tif (Object.getOwnPropertySymbols) {\n\t\t\tsymbols = Object.getOwnPropertySymbols(from);\n\t\t\tfor (var i = 0; i < symbols.length; i++) {\n\t\t\t\tif (propIsEnumerable.call(from, symbols[i])) {\n\t\t\t\t\tto[symbols[i]] = from[symbols[i]];\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\treturn to;\n};\n","/**\n * Epicenter Javascript libraries\n * v<%= version %>\n * https://github.com/forio/epicenter-js-libs\n */\n\nvar F = {\n _private: {}, //need this hook now because tests expect everything to be global. Delete once tests are browserified\n util: {},\n factory: {},\n transport: {},\n store: {},\n service: {},\n manager: {\n strategy: {}\n },\n\n};\n\nF.load = require('./env-load');\n\nif (!global.SKIP_ENV_LOAD) {\n F.load();\n}\n\nF.util.query = require('./util/query-util');\nF.util.run = require('./util/run-util');\nF.util.classFrom = require('./util/inherit');\nF._private.strategyutils = require('./managers/strategy-utils');\n\nF.factory.Transport = require('./transport/http-transport-factory');\nF.transport.Ajax = require('./transport/ajax-http-transport');\n\nF.service.URL = require('./service/url-config-service');\nF.service.Config = require('./service/configuration-service');\nF.service.Run = require('./service/run-api-service');\nF.service.File = require('./service/admin-file-service');\nF.service.Variables = require('./service/variables-api-service');\nF.service.Data = require('./service/data-api-service');\nF.service.Auth = require('./service/auth-api-service');\nF.service.World = require('./service/world-api-adapter');\nF.service.State = require('./service/state-api-adapter');\nF.service.User = require('./service/user-api-adapter');\nF.service.Member = require('./service/member-api-adapter');\nF.service.Asset = require('./service/asset-api-adapter');\nF.service.Group = require('./service/group-api-service');\nF.service.Introspect = require('./service/introspection-api-service');\nF.service.Presence = require('./service/presence-api-service');\n\nF.store.Cookie = require('./store/cookie-store');\nF.factory.Store = require('./store/store-factory');\n\nF.manager.ScenarioManager = require('./managers/scenario-manager');\nF.manager.RunManager = require('./managers/run-manager');\nF.manager.AuthManager = require('./managers/auth-manager');\nF.manager.WorldManager = require('./managers/world-manager');\nF.manager.SavedRunsManager = require('./managers/saved-runs-manager');\n\nvar strategies = require('./managers/run-strategies');\nF.manager.strategy = strategies.list; //TODO: this is not really a manager so namespace this better\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\nF.constants = require('./managers/key-names');\n\nglobal.F = F;\nmodule.exports = F;\n","'use strict';\n\nvar URLConfigService = require('./service/url-config-service');\n\nvar envLoad = function (callback) {\n var urlService = new URLConfigService();\n var infoUrl = urlService.getAPIPath('config');\n var envPromise = $.ajax({ url: infoUrl, async: false });\n envPromise = envPromise.then(function (res) {\n var overrides = res.api;\n URLConfigService.defaults = $.extend(URLConfigService.defaults, overrides);\n });\n return envPromise.then(callback).fail(callback);\n};\n\nmodule.exports = envLoad;\n","/**\n* ## Authorization Manager\n*\n* The Authorization Manager provides an easy way to manage user authentication (logging in and out) and authorization (keeping track of tokens, sessions, and groups) for projects.\n*\n* The Authorization Manager is most useful for [team projects](../../../glossary/#team) with an access level of [Authenticated](../../../glossary/#access). These projects are accessed by [end users](../../../glossary/#users) who are members of one or more [groups](../../../glossary/#groups).\n*\n* #### Using the Authorization Manager\n*\n* To use the Authorization Manager, instantiate it. Then, make calls to any of the methods you need:\n*\n* var authMgr = new F.manager.AuthManager({\n* account: 'acme-simulations',\n* userName: 'enduser1',\n* password: 'passw0rd'\n* });\n* authMgr.login().then(function () {\n* authMgr.getCurrentUserSessionInfo();\n* });\n*\n*\n* The `options` object passed to the `F.manager.AuthManager()` call can include:\n*\n* * `account`: The account id for this `userName`. In the Epicenter UI, this is the **Team ID** (for team projects) or the **User ID** (for personal projects).\n* * `userName`: Email or username to use for logging in.\n* * `password`: Password for specified `userName`.\n* * `project`: The **Project ID** for the project to log this user into. Optional.\n* * `groupId`: Id of the group to which `userName` belongs. Required for end users if the `project` is specified.\n*\n* If you prefer starting from a template, the Epicenter JS Libs [Login Component](../../#components) uses the Authorization Manager as well. This sample HTML page (and associated CSS and JS files) provides a login form for team members and end users of your project. It also includes a group selector for end users that are members of multiple groups.\n*/\n\n'use strict';\nvar AuthAdapter = require('../service/auth-api-service');\nvar MemberAdapter = require('../service/member-api-adapter');\nvar GroupService = require('../service/group-api-service');\nvar SessionManager = require('../store/session-manager');\nvar _pick = require('../util/object-util')._pick;\nvar objectAssign = require('object-assign');\n\nvar atob = window.atob || require('Base64').atob;\n\nvar defaults = {\n requiresGroup: true\n};\n\nfunction AuthManager(options) {\n options = $.extend(true, {}, defaults, options);\n this.sessionManager = new SessionManager(options);\n this.options = this.sessionManager.getMergedOptions();\n\n this.authAdapter = new AuthAdapter(this.options);\n}\n\nvar _findUserInGroup = function (members, id) {\n for (var j = 0; j < members.length; j++) {\n if (members[j].userId === id) {\n return members[j];\n }\n }\n return null;\n};\n\nAuthManager.prototype = $.extend(AuthManager.prototype, {\n\n /**\n * Logs user in.\n *\n * **Example**\n *\n * authMgr.login({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * userName: 'enduser1',\n * password: 'passw0rd'\n * })\n * .then(function(statusObj) {\n * // if enduser1 belongs to exactly one group\n * // (or if the login() call is modified to include the group id)\n * // continue here\n * })\n * .fail(function(statusObj) {\n * // if enduser1 belongs to multiple groups,\n * // the login() call fails\n * // and returns all groups of which the user is a member\n * for (var i=0; i < statusObj.userGroups.length; i++) {\n * console.log(statusObj.userGroups[i].name, statusObj.userGroups[i].groupId);\n * }\n * });\n *\n * **Parameters**\n *\n * @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:\n * @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).\n * @param {string} options.userName Email or username to use for logging in.\n * @param {string} options.password Password for specified `userName`.\n * @param {string} options.project (Optional) The **Project ID** for the project to log this user into.\n * @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.\n * @return {Promise}\n */\n login: function (options) {\n var me = this;\n var $d = $.Deferred();\n var sessionManager = this.sessionManager;\n var adapterOptions = sessionManager.getMergedOptions({ success: $.noop, error: $.noop }, options);\n var outSuccess = adapterOptions.success;\n var outError = adapterOptions.error;\n var groupId = adapterOptions.groupId;\n\n var decodeToken = function (token) {\n var encoded = token.split('.')[1];\n while (encoded.length % 4 !== 0) { //eslint-disable-line\n encoded += '=';\n }\n return JSON.parse(atob(encoded));\n };\n\n var handleGroupError = function (message, statusCode, data, type) {\n // logout the user since it's in an invalid state with no group selected\n me.logout().then(function () {\n var error = $.extend(true, {}, data, { statusText: message, status: statusCode, type: type });\n $d.reject(error);\n });\n };\n\n var handleSuccess = function (response) {\n var token = response.access_token;\n var userInfo = decodeToken(token);\n var oldGroups = sessionManager.getSession(adapterOptions).groups || {};\n var userGroupOpts = $.extend(true, {}, adapterOptions, { success: $.noop });\n var data = { auth: response, user: userInfo };\n var project = adapterOptions.project;\n var isTeamMember = userInfo.parent_account_id === null;\n var requiresGroup = adapterOptions.requiresGroup && project;\n\n var userName = (userInfo.user_name || '').split('/')[0]; //of form /\n var sessionInfo = {\n auth_token: token,\n account: adapterOptions.account,\n project: project,\n userId: userInfo.user_id,\n groups: oldGroups,\n isTeamMember: isTeamMember,\n userName: userName,\n };\n // The group is not required if the user is not logging into a project\n if (!requiresGroup) {\n sessionManager.saveSession(sessionInfo);\n outSuccess.apply(this, [data]);\n $d.resolve(data);\n return;\n }\n\n var handleGroupList = function (groupList) {\n data.userGroups = groupList;\n\n var group = null;\n if (groupList.length === 0) {\n handleGroupError('The user has no groups associated in this account', 403, data, 'NO_GROUPS');\n return;\n } else if (groupList.length === 1) {\n // Select the only group\n group = groupList[0];\n } else if (groupList.length > 1) {\n if (groupId) {\n var filteredGroups = $.grep(groupList, function (resGroup) {\n return resGroup.groupId === groupId;\n });\n group = filteredGroups.length === 1 ? filteredGroups[0] : null;\n }\n }\n\n if (group) {\n // A team member does not get the group members because is calling the Group API\n // but it's automatically a fac user\n var isFac = isTeamMember ? true : _findUserInGroup(group.members, userInfo.user_id).role === 'facilitator';\n var groupData = {\n groupId: group.groupId,\n groupName: group.name,\n isFac: isFac\n };\n var sessionInfoWithGroup = objectAssign({}, sessionInfo, groupData);\n sessionInfo.groups[project] = groupData;\n me.sessionManager.saveSession(sessionInfoWithGroup, adapterOptions);\n outSuccess.apply(this, [data]);\n $d.resolve(data);\n } else {\n handleGroupError('This user is associated with more than one group. Please specify a group id to log into and try again', 403, data, 'MULTIPLE_GROUPS');\n }\n };\n\n if (!isTeamMember) {\n me.getUserGroups({ userId: userInfo.user_id, token: token }, userGroupOpts)\n .then(handleGroupList, $d.reject);\n } else {\n var opts = objectAssign({}, userGroupOpts, { token: token });\n var groupService = new GroupService(opts);\n groupService.getGroups({ account: adapterOptions.account, project: project })\n .then(function (groups) {\n // Group API returns id instead of groupId\n groups.forEach(function (group) {\n group.groupId = group.id;\n });\n\n if (groups.length) {\n handleGroupList(groups);\n } else {\n //either it's a private project or there are no groups\n sessionManager.saveSession(sessionInfo);\n outSuccess.apply(this, [data]);\n $d.resolve(data);\n return;\n }\n }, $d.reject);\n }\n };\n\n adapterOptions.success = handleSuccess;\n adapterOptions.error = function (response) {\n if (adapterOptions.account) {\n // Try to login as a system user\n adapterOptions.account = null;\n adapterOptions.error = function () {\n outError.apply(this, arguments);\n $d.reject(response);\n };\n\n me.authAdapter.login(adapterOptions);\n return;\n }\n\n outError.apply(this, arguments);\n $d.reject(response);\n };\n\n this.authAdapter.login(adapterOptions);\n return $d.promise();\n },\n\n /**\n * Logs user out by clearing all session information.\n *\n * **Example**\n *\n * authMgr.logout();\n *\n * **Parameters**\n *\n * @param {Object} options (Optional) Overrides for configuration options.\n * @return {Promise}\n */\n logout: function (options) {\n var me = this;\n var adapterOptions = this.sessionManager.getMergedOptions(options);\n\n var removeCookieFn = function (response) {\n me.sessionManager.removeSession();\n };\n\n return this.authAdapter.logout(adapterOptions).then(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 * @return {Promise}\n */\n getToken: function (options) {\n var httpOptions = this.sessionManager.getMergedOptions(options);\n\n var session = this.sessionManager.getSession(httpOptions);\n var $d = $.Deferred();\n if (session.auth_token) {\n $d.resolve(session.auth_token);\n } else {\n this.login(httpOptions).then($d.resolve);\n }\n return $d.promise();\n },\n\n /**\n * Returns an array of group records, one for each group of which the current user is a member. Each group record includes the group `name`, `account`, `project`, and `groupId`.\n *\n * If some end users in your project are members of multiple groups, this is a useful method to call on your project's login page. When the user attempts to log in, you can use this to display the groups of which the user is member, and have the user select the correct group to log in to for this session.\n *\n * **Example**\n *\n * // get groups for current user\n * var sessionObj = authMgr.getCurrentUserSessionInfo();\n * authMgr.getUserGroups({ userId: sessionObj.userId, token: sessionObj.auth_token })\n * .then(function (groups) {\n * for (var i=0; i < groups.length; i++)\n * { console.log(groups[i].name); }\n * });\n *\n * // get groups for particular user\n * authMgr.getUserGroups({userId: 'b1c19dda-2d2e-4777-ad5d-3929f17e86d3', token: savedProjAccessToken });\n *\n * **Parameters**\n * @param {Object} params Object with a userId and token properties.\n * @param {String} params.userId The userId. If looking up groups for the currently logged in user, this is in the session information. Otherwise, pass a string.\n * @param {String} params.token The authorization credentials (access token) to use for checking the groups for this user. If looking up groups for the currently logged in user, this is in the session information. A team member's token or a project access token can access all the groups for all end users in the team or project.\n * @param {Object} options (Optional) Overrides for configuration options.\n * @return {Promise}\n */\n getUserGroups: function (params, options) {\n var adapterOptions = this.sessionManager.getMergedOptions({ success: $.noop }, options);\n var $d = $.Deferred();\n var outSuccess = adapterOptions.success;\n\n adapterOptions.success = function (memberInfo) {\n // The member API is at the account scope, we filter by project\n if (adapterOptions.project) {\n memberInfo = $.grep(memberInfo, function (group) {\n return group.project === adapterOptions.project;\n });\n }\n\n outSuccess.apply(this, [memberInfo]);\n $d.resolve(memberInfo);\n };\n\n var memberAdapter = new MemberAdapter({ token: params.token, server: adapterOptions.server });\n memberAdapter.getGroupsForUser(params, adapterOptions).fail($d.reject);\n return $d.promise();\n },\n\n /**\n * Helper method to check if you're currently logged in\n * @return {Boolean} true if you're logged in\n */\n isLoggedIn: function () {\n var session = this.getCurrentUserSessionInfo();\n return !!(session && session.userId);\n },\n\n /**\n * Returns session information for the current user, including the `userId`, `account`, `project`, `groupId`, `groupName`, `isFac` (whether the end user is a facilitator of this group), and `auth_token` (user access token).\n *\n * *Important*: This method is synchronous. The session information is returned immediately in an object; no callbacks or promises are needed.\n *\n * Session information is stored in a cookie in the browser.\n *\n * **Example**\n *\n * var sessionObj = authMgr.getCurrentUserSessionInfo();\n *\n * **Parameters**\n * @param {Object} options (Optional) Overrides for configuration options.\n * @return {Object} session information\n */\n getCurrentUserSessionInfo: function (options) {\n var adapterOptions = this.sessionManager.getMergedOptions({ success: $.noop }, options);\n return this.sessionManager.getSession(adapterOptions);\n },\n\n /*\n * Adds one or more groups to the current session. \n *\n * This method assumes that the project and group exist and the user specified in the session is part of this project and group.\n *\n * Returns the new session object.\n *\n * **Example**\n *\n * authMgr.addGroups({ project: 'hello-world', groupName: 'groupName', groupId: 'groupId' });\n * authMgr.addGroups([{ project: 'hello-world', groupName: 'groupName', groupId: 'groupId' }, { project: 'hello-world', groupName: '...' }]);\n *\n * **Parameters**\n * @param {object|array} groups (Required) The group object must contain the `project` (**Project ID**) and `groupName` properties. If passing an array of such objects, all of the objects must contain *different* `project` (**Project ID**) values: although end users may be logged in to multiple projects at once, they may only be logged in to one group per project at a time.\n * @param {string} group.isFac (optional) Defaults to `false`. Set to `true` if the user in the session should be a facilitator in this group.\n * @param {string} group.groupId (optional) Defaults to undefined. Needed mostly for the Members API.\n * @return {Object} session information\n */\n addGroups: function (groups) {\n var session = this.getCurrentUserSessionInfo();\n var isArray = Array.isArray(groups);\n groups = isArray ? groups : [groups];\n\n $.each(groups, function (index, group) {\n var extendedGroup = $.extend({}, { isFac: false }, group);\n var project = extendedGroup.project;\n var validProps = ['groupName', 'groupId', 'isFac'];\n if (!project || !extendedGroup.groupName) {\n throw new Error('No project or groupName specified.');\n }\n // filter object\n extendedGroup = _pick(extendedGroup, validProps);\n session.groups[project] = extendedGroup;\n });\n this.sessionManager.saveSession(session);\n return session;\n }\n});\n\nmodule.exports = AuthManager;\n","'use strict';\n\n/**\n * ## Channel Manager\n *\n * There are two main use cases for the channel: event notifications and chat messages.\n *\n * If you are developing with Epicenter.js, you should use the [Epicenter Channel Manager](../epicenter-channel-manager/) rather than this more generic Channel Manager. (The Epicenter Channel Manager is a wrapper that instantiates a Channel Manager with Epicenter-specific defaults.) The Epicenter Channel Manager documentation also has more [background](../epicenter-channel-manager/#background) information on channels and their use. \n *\n * However, you can work directly with the Channel Manager if you like. (This might be useful if you are working through Node.js, for example, `require('manager/channel-manager')`.)\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 * 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 a particular channel -- that is, an instance of a [Channel Service](../channel-service/) -- 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 * // because we used an Epicenter Channel Manager to get the group channel,\n * // subscribe() and publish() here default to the base topic for the group;\n * gc.subscribe('', function(data) { console.log(data); });\n * gc.publish('', { message: 'a new message to the group' });\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 */\n\nvar Channel = require('../service/channel-service');\nvar SessionManager = require('../store/session-manager');\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 `true`.\n * @type {boolean}\n */\n websocketEnabled: true,\n\n /**\n * Whether the ACK extension is enabled. Defaults to `true`. See [https://docs.cometd.org/current/reference/#_extensions_acknowledge](https://docs.cometd.org/current/reference/#_extensions_acknowledge) for more info.\n * @type {boolean}\n */\n ackEnabled: true,\n\n /**\n * If false each instance of Channel will have a separate cometd connection to server, which could be noisy. Set to true to re-use the same connection across instances.\n * @type {boolean}\n */\n shareConnection: false,\n\n /**\n * Other defaults to pass on to instances of the underlying [Channel Service](../channel-service/), which are created through `getChannel()`.\n * @type {object}\n */\n channel: {\n\n },\n\n /**\n * Options to pass to the channel handshake.\n *\n * For example, the [Epicenter Channel Manager](../epicenter-channel-manager/) passes `ext` and authorization information. More information on possible options is in the details of the underlying [Push Channel API](../../../rest_apis/multiplayer/channel/).\n *\n * @type {object}\n */\n handshake: undefined\n };\n this.sessionManager = new SessionManager();\n var defaultCometOptions = this.sessionManager.getMergedOptions(defaults, options);\n this.currentSubscriptions = [];\n this.options = defaultCometOptions;\n\n if (defaultCometOptions.shareConnection && ChannelManager.prototype._cometd) {\n this.cometd = ChannelManager.prototype._cometd;\n return this;\n }\n var cometd = new $.CometD();\n ChannelManager.prototype._cometd = cometd;\n\n cometd.websocketEnabled = defaultCometOptions.websocketEnabled;\n cometd.ackEnabled = defaultCometOptions.ackEnabled;\n\n this.isConnected = false;\n var connectionBroken = function (message) {\n $(this).trigger('disconnect', message);\n };\n var connectionSucceeded = function (message) {\n $(this).trigger('connect', message);\n };\n var me = this;\n\n cometd.configure(defaultCometOptions);\n\n cometd.addListener('/meta/connect', function (message) {\n var wasConnected = this.isConnected;\n this.isConnected = (message.successful === true);\n if (!wasConnected && this.isConnected) { //Connecting for the first time\n connectionSucceeded.call(this, message);\n } else if (wasConnected && !this.isConnected) { //Only throw disconnected message fro the first disconnect, not once per try\n connectionBroken.call(this, message);\n }\n }.bind(this));\n\n cometd.addListener('/meta/disconnect', connectionBroken);\n\n cometd.addListener('/meta/handshake', function (message) {\n if (message.successful) {\n //http://docs.cometd.org/reference/javascript_subscribe.html#javascript_subscribe_meta_channels\n // ^ \"dynamic subscriptions are cleared (like any other subscription) and the application needs to figure out which dynamic subscription must be performed again\"\n cometd.batch(function () {\n $(me.currentSubscriptions).each(function (index, subs) {\n cometd.resubscribe(subs);\n });\n });\n }\n });\n\n //Other interesting events for reference\n cometd.addListener('/meta/subscribe', function (message) {\n $(me).trigger('subscribe', message);\n });\n cometd.addListener('/meta/unsubscribe', function (message) {\n $(me).trigger('unsubscribe', message);\n });\n cometd.addListener('/meta/publish', function (message) {\n $(me).trigger('publish', message);\n });\n cometd.addListener('/meta/unsuccessful', function (message) {\n $(me).trigger('error', message);\n });\n\n cometd.handshake(defaultCometOptions.handshake);\n\n this.cometd = cometd;\n};\n\n\nChannelManager.prototype = $.extend(ChannelManager.prototype, {\n\n /**\n * Creates and returns a channel, that is, an instance of a [Channel Service](../channel-service/).\n *\n * **Example**\n *\n * var cm = new F.manager.ChannelManager();\n * var channel = cm.getChannel();\n *\n * channel.subscribe('topic', callback);\n * channel.publish('topic', { myData: 100 });\n *\n * **Parameters**\n * @param {Object|String} options (Optional) If string, assumed to be the base channel url. If object, assumed to be configuration options for the constructor.\n * @return {Channel} Channel instance\n */\n getChannel: function (options) {\n //If you just want to pass in a string\n if (options && !$.isPlainObject(options)) {\n options = {\n base: options\n };\n }\n var defaults = {\n transport: this.cometd\n };\n var channel = new Channel($.extend(true, {}, this.options.channel, defaults, options));\n\n\n //Wrap subs and unsubs so we can use it to re-attach handlers after being disconnected\n var subs = channel.subscribe;\n channel.subscribe = function () {\n var subid = subs.apply(channel, arguments);\n this.currentSubscriptions = this.currentSubscriptions.concat(subid);\n return subid;\n }.bind(this);\n\n\n var unsubs = channel.unsubscribe;\n channel.unsubscribe = function () {\n var removed = unsubs.apply(channel, arguments);\n for (var i = 0; i < this.currentSubscriptions.length; i++) {\n if (this.currentSubscriptions[i].id === removed.id) {\n this.currentSubscriptions.splice(i, 1);\n }\n }\n return removed;\n }.bind(this);\n\n return channel;\n },\n\n /**\n * Start listening for events on this instance. Signature is same as for jQuery Events: http://api.jquery.com/on/.\n *\n * Supported events are: `connect`, `disconnect`, `subscribe`, `unsubscribe`, `publish`, `error`.\n *\n * **Parameters**\n *\n * @param {string} event The event type. See more detail at jQuery Events: http://api.jquery.com/on/.\n */\n on: function (event) {\n $(this).on.apply($(this), arguments);\n },\n\n /**\n * Stop listening for events on this instance. Signature is same as for jQuery Events: http://api.jquery.com/off/.\n *\n * **Parameters**\n *\n * @param {string} event The event type. See more detail at jQuery Events: http://api.jquery.com/off/.\n */\n off: function (event) {\n $(this).off.apply($(this), arguments);\n },\n\n /**\n * Trigger events and execute handlers. Signature is same as for jQuery Events: http://api.jquery.com/trigger/.\n *\n * **Parameters**\n *\n * @param {string} event The event type. See more detail at jQuery Events: http://api.jquery.com/trigger/.\n */\n trigger: function (event) {\n $(this).trigger.apply($(this), arguments);\n }\n});\n\nmodule.exports = ChannelManager;\n","'use strict';\n\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).\n *\n * \n * ### Channel Background\n *\n * Channel notifications are only available for [team projects](../../../glossary/#team). There are two main use cases for the push channel: event notifications and chat messages.\n *\n * #### Event Notifications\n *\n * Within a [multiplayer simulation or world](../../../glossary/#world), it is often useful for your project's [model](../../../writing_your_model/) to alert the [user interface (browser)](../../../creating_your_interface/) that something new has happened.\n *\n * Usually, this \"something new\" is an event within the project, group, or world, such as:\n *\n * * An end user comes online (logs in) or goes offline. (This is especially interesting in a multiplayer world; only available if you have [enabled authorization](../../../updating_your_settings/#general-settings) for the channel.)\n * * An end user is assigned to a world.\n * * An end user updates a variable / makes a decision.\n * * An end user creates or updates data stored in the [Data API](../data-api-service/).\n * * An operation (method) is called. (This is especially interesting if the model is advanced, for instance, the Vensim `step` operation is called.)\n *\n * When these events occur, you often want to have the user interface for one or more end users automatically update with new information.\n *\n * #### Chat Messages\n *\n * Another reason to use the push channel is to allow players (end users) to send chat messages to other players, and to have those messages appear immediately.\n *\n * #### Getting Started\n *\n * For both the event notification and chat message use cases:\n *\n * * First, enable channel notifications for your project.\n * * Channel notifications are only available for [team projects](../../../glossary/#team). To enable notifications for your project, [update your project settings](../../../updating_your_settings/#general-settings) to turn on the **Push Channel** setting, and optionally require authorization for the channel.\n * * Then, instantiate an Epicenter Channel Manager.\n * * Next, get the channel with the scope you want (user, world, group, data).\n * * Finally, use the channel's `subscribe()` and `publish()` methods to subscribe to topics or publish data to topics.\n *\n * Here's an example of those last three steps (instantiate, get channel, subscribe):\n *\n * var cm = new F.manager.ChannelManager();\n * var gc = cm.getGroupChannel();\n * gc.subscribe('', function(data) { console.log(data); });\n * gc.publish('', { message: 'a new message to the group' });\n *\n * For a more detailed example, see a [complete publish and subscribe example](../../../rest_apis/multiplayer/channel/#epijs-example).\n *\n * For details on what data is published automatically to which channels, see [Automatic Publishing of Events](../../../rest_apis/multiplayer/channel/#publish-message-auto).\n *\n * #### Creating an Epicenter Channel Manager\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 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 * The parameters for instantiating an Epicenter Channel Manager include:\n *\n * * `options` Object with details about the Epicenter project for this Epicenter Channel Manager instance.\n * * `options.account` The Epicenter account id (**Team ID** for team projects, **User ID** for personal projects).\n * * `options.project` Epicenter project id.\n * * `options.userName` Epicenter userName used for authentication.\n * * `options.userId` Epicenter user id used for authentication. Optional; `options.userName` is preferred.\n * * `options.token` Epicenter token used for authentication. (You can retrieve this using `authManager.getToken()` from the [Authorization Manager](../auth-manager/).)\n * * `options.allowAllChannels` If not included or if set to `false`, all channel paths are validated; if your project requires [Push Channel Authorization](../../../updating_your_settings/), you should use this option. If you want to allow other channel paths, set to `true`; this is not common.\n */\n\nvar ChannelManager = require('./channel-manager');\nvar ConfigService = require('../service/configuration-service');\nvar classFrom = require('../util/inherit');\nvar SessionManager = require('../store/session-manager');\n\nvar validTypes = {\n project: true,\n group: true,\n world: true,\n user: true,\n data: true,\n general: true,\n chat: true\n};\nvar getFromSessionOrError = function (value, sessionKeyName, settings) {\n if (!value) {\n if (settings && settings[sessionKeyName]) {\n value = settings[sessionKeyName];\n } else {\n throw new Error(sessionKeyName + ' not found. Please log-in again, or specify ' + sessionKeyName + ' explicitly');\n }\n }\n return value;\n};\n\nvar isPresenceData = function (payload) {\n return payload.data && payload.data.type === 'user' && payload.data.user;\n};\n\nvar __super = ChannelManager.prototype;\nvar EpicenterChannelManager = classFrom(ChannelManager, {\n constructor: function (options) {\n this.sessionManager = new SessionManager(options);\n var defaultCometOptions = this.sessionManager.getMergedOptions(options);\n\n var urlConfig = new ConfigService(defaultCometOptions).get('server');\n if (!defaultCometOptions.url) {\n defaultCometOptions.url = urlConfig.getAPIPath('channel');\n }\n\n if (defaultCometOptions.handshake === undefined) {\n var userName = defaultCometOptions.userName;\n var userId = defaultCometOptions.userId;\n var token = defaultCometOptions.token;\n if ((userName || userId) && token) {\n var userProp = userName ? 'userName' : 'userId';\n var ext = {\n authorization: 'Bearer ' + token\n };\n ext[userProp] = userName ? userName : userId;\n\n defaultCometOptions.handshake = {\n ext: ext\n };\n }\n }\n\n this.options = defaultCometOptions;\n return __super.constructor.call(this, defaultCometOptions);\n },\n\n /**\n * Creates and returns a channel, that is, an instance of a [Channel Service](../channel-service/).\n *\n * This method enforces Epicenter-specific channel naming: all channels requested must be in the form `/{type}/{account id}/{project id}/{...}`, where `type` is one of `run`, `data`, `user`, `world`, or `chat`.\n *\n * **Example**\n *\n * var cm = new F.manager.EpicenterChannelManager();\n * var channel = cm.getChannel('/group/acme/supply-chain-game/');\n *\n * channel.subscribe('topic', callback);\n * channel.publish('topic', { myData: 100 });\n *\n * **Parameters**\n * @param {Object|String} options (Optional) If string, assumed to be the base channel url. If object, assumed to be configuration options for the constructor.\n * @return {Channel} Channel instance\n */\n getChannel: function (options) {\n if (options && typeof options !== 'object') {\n options = {\n base: options\n };\n }\n var channelOpts = $.extend({}, this.options, options);\n var base = channelOpts.base;\n if (!base) {\n throw new Error('No base topic was provided');\n }\n\n if (!channelOpts.allowAllChannels) {\n var baseParts = base.split('/');\n var channelType = baseParts[1];\n if (baseParts.length < 4) { //eslint-disable-line\n throw new Error('Invalid channel base name, it must be in the form /{type}/{account id}/{project id}/{...}');\n }\n if (!validTypes[channelType]) {\n throw new Error('Invalid channel type');\n }\n }\n return __super.getChannel.apply(this, arguments);\n },\n\n /**\n * Create and return a publish/subscribe channel (from the underlying [Channel Manager](../channel-manager/)) for the given [group](../../../glossary/#groups). The group must exist in the account (team) and project provided.\n *\n * There are no notifications from Epicenter on this channel; all messages are user-originated.\n *\n * **Example**\n *\n * var cm = new F.manager.ChannelManager();\n * var gc = cm.getGroupChannel();\n * gc.subscribe('broadcasts', callback);\n *\n * **Return Value**\n *\n * * *Channel* Returns the channel (an instance of the [Channel Service](../channel-service/)).\n *\n * **Parameters**\n *\n * @param {String} groupName (Optional) Group to broadcast to. If not provided, picks up group from current session if end user is logged in.\n * @return {Channel} Channel instance\n */\n getGroupChannel: function (groupName) {\n var session = this.sessionManager.getMergedOptions(this.options);\n groupName = getFromSessionOrError(groupName, 'groupName', session);\n var account = getFromSessionOrError('', 'account', session);\n var project = getFromSessionOrError('', 'project', session);\n\n var baseTopic = ['/group', account, project, groupName].join('/');\n var channel = __super.getChannel.call(this, { base: baseTopic });\n var oldsubs = channel.subscribe;\n channel.subscribe = function (topic, callback, context, options) {\n var callbackWithoutPresenceData = function (payload) {\n if (!isPresenceData(payload)) {\n callback.call(context, payload);\n }\n };\n return oldsubs.call(channel, topic, callbackWithoutPresenceData, context, options);\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 [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 * @return {Channel} Channel instance\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 var session = this.sessionManager.getMergedOptions(this.options);\n\n groupName = getFromSessionOrError(groupName, 'groupName', session);\n var account = getFromSessionOrError('', 'account', session);\n var project = getFromSessionOrError('', 'project', session);\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 * @return {Channel} Channel instance\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 session = this.sessionManager.getMergedOptions(this.options);\n\n var userid = ($.isPlainObject(user) && user.id) ? user.id : user;\n userid = getFromSessionOrError(userid, 'userId', session);\n groupName = getFromSessionOrError(groupName, 'groupName', session);\n\n var account = getFromSessionOrError('', 'account', session);\n var project = getFromSessionOrError('', 'project', session);\n\n var baseTopic = ['/user', account, project, groupName, worldid, userid].join('/');\n return __super.getChannel.call(this, { base: baseTopic });\n },\n\n /**\n * Create and return a publish/subscribe channel (from the underlying [Channel Manager](../channel-manager/)) that automatically tracks the presence of an [end user](../../../glossary/#users), that is, whether the end user is currently online in this group. 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 group are also online.\n *\n * Note that the presence channel is tracking all end users in a group. In particular, if the project additionally splits each group into [worlds](../world-manager/), this channel continues to show notifications for all end users in the group (not restricted by worlds).\n *\n * **Example**\n *\n * var cm = new F.manager.ChannelManager();\n * var pc = cm.getPresenceChannel();\n * pc.subscribe('', function (data) {\n * // 'data' is the entire message object to the channel;\n * // parse for information of interest\n * if (data.data.subType === 'disconnect') {\n * console.log('user ', data.data.user.userName, 'disconnected at ', data.data.date);\n * }\n * if (data.data.subType === 'connect') {\n * console.log('user ', data.data.user.userName, 'connected at ', data.data.date);\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} groupName (Optional) Group the end user is in. If not provided, picks up group from current session if end user is logged in.\n * @return {Channel} Channel instance\n */\n getPresenceChannel: function (groupName) {\n var session = this.sessionManager.getMergedOptions(this.options);\n groupName = getFromSessionOrError(groupName, 'groupName', session);\n var account = getFromSessionOrError('', 'account', session);\n var project = getFromSessionOrError('', 'project', session);\n\n var baseTopic = ['/group', account, project, groupName].join('/');\n var channel = __super.getChannel.call(this, { base: baseTopic });\n var oldsubs = channel.subscribe;\n channel.subscribe = function (topic, callback, context, options) {\n var callbackWithOnlyPresenceData = function (payload) {\n if (isPresenceData(payload)) {\n callback.call(context, payload);\n }\n };\n return oldsubs.call(channel, topic, callbackWithOnlyPresenceData, context, options);\n };\n return channel;\n },\n\n /**\n * Create and return a publish/subscribe channel (from the underlying [Channel Manager](../channel-manager/)) for the given collection. (The collection name is specified in the `root` argument when the [Data Service](../data-api-service/) is instantiated.) Must be one of the collections in this account (team) and project.\n *\n * There are automatic notifications from Epicenter on this channel when data is created, updated, or deleted in this collection. See more on [automatic messages to the data channel](../../../rest_apis/multiplayer/channel/#data-messages).\n *\n * **Example**\n *\n * var cm = new F.manager.ChannelManager();\n * var dc = cm.getDataChannel('survey-responses');\n * dc.subscribe('', function(data, meta) {\n * console.log(data);\n *\n * // meta.date is time of change,\n * // meta.subType is the kind of change: new, update, or delete\n * // meta.path is the full path to the changed data\n * console.log(meta);\n * });\n *\n * **Return Value**\n *\n * * *Channel* Returns the channel (an instance of the [Channel Service](../channel-service/)).\n *\n * **Parameters**\n *\n * @param {String} collection Name of collection whose automatic notifications you want to receive.\n * @return {Channel} Channel instance\n */\n getDataChannel: function (collection) {\n if (!collection) {\n throw new Error('Please specify a collection to listen on.');\n }\n\n var session = this.sessionManager.getMergedOptions(this.options);\n var account = getFromSessionOrError('', 'account', session);\n var project = getFromSessionOrError('', 'project', session);\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 dataPath: payload.data.data.path,\n };\n var actualData = payload.data.data;\n if (actualData.data !== undefined) { //Delete notifications are one data-level behind of course\n actualData = actualData.data;\n }\n\n callback.call(context, actualData, meta);\n };\n return oldsubs.call(channel, topic, callbackWithCleanData, context, options);\n };\n\n return channel;\n }\n});\n\nmodule.exports = EpicenterChannelManager;\n","'use strict';\n\nmodule.exports = {\n EPI_SESSION_KEY: 'epicenterjs.session',\n STRATEGY_SESSION_KEY: 'epicenter-scenario'\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)](../strategies/) 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/) and the RESFTful [Run API](../../../rest_apis/aggregate_run_api). 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.\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 optionally pass a `files` object with the names of the files, for example: `\"files\": {\"data\": \"myExtraData.xls\"}`. (See more on [Using External Data in Vensim](../../../model_code/vensim/vensim_example_xls/).)\n*\n* * `strategy`: (optional) Run creation strategy for when to create a new run and when to reuse an end user's existing run. This is *optional*; by default, the Run Manager selects `reuse-per-session`, or `reuse-last-initialized` if you also pass in an initial operation. See [below](#using-the-run-manager-to-access-and-register-strategies) for more information on strategies.\n*\n* * `strategyOptions`: (optional) Additional options passed directly to the [run creation strategy](../strategies/).\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. This can also be a function which returns a string, if you'd like to control this at runtime.\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: 'reuse-never',\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* ### Using the Run Manager to access and register strategies\n*\n* The `strategy` for a Run Manager describes when to create a new run and when to reuse an end user's existing run. The Run Manager is responsible for passing a strategy everything it might need to determine the 'correct' run, that is, how to find the best existing run and how to decide when to create a new run.\n*\n* There are several common strategies provided as part of Epicenter.js, which you can list by accessing `F.manager.RunManager.strategies`. You can also create your own strategies, and register them to use with Run Managers. See [Run Manager Strategies](../strategies/) for details.\n* \n*/\n\n'use strict';\nvar strategies = require('./run-strategies');\nvar specialOperations = require('./special-operations');\n\nvar RunService = require('../service/run-api-service');\nvar SessionManager = require('../store/session-manager');\n\nvar util = require('../util/object-util');\nvar keyNames = require('./key-names');\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\nfunction sessionKeyFromOptions(options, runService) {\n var config = runService.getCurrentConfig();\n var sessionKey = $.isFunction(options.sessionKey) ? options.sessionKey(config) : options.sessionKey;\n return sessionKey;\n}\n\nfunction setRunInSession(sessionKey, run, sessionManager) {\n if (sessionKey) {\n delete run.variables;\n sessionManager.getStore().set(sessionKey, JSON.stringify(run));\n }\n}\n\nvar defaults = {\n sessionKey: function (config) { \n var baseKey = keyNames.STRATEGY_SESSION_KEY;\n var key = ['account', 'project', 'model'].reduce(function (accum, key) {\n return config[key] ? accum + '-' + config[key] : accum; \n }, baseKey);\n return key;\n }\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 if (!util.isEmpty(this.options.run)) {\n this.run = new RunService(this.options.run);\n } else {\n throw new Error('No run options passed to RunManager');\n }\n patchRunService(this.run, this);\n\n this.strategy = strategies.getBestStrategy(this.options);\n this.sessionManager = new SessionManager(this.options);\n}\n\nRunManager.prototype = {\n /**\n * Returns the run object for the 'correct' run. The correct run is defined by the strategy. \n *\n * For example, if the strategy is `reuse-never`, the call\n * to `getRun()` always returns a newly created run; if the strategy is `reuse-per-session`,\n * `getRun()` returns the run currently referenced in the browser cookie, and if there is none, creates a new run. \n * See [Run Manager Strategies](../strategies/) 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 * rm.getRun(['sample_int']).then(function (run) {\n * // an object whose fields are the name : value pairs of the variables passed to getRun()\n * console.log(run.variables);\n * // the value of sample_int\n * console.log(run.variables.sample_int); \n * });\n *\n * @param {Array} variables (Optional) The run object is populated with the provided model variables, if provided. Note: `getRun()` does not throw an error if you try to get a variable which doesn't exist. Instead, the variables list is empty, and any errors are logged to the console.\n * @param {Object} options (Optional) Configuration options; passed on to [RunService#create](../run-api-service/#create) if the strategy does create a new run.\n * @return {$promise} Promise to complete the call.\n */\n getRun: function (variables, options) {\n var me = this;\n var sessionStore = this.sessionManager.getStore();\n\n var sessionContents = sessionStore.get(sessionKeyFromOptions(this.options, me.run));\n var runSession = JSON.parse(sessionContents || '{}');\n \n if (runSession.runId) {\n //EpiJS < 2.2 used runId as key, so maintain comptaibility. Remove at some future date (Summer `17?)\n runSession.id = runSession.runId;\n }\n\n var authSession = this.sessionManager.getSession();\n if (this.strategy.requiresAuth && util.isEmpty(authSession)) {\n console.error('No user-session available', this.options.strategy, 'requires authentication.');\n return $.Deferred().reject('No user-session available').promise();\n }\n return this.strategy\n .getRun(this.run, authSession, runSession, options).then(function (run) {\n if (run && run.id) {\n me.run.updateConfig({ filter: run.id });\n var sessionKey = sessionKeyFromOptions(me.options, me.run);\n setRunInSession(sessionKey, run, me.sessionManager);\n\n if (variables && variables.length) {\n return me.run.variables().query(variables).then(function (results) {\n run.variables = results;\n return run;\n }).catch(function (err) {\n run.variables = {};\n console.error(err);\n return run;\n });\n }\n }\n return run;\n });\n },\n\n /**\n * Returns the run object for a 'reset' run. The definition of a reset is defined by the strategy, but typically means forcing the creation of a new run. For example, `reset()` for the default strategies `reuse-per-session` and `reuse-last-initialized` both create new runs.\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} options (Optional) Configuration options; passed on to [RunService#create](../run-api-service/#create).\n * @return {Promise}\n */\n reset: function (options) {\n var me = this;\n var authSession = this.sessionManager.getSession();\n if (this.strategy.requiresAuth && util.isEmpty(authSession)) {\n console.error('No user-session available', this.options.strategy, 'requires authentication.');\n return $.Deferred().reject('No user-session available').promise();\n }\n return this.strategy.reset(this.run, authSession, options).then(function (run) {\n if (run && run.id) {\n me.run.updateConfig({ filter: run.id });\n var sessionKey = sessionKeyFromOptions(me.options, me.run);\n setRunInSession(sessionKey, run.id, me.sessionManager);\n }\n return run;\n });\n }\n};\n\nRunManager.strategies = strategies;\nmodule.exports = RunManager;\n","'use strict';\n\nvar Base = require('./none-strategy');\nvar classFrom = require('../../util/inherit');\n\n/**\n* ## Conditional Creation Strategy\n*\n* This strategy will try to get the run stored in the cookie and\n* evaluate if it needs to create a new run by calling the `condition` function.\n*/\n\nvar Strategy = classFrom(Base, {\n constructor: function Strategy(condition) {\n if (condition == null) { //eslint-disable-line\n throw new Error('Conditional strategy needs a condition to create a run');\n }\n this.condition = typeof condition !== 'function' ? function () { return condition; } : condition;\n },\n\n /**\n * Gets a new 'correct' run, or updates the existing one (the definition of 'correct' depends on strategy implementation).\n * @param {RunService} runService A Run Service instance for the current run, as determined by the Run Manager.\n * @param {Object} userSession Information about the current user session. See [AuthManager#getCurrentUserSessionInfo](../auth-manager/#getcurrentusersessioninfo) for format.\n * @param {Object} options (Optional) See [RunService#create](../run-api-service/#create) for supported options.\n * @return {Promise} \n */\n reset: function (runService, userSession, options) {\n var group = userSession && userSession.groupName;\n var opt = $.extend({\n scope: { group: group }\n }, runService.getCurrentConfig());\n\n return runService\n .create(opt, options)\n .then(function (run) {\n run.freshlyCreated = true;\n return run;\n });\n },\n\n /**\n * Gets the 'correct' run (the definition of 'correct' depends on strategy implementation).\n * @param {RunService} runService A Run Service instance for the current run, as determined by the Run Manager.\n * @param {Object} userSession Information about the current user session. See [AuthManager#getCurrentUserSessionInfo](../auth-manager/#getcurrentusersessioninfo) for format.\n * @param {Object} runSession The Run Manager stores the 'last accessed' run in a cookie and passes it back here.\n * @param {Object} options (Optional) See [RunService#create](../run-api-service/#create) for supported options.\n * @return {Promise} \n */\n getRun: function (runService, userSession, runSession, options) {\n var me = this;\n if (runSession && runSession.id) {\n return this.loadAndCheck(runService, userSession, runSession, options).catch(function () {\n return me.reset(runService, userSession, options); //if it got the wrong cookie for e.g.\n });\n } else {\n return this.reset(runService, userSession, options);\n }\n },\n\n loadAndCheck: function (runService, userSession, runSession, options) {\n var shouldCreate = false;\n var me = this;\n\n return runService\n .load(runSession.id, null, {\n success: function (run, msg, headers) {\n shouldCreate = me.condition(run, headers, userSession, runSession);\n }\n })\n .then(function (run) {\n if (shouldCreate) {\n return me.reset(runService, userSession, options);\n }\n return run;\n });\n }\n});\n\nmodule.exports = Strategy;\n","/**\n * The `new-if-initialized` strategy creates a new run if the current one is in memory or has its `initialized` field set to `true`. The `initialized` field in the run record is automatically set to `true` at run creation, but can be changed.\n * \n * This strategy is useful if your project is structured such that immediately after a run is created, the model is executed completely (for example, a Vensim model is stepped to the end). It is similar to the `new-if-missing` strategy, except that it checks a field of the run record.\n * \n * Specifically, the strategy is:\n *\n * * Check the `sessionKey` cookie. \n * * This cookie is set by the [Run Manager](../run-manager/) and configurable through its options.\n * * If the cookie exists, check whether the run is in memory or only persisted in the database. Additionally, check whether the run's `initialized` field is `true`. \n * * If the run is in memory, create a new run.\n * * If the run's `initialized` field is `true`, create a new run.\n * * Otherwise, use the existing run.\n * * If the cookie does not exist, create a new run for this end user.\n * \n * @deprecated Consider using `reuse-last-initialized` instead\n */\n\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 (options) {\n __super.constructor.call(this, this.createIf, options);\n console.warn('This strategy is deprecated; all runs now default to being initialized by default making this redundant. Consider using `reuse-last-initialized` instead.');\n },\n\n createIf: function (run, headers) {\n return headers.getResponseHeader('pragma') === 'persistent' || run.initialized;\n }\n});\n\nmodule.exports = Strategy;\n","/**\n * The `new-if-persisted` strategy creates a new run when the current one becomes persisted (end user is idle for a set period), but otherwise uses the current one. \n * \n * Using this strategy means that when end users navigate between pages in your project, or refresh their browsers, they will still be working with the same run. \n * \n * However, if they are idle for longer than your project's **Model Session Timeout** (configured in your project's [Settings](../../../updating_your_settings/)), then their run is persisted; the next time they interact with the project, they will get a new run. (See more background on [Run Persistence](../../../run_persistence/).)\n * \n * This strategy is useful for multi-page projects where end users play through a simulation in one sitting, stepping through the model sequentially (for example, a Vensim model that uses the `step` operation) or calling specific functions until the model is \"complete.\" However, you will need to guarantee that your end users will remain engaged with the project from beginning to end — or at least, that if they are idle for longer than the **Model Session Timeout**, it is okay for them to start the project from scratch (with an uninitialized model). \n * \n * Specifically, the strategy is:\n *\n * * Check the `sessionKey` cookie.\n * * This cookie is set by the [Run Manager](../run-manager/) and configurable through its options.\n * * If the cookie exists, check whether the run is in memory or only persisted in the database. \n * * If the run is in memory, use the run.\n * * If the run is only persisted (and not still in memory), create a new run for this end user.\n * * If the cookie does not exist, create a new run for this end user.\n *\n * @deprecated The run-service now sets a header to automatically bring back runs into memory\n */\n\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 (options) {\n __super.constructor.call(this, this.createIf, options);\n console.warn('This strategy is deprecated; the run-service now sets a header to automatically bring back runs into memory');\n },\n\n createIf: function (run, headers) {\n return headers.getResponseHeader('pragma') === 'persistent';\n }\n});\n\nmodule.exports = Strategy;\n","/**\n * ### Working with Run Strategies\n *\n * You can access a list of available strategies using `F.manager.RunManager.strategies.list`. You can also ask for a particular strategy by name.\n *\n * If you decide to [create your own run strategy](#create-your-own), you can register your strategy. Registering your strategy means that:\n *\n * * You can pass the strategy by name to a Run Manager (as opposed to passing the strategy function): `new F.manager.RunManager({ strategy: 'mynewname'})`.\n * * You can pass configuration options to your strategy.\n * * You can specify whether or not your strategy requires authorization (a valid user session) to work.\n */\n\n\nvar list = {\n 'conditional-creation': require('./conditional-creation-strategy'),\n 'new-if-initialized': require('./deprecated/new-if-initialized-strategy'), //deprecated\n 'new-if-persisted': require('./deprecated/new-if-persisted-strategy'), //deprecated\n\n none: require('./none-strategy'),\n\n multiplayer: require('./multiplayer-strategy'),\n 'reuse-never': require('./reuse-never'),\n 'reuse-per-session': require('./reuse-per-session'),\n 'reuse-across-sessions': require('./reuse-across-sessions'),\n 'reuse-last-initialized': require('./reuse-last-initialized'),\n};\n\n//Add back older aliases\nlist['always-new'] = list['reuse-never'];\nlist['new-if-missing'] = list['reuse-per-session'];\nlist['persistent-single-player'] = list['reuse-across-sessions'];\n\n\nmodule.exports = {\n /**\n * List of available strategies. Within this object, each key is the strategy name and the associated value is the strategy constructor.\n * @type {Object} \n */\n list: list,\n\n /**\n * Gets strategy by name.\n *\n * **Example**\n *\n * var reuseStrat = F.manager.RunManager.strategies.byName('reuse-across-sessions');\n * // shows strategy function\n * console.log('reuseStrat = ', reuseStrat);\n * // create a new run manager using this strategy\n * var rm = new F.manager.RunManager({strategy: reuseStrat, run: { model: 'model.vmf'} });\n *\n * **Parameters**\n * @param {String} strategyName Name of strategy to get.\n * @return {Function} Strategy function.\n */\n byName: function (strategyName) {\n return list[strategyName];\n },\n\n getBestStrategy: function (options) {\n var strategy = options.strategy;\n if (!strategy) {\n if (options.strategyOptions && options.strategyOptions.initOperation) {\n strategy = 'reuse-last-initialized';\n } else {\n strategy = 'reuse-per-session';\n }\n }\n\n if (strategy.getRun) {\n return strategy;\n }\n var StrategyCtor = typeof strategy === 'function' ? strategy : this.byName(strategy);\n if (!StrategyCtor) {\n throw new Error('Specified run creation strategy was invalid:', strategy);\n }\n\n var strategyInstance = new StrategyCtor(options);\n if (!strategyInstance.getRun || !strategyInstance.reset) {\n throw new Error('All strategies should implement a `getRun` and `reset` interface', options.strategy);\n }\n strategyInstance.requiresAuth = StrategyCtor.requiresAuth;\n\n return strategyInstance;\n },\n\n /**\n * Adds a new strategy.\n *\n * **Example**\n *\n * // this \"favorite run\" strategy always returns the same run, no matter what\n * // (not a useful strategy, except as an example)\n * F.manager.RunManager.strategies.register(\n * 'favRun', \n * function() { \n * return { getRun: function() { return '0000015a4cd1700209cd0a7d207f44bac289'; },\n * reset: function() { return '0000015a4cd1700209cd0a7d207f44bac289'; } \n * } \n * }, \n * { requiresAuth: true }\n * );\n * \n * var rm = new F.manager.RunManager({strategy: 'favRun', run: { model: 'model.vmf'} });\n *\n * **Parameters**\n * @param {String} name Name for strategy. This string can then be passed to a Run Manager as `new F.manager.RunManager({ strategy: 'mynewname'})`.\n * @param {Function} strategy The strategy constructor. Will be called with `new` on Run Manager initialization.\n * @param {Object} options Options for strategy.\n * @param {Boolean} options.requiresAuth Specify if the strategy requires a valid user session to work.\n */\n register: function (name, strategy, options) {\n strategy.options = options;\n list[name] = strategy;\n }\n};","/**\n * The `multiplayer` strategy is for use with [multiplayer worlds](../../../glossary/#world). It checks the current world for this end user, and always returns the current run for that world. This is equivalent to calling `getCurrentWorldForUser()` and then `getCurrentRunId()` from the [World API Adapater](../world-api-adapter/). If you use the [World Manager](../world-manager/), you are automatically using this strategy.\n * \n * Using this strategy means that end users in projects with multiplayer worlds always see the most current world and run. This ensures that they are in sync with the other end users sharing their world and run. In turn, this allows for competitive or collaborative multiplayer projects.\n */\n'use strict';\n\nvar classFrom = require('../../util/inherit');\n\nvar IdentityStrategy = require('./none-strategy');\nvar WorldApiAdapter = require('../../service/world-api-adapter');\n\nvar defaults = {};\n\nvar Strategy = classFrom(IdentityStrategy, {\n constructor: function (options) {\n this.options = $.extend(true, {}, defaults, options);\n this.worldApi = new WorldApiAdapter(this.options.run);\n },\n\n reset: function (runService, session, options) {\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, options).then(function (runid) {\n return {\n id: runid\n };\n });\n }.bind(this));\n },\n\n getRun: function (runService, session) {\n var curUserId = session.userId;\n var curGroupName = session.groupName;\n var worldApi = this.worldApi;\n var model = this.options.model;\n var me = 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: me.options, session: session });\n }\n return worldApi.getCurrentRunId({ model: model, filter: world.id })\n .then(function (id) {\n return runService.load(id);\n })\n .then(dtd.resolve)\n .fail(dtd.reject);\n };\n\n var serverError = function (error) {\n // is this possible?\n return dtd.reject(error, session, me.options);\n };\n\n this.worldApi\n .getCurrentWorldForUser(curUserId, curGroupName)\n .then(loadRunFromWorld)\n .fail(serverError);\n\n return dtd.promise();\n },\n\n});\n\nmodule.exports = Strategy;\n","/**\n * The `none` strategy never returns a run or tries to create a new run. It simply returns the contents of the current [Run Service instance](../run-api-service/).\n * \n * This strategy is useful if you want to manually decide how to create your own runs and don't want any automatic assistance.\n */\n\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 (options) {\n\n },\n\n reset: function () {\n // return a newly created run\n return $.Deferred().resolve().promise();\n },\n\n getRun: function (runService) {\n // return a usable run\n return $.Deferred().resolve(runService).promise();\n }\n});\n","/**\n * The `reuse-across-sessions` strategy returns the latest (most recent) run for this user, whether it is in memory or not. If there are no runs for this user, it creates a new one.\n *\n * This strategy is useful if end users are using your project for an extended period of time, possibly over several sessions. This is most common in cases where a user of your project executes the model step by step (as opposed to a project where the model is executed completely, for example, a Vensim model that is immediately stepped to the end).\n *\n * Specifically, the strategy is:\n * \n * * Check if there are any runs for this end user.\n * * If there are no runs (either in memory or in the database), create a new one.\n * * If there are runs, take the latest (most recent) one.\n *\n * @name persistent-single-player\n */\n\n'use strict';\n\nvar classFrom = require('../../util/inherit');\nvar IdentityStrategy = require('./none-strategy');\nvar injectFiltersFromSession = require('../strategy-utils').injectFiltersFromSession;\nvar injectScopeFromSession = require('../strategy-utils').injectScopeFromSession;\n\nvar defaults = {\n /**\n * (Optional) Additional criteria to use while selecting the last run\n * @type {Object}\n */\n filter: {},\n};\n\nvar Strategy = classFrom(IdentityStrategy, {\n constructor: function Strategy(options) {\n var strategyOptions = options ? options.strategyOptions : {};\n this.options = $.extend(true, {}, defaults, strategyOptions);\n },\n\n reset: function (runService, userSession, options) {\n var opt = injectScopeFromSession(runService.getCurrentConfig(), userSession);\n return runService\n .create(opt, options)\n .then(function (run) {\n run.freshlyCreated = true;\n return run;\n });\n },\n\n getRun: function (runService, userSession, runSession, options) {\n var filter = injectFiltersFromSession(this.options.filter, userSession);\n var me = this;\n return runService.query(filter, { \n // startrecord: 0, //TODO: Uncomment when EPICENTER-2569 is fixed\n // endrecord: 0,\n sort: 'created', \n direction: 'desc'\n }).then(function (runs) {\n if (!runs.length) {\n return me.reset(runService, userSession, options);\n }\n return runs[0];\n });\n }\n});\n\nmodule.exports = Strategy;\n","/**\n * The `reuse-last-initialized` strategy looks for the most recent run that matches particular criteria; if it cannot find one, it creates a new run and immediately executes a set of \"initialization\" operations. \n *\n * This strategy is useful if you have a time-based model and always want the run you're operating on to start at a particular step. For example:\n *\n * var rm = new F.manager.RunManager({\n * strategy: 'reuse-last-initialized',\n * strategyOptions: {\n * initOperation: [{ step: 10 }]\n * }\n * });\n * \n * This strategy is also useful if you have a custom initialization function in your model, and want to make sure it's always executed for new runs.\n *\n * Specifically, the strategy is:\n *\n * * Look for the most recent run that matches the (optional) `flag` criteria\n * * If there are no runs that match the `flag` criteria, create a new run. Immediately \"initialize\" this new run by:\n * * Calling the model operation(s) specified in the `initOperation` array.\n * * Optionally, setting a `flag` in the run.\n *\n */\n\n'use strict';\nvar classFrom = require('../../util/inherit');\nvar injectFiltersFromSession = require('../strategy-utils').injectFiltersFromSession;\nvar injectScopeFromSession = require('../strategy-utils').injectScopeFromSession;\n\nvar Base = {};\n\nvar defaults = {\n /**\n * Operations to execute in the model for initialization to be considered complete.\n * @type {Array} Can be in any of the formats [Run Service's `serial()`](../run-api-service/#serial) supports.\n */\n initOperation: [],\n\n /**\n * (Optional) Flag to set in run after initialization operations are run. You typically would not override this unless you needed to set additional properties as well.\n * @type {Object}\n */\n flag: null,\n};\nmodule.exports = classFrom(Base, {\n constructor: function (options) {\n var strategyOptions = options ? options.strategyOptions : {};\n this.options = $.extend(true, {}, defaults, strategyOptions);\n if (!this.options.initOperation || !this.options.initOperation.length) {\n throw new Error('Specifying an init function is required for this strategy');\n }\n if (!this.options.flag) {\n this.options.flag = {\n isInitComplete: true\n };\n }\n },\n\n reset: function (runService, userSession, options) {\n var opt = injectScopeFromSession(runService.getCurrentConfig(), userSession);\n var me = this;\n return runService.create(opt, options).then(function (createResponse) {\n return runService.serial([].concat(me.options.initOperation)).then(function () {\n return createResponse;\n });\n }).then(function (createResponse) {\n return runService.save(me.options.flag).then(function (patchResponse) {\n return $.extend(true, {}, createResponse, patchResponse);\n });\n });\n },\n\n getRun: function (runService, userSession, runSession, options) {\n var sessionFilter = injectFiltersFromSession(this.options.flag, userSession);\n var runopts = runService.getCurrentConfig();\n var filter = $.extend(true, { trashed: false }, sessionFilter, { model: runopts.model });\n var me = this;\n return runService.query(filter, { \n // startrecord: 0, //TODO: Uncomment when EPICENTER-2569 is fixed\n // endrecord: 0,\n sort: 'created', \n direction: 'desc'\n }).then(function (runs) {\n if (!runs.length) {\n return me.reset(runService, userSession, options);\n }\n return runs[0];\n });\n }\n});","/**\n * The `reuse-never` strategy always creates a new run for this end user irrespective of current state. This is equivalent to calling `F.service.Run.create()` from the [Run Service](../run-api-service/) every time. \n * \n * This strategy means that every time your end users refresh their browsers, they get a new run. \n * \n * This strategy can be useful for basic, single-page projects. This strategy is also useful for prototyping or project development: it creates a new run each time you refresh the page, and you can easily check the outputs of the model. However, typically you will use one of the other strategies for a production project.\n *\n * @name always-new\n */\n\n'use strict';\n\nvar classFrom = require('../../util/inherit');\nvar ConditionalStrategy = require('./conditional-creation-strategy');\n\nvar __super = ConditionalStrategy.prototype;\n\nvar Strategy = classFrom(ConditionalStrategy, {\n constructor: function (options) {\n __super.constructor.call(this, 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","/**\n * The `reuse-per-session` strategy creates a new run when the current one is not in the browser cookie.\n * \n * Using this strategy means that when end users navigate between pages in your project, or refresh their browsers, they will still be working with the same run. However, if end users log out and return to the project at a later date, a new run is created.\n *\n * This strategy is useful if your project is structured such that immediately after a run is created, the model is executed completely (for example, a Vensim model that is stepped to the end as soon as it is created). In contrast, if end users play with your project for an extended period of time, executing the model step by step, the `reuse-across-sessions` strategy is probably a better choice (it allows end users to pick up where they left off, rather than starting from scratch each browser session).\n * \n * Specifically, the strategy is:\n *\n * * Check the `sessionKey` cookie.\n * * This cookie is set by the [Run Manager](../run-manager/) and configurable through its options. \n * * If the cookie exists, use the run id stored there. \n * * If the cookie does not exist, create a new run for this end user.\n *\n * @name new-if-missing\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 (options) {\n __super.constructor.call(this, 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","/**\n * ## Saved Runs Manager\n *\n * The Saved Runs Manager is a specific type of [Run Manager](../../run-manager/) which provides access to a list of runs (rather than just one run). It also provides utility functions for dealing with multiple runs (e.g. saving, deleting, listing).\n *\n * An instance of a Saved Runs Manager is included automatically in every instance of a [Scenario Manager](../), and is accessible from the Scenario Manager at `.savedRuns`. See [more information](../#properties) on using `.savedRuns` within the Scenario Manager.\n *\n */\n'use strict';\n\nvar RunService = require('../service/run-api-service');\nvar SessionManager = require('../store/session-manager');\n\nvar injectFiltersFromSession = require('./strategy-utils').injectFiltersFromSession;\n\nvar SavedRunsManager = function (config) {\n var defaults = {\n /**\n * If set, will only pull runs from current group. Defaults to `true`.\n * @type {Boolean}\n */\n scopeByGroup: true,\n\n /**\n * If set, will only pull runs from current user. Defaults to `true`.\n *\n * For multiplayer run comparison projects, set this to false so that all end users in a group can view the shared set of saved runs.\n * @type {Boolean}\n */\n scopeByUser: true,\n };\n\n this.sessionManager = new SessionManager();\n\n var options = $.extend(true, {}, defaults, config);\n if (options.run) {\n if (options.run instanceof RunService) {\n this.runService = options.run;\n } else {\n this.runService = new RunService(options.run);\n }\n this.options = options;\n } else {\n throw new Error('No run options passed to SavedRunsManager');\n }\n};\n\nSavedRunsManager.prototype = {\n /**\n * Marks a run as saved. \n *\n * Note that while any run can be saved, only runs which also match the configuration options `scopeByGroup` and `scopeByUser` are returned by the `getRuns()` method.\n *\n * **Example**\n *\n * var sm = new F.manager.ScenarioManager();\n * sm.savedRuns.save('0000015a4cd1700209cd0a7d207f44bac289');\n *\n * @param {String|RunService} run Run to save. Pass in either the run id, as a string, or the [Run Service](../../run-api-service/).\n * @param {Object} otherFields (Optional) Any other meta-data to save with the run.\n * @return {Promise}\n */\n save: function (run, otherFields) {\n var param = $.extend(true, {}, otherFields, { saved: true, trashed: false });\n return this.mark(run, param);\n },\n /**\n * Marks a run as removed; the inverse of marking as saved.\n *\n * **Example**\n *\n * var sm = new F.manager.ScenarioManager();\n * sm.savedRuns.remove('0000015a4cd1700209cd0a7d207f44bac289');\n *\n * @param {String|RunService} run Run to remove. Pass in either the run id, as a string, or the [Run Service](../../run-api-service/).\n * @param {Object} otherFields (Optional) any other meta-data to save with the run.\n * @return {Promise}\n */\n remove: function (run, otherFields) {\n var param = $.extend(true, {}, otherFields, { saved: false, trashed: true });\n return this.mark(run, param);\n },\n\n\n /**\n * Sets additional fields on a run. This is a convenience method for [RunService#save](../../run-api-service/#save).\n *\n * **Example**\n *\n * var sm = new F.manager.ScenarioManager();\n * sm.savedRuns.mark('0000015a4cd1700209cd0a7d207f44bac289', \n * { 'myRunName': 'sample policy decisions' });\n *\n * @param {String|RunService} run Run to operate on. Pass in either the run id, as a string, or the [Run Service](../../run-api-service/).\n * @param {Object} toMark Fields to set, as name : value pairs.\n * @return {Promise}\n */\n mark: function (run, toMark) {\n var rs;\n var existingOptions = this.runService.getCurrentConfig();\n if (run instanceof RunService) {\n rs = run;\n } else if (run && (typeof run === 'string')) {\n rs = new RunService($.extend(true, {}, existingOptions, { id: run, autoRestore: false }));\n } else if ($.isArray(run)) {\n var me = this;\n var proms = run.map(function (r) {\n return me.mark(r, toMark);\n });\n return $.when.apply(null, proms);\n } else {\n throw new Error('Invalid run object provided');\n }\n return rs.save(toMark);\n },\n\n /**\n * Returns a list of saved runs.\n *\n * **Example**\n *\n * var sm = new F.manager.ScenarioManager();\n * sm.savedRuns.getRuns().then(function (runs) {\n * for (var i=0; i\n * //\n * $('#fileupload').on('change', function (e) {\n * var file = e.target.files[0];\n * var data = new FormData();\n * data.append('file', file, file.name);\n * fa.create(file.name, data);\n * });\n */\n\n'use strict';\n\nvar ConfigService = require('./configuration-service');\nvar TransportFactory = require('../transport/http-transport-factory');\nvar SessionManager = require('../store/session-manager');\n\nmodule.exports = function (config) {\n var defaults = {\n /**\n * For projects that require authentication, pass in the user access token (defaults to empty string). If the user is already logged in to Epicenter, the user access token is already set in a cookie and automatically loaded from there. (See [more background on access tokens](../../../project_access/)).\n * @see [Authentication API Service](../auth-api-service/) for getting tokens.\n * @type {String}\n */\n token: undefined,\n\n /**\n * The account id. In the Epicenter UI, this is the **Team ID** (for team projects) or **User ID** (for personal projects). Defaults to undefined.\n * @type {String}\n */\n account: undefined,\n\n /**\n * The project id. Defaults to undefined.\n * @type {String}\n */\n project: undefined,\n\n /**\n * The folder type. One of `model` | `static` | `node`.\n * @type {String}\n */\n folderType: 'static',\n\n\n /**\n * Options to pass on to the underlying transport layer. All jquery.ajax options at http://api.jquery.com/jQuery.ajax/ are available. Defaults to empty object.\n * @type {Object}\n */\n transport: {}\n };\n\n this.sessionManager = new SessionManager();\n var serviceOptions = this.sessionManager.getMergedOptions(defaults, config);\n var urlConfig = new ConfigService(serviceOptions).get('server');\n if (serviceOptions.account) {\n urlConfig.accountPath = serviceOptions.account;\n }\n if (serviceOptions.project) {\n urlConfig.projectPath = serviceOptions.project;\n }\n\n var httpOptions = $.extend(true, {}, serviceOptions.transport, {\n url: urlConfig.getAPIPath('file')\n });\n\n if (serviceOptions.token) {\n httpOptions.headers = {\n Authorization: 'Bearer ' + serviceOptions.token\n };\n }\n var http = new TransportFactory(httpOptions);\n\n function uploadBody(fileName, contents) {\n var boundary = '---------------------------7da24f2e50046';\n\n return {\n body: '--' + boundary + '\\r\\n' +\n 'Content-Disposition: form-data; name=\"file\";' +\n 'filename=\"' + fileName + '\"\\r\\n' +\n 'Content-type: text/html\\r\\n\\r\\n' +\n contents + '\\r\\n' +\n '--' + boundary + '--',\n boundary: boundary\n };\n }\n\n function uploadFileOptions(filePath, contents, options) {\n filePath = filePath.split('/');\n var fileName = filePath.pop();\n filePath = filePath.join('/');\n var path = serviceOptions.folderType + '/' + filePath;\n\n var extraParams = {};\n if (contents instanceof FormData) {\n extraParams = {\n data: contents,\n processData: false,\n contentType: false,\n };\n } else {\n var upload = uploadBody(fileName, contents);\n extraParams = {\n data: upload.body,\n contentType: 'multipart/form-data; boundary=' + upload.boundary\n };\n }\n\n return $.extend(true, {}, serviceOptions, options, {\n url: urlConfig.getAPIPath('file') + path,\n }, extraParams);\n }\n\n var publicAsyncAPI = {\n /**\n * Get a directory listing, or contents of a file.\n * @param {String} filePath Path to the file\n * @param {Object} options (Optional) Overrides for configuration options.\n * @return {Promise}\n */\n getContents: function (filePath, options) {\n var path = serviceOptions.folderType + '/' + filePath;\n var httpOptions = $.extend(true, {}, serviceOptions, options, {\n url: urlConfig.getAPIPath('file') + path\n });\n return http.get('', httpOptions);\n },\n\n /**\n * Replaces the file at the given file path.\n * @param {String} filePath Path to the file\n * @param {String | FormData } contents Contents to write to file\n * @param {Object} options (Optional) Overrides for configuration options\n * @return {Promise}\n */\n replace: function (filePath, contents, options) {\n var httpOptions = uploadFileOptions(filePath, contents, options);\n return http.put(httpOptions.data, httpOptions);\n },\n\n /**\n * Creates a file in the given file path.\n * @param {String} filePath Path to the file\n * @param {String | FormData } contents Contents to write to file\n * @param {Boolean} replaceExisting Replace file if it already exists; defaults to false\n * @param {Object} options (Optional) Overrides for configuration options\n * @return {Promise}\n */\n create: function (filePath, contents, replaceExisting, options) {\n var httpOptions = uploadFileOptions(filePath, contents, options);\n var prom = http.post(httpOptions.data, httpOptions);\n var me = this;\n if (replaceExisting === true) {\n prom = prom.then(null, function (xhr) {\n var conflictStatus = 409;\n if (xhr.status === conflictStatus) {\n return me.replace(filePath, contents, options);\n }\n });\n }\n return prom;\n },\n\n /**\n * Removes the file.\n * @param {String} filePath Path to the file\n * @param {Object} options (Optional) Overrides for configuration options\n * @return {Promise}\n */\n remove: function (filePath, options) {\n var path = serviceOptions.folderType + '/' + filePath;\n var httpOptions = $.extend(true, {}, serviceOptions, options, {\n url: urlConfig.getAPIPath('file') + path\n });\n return http.delete(null, httpOptions);\n },\n\n /**\n * Renames the file.\n * @param {String} filePath Path to the file\n * @param {String} newName New name of file\n * @param {Object} options (Optional) Overrides for configuration options\n * @return {Promise}\n */\n rename: function (filePath, newName, options) {\n var path = serviceOptions.folderType + '/' + filePath;\n var httpOptions = $.extend(true, {}, serviceOptions, options, {\n url: urlConfig.getAPIPath('file') + path\n });\n return http.patch({ name: newName }, httpOptions);\n }\n };\n\n $.extend(this, publicAsyncAPI);\n};\n","/**\n * ## Asset API Adapter\n *\n * The Asset API Adapter allows you to store assets -- resources or files of any kind -- used by a project with a scope that is specific to project, group, or end user.\n *\n * Assets are used with [team projects](../../../project_admin/#team). One common use case is having end users in a [group](../../../glossary/#groups) or in a [multiplayer world](../../../glossary/#world) upload data -- videos created during game play, profile pictures for customizing their experience, etc. -- as part of playing through the project.\n *\n * Resources created using the Asset Adapter are scoped:\n *\n * * Project assets are writable only by [team members](../../../glossary/#team), that is, Epicenter authors.\n * * Group assets are writable by anyone with access to the project that is part of that particular [group](../../../glossary/#groups). This includes all [team members](../../../glossary/#team) (Epicenter authors) and any [end users](../../../glossary/#users) who are members of the group -- both facilitators and standard end users.\n * * User assets are writable by the specific end user, and by the facilitator of the group.\n * * All assets are readable by anyone with the exact URI.\n *\n * To use the Asset Adapter, instantiate it and then access the methods provided. Instantiating requires the account id (**Team ID** in the Epicenter user interface) and project id (**Project ID**). The group name is required for assets with a group scope, and the group name and userId are required for assets with a user scope. If not included, they are taken from the logged in user's session information if needed.\n *\n * When creating an asset, you can pass in text (encoded data) to the `create()` call. Alternatively, you can make the `create()` call as part of an HTML form and pass in a file uploaded via the form.\n *\n * // instantiate the Asset Adapter\n * var aa = new F.service.Asset({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * group: 'team1',\n * userId: '12345'\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\n'use strict';\n\nvar ConfigService = require('./configuration-service');\nvar TransportFactory = require('../transport/http-transport-factory');\nvar _pick = require('../util/object-util')._pick;\nvar SessionManager = require('../store/session-manager');\n\nvar apiEndpoint = 'asset';\n\nmodule.exports = function (config) {\n var defaults = {\n /**\n * For projects that require authentication, pass in the user access token (defaults to empty string). If the user is already logged in to Epicenter, the user access token is already set in a cookie and automatically loaded from there. (See [more background on access tokens](../../../project_access/)).\n * @see [Authentication API Service](../auth-api-service/) for getting tokens.\n * @type {String}\n */\n token: undefined,\n /**\n * The account id. In the Epicenter UI, this is the **Team ID** (for team projects). If left undefined, taken from the URL.\n * @type {String}\n */\n account: undefined,\n /**\n * The project id. If left undefined, taken from the URL.\n * @type {String}\n */\n project: undefined,\n /**\n * The group name. Defaults to session's `groupName`.\n * @type {String}\n */\n group: undefined,\n /**\n * The user id. Defaults to session's `userId`.\n * @type {String}\n */\n userId: undefined,\n /**\n * The scope for the asset. Valid values are: `user`, `group`, and `project`. See above for the required permissions to write to each scope. Defaults to `user`, meaning the current end user or a facilitator in the end user's group can edit the asset.\n * @type {String}\n */\n scope: 'user',\n /**\n * Determines if a request to list the assets in a scope includes the complete URL for each asset (`true`), or only the file names of the assets (`false`). Defaults to `true`.\n * @type {boolean}\n */\n fullUrl: true,\n /**\n * The transport object contains the options passed to the XHR request.\n * @type {object}\n */\n transport: {\n processData: false\n }\n };\n this.sessionManager = new SessionManager();\n var serviceOptions = this.sessionManager.getMergedOptions(defaults, config);\n var urlConfig = new ConfigService(serviceOptions).get('server');\n\n if (!serviceOptions.account) {\n serviceOptions.account = urlConfig.accountPath;\n }\n\n if (!serviceOptions.project) {\n serviceOptions.project = urlConfig.projectPath;\n }\n\n var transportOptions = $.extend(true, {}, serviceOptions.transport, {\n url: urlConfig.getAPIPath(apiEndpoint)\n });\n\n if (serviceOptions.token) {\n transportOptions.headers = {\n Authorization: 'Bearer ' + serviceOptions.token\n };\n }\n\n var http = new TransportFactory(transportOptions);\n\n var assetApiParams = ['encoding', 'data', 'contentType'];\n var scopeConfig = {\n user: ['scope', 'account', 'project', 'group', 'userId'],\n group: ['scope', 'account', 'project', 'group'],\n project: ['scope', 'account', 'project'],\n };\n\n var validateFilename = function (filename) {\n if (!filename) {\n throw new Error('filename is needed.');\n }\n };\n\n var validateUrlParams = function (options) {\n var partKeys = scopeConfig[options.scope];\n if (!partKeys) {\n throw new Error('scope parameter is needed.');\n }\n\n $.each(partKeys, function () {\n if (!options[this]) {\n throw new Error(this + ' parameter is needed.');\n }\n });\n };\n\n var buildUrl = function (filename, options) {\n validateUrlParams(options);\n var partKeys = scopeConfig[options.scope];\n var parts = $.map(partKeys, function (key) {\n return options[key];\n });\n if (filename) {\n // This prevents adding a trailing / in the URL as the Asset API\n // does not work correctly with it\n filename = '/' + filename;\n }\n return urlConfig.getAPIPath(apiEndpoint) + parts.join('/') + filename;\n };\n\n // Private function, all requests follow a more or less same approach to\n // use the Asset API and the difference is the HTTP verb\n //\n // @param {string} method` (Required) HTTP verb\n // @param {string} filename` (Required) Name of the file to delete/replace/create\n // @param {object} params` (Optional) Body parameters to send to the Asset API\n // @param {object} options` (Optional) Options object to override global options.\n var upload = function (method, filename, params, options) {\n validateFilename(filename);\n // make sure the parameter is clean\n method = method.toLowerCase();\n var contentType = params instanceof FormData === true ? false : 'application/json';\n if (contentType === 'application/json') {\n // whitelist the fields that we actually can send to the api\n params = _pick(params, assetApiParams);\n } else { // else we're sending form data which goes directly in request body\n // For multipart/form-data uploads the filename is not set in the URL,\n // it's getting picked by the FormData field filename.\n filename = method === 'post' || method === 'put' ? '' : filename;\n }\n var urlOptions = $.extend({}, serviceOptions, options);\n var url = buildUrl(filename, urlOptions);\n var createOptions = $.extend(true, {}, urlOptions, { url: url, contentType: contentType });\n\n return http[method](params, createOptions);\n };\n\n var publicAPI = {\n /**\n * Creates a file in the Asset API. The server returns an error (status code `409`, conflict) if the file already exists, so\n * check first with a `list()` or a `get()`.\n *\n * **Example**\n *\n * var aa = new F.service.Asset({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * group: 'team1',\n * userId: ''\n * });\n *\n * // create a new asset using encoded text\n * aa.create('test.txt', {\n * encoding: 'BASE_64',\n * data: 'VGhpcyBpcyBhIHRlc3QgZmlsZS4=',\n * contentType: 'text/plain'\n * }, { scope: 'user' });\n *\n * // alternatively, create a new asset using a file uploaded through a form\n * // this sample code goes with an html form that looks like this:\n * //\n * //
\n * // \n * // \n * // \n * //
\n * //\n * $('#upload-file').on('submit', function (e) {\n * e.preventDefault();\n * var filename = $('#filename').val();\n * var data = new FormData();\n * var inputControl = $('#file')[0];\n * data.append('file', inputControl.files[0], filename);\n *\n * aa.create(filename, data, { scope: 'user' });\n * });\n *\n *\n * **Parameters**\n * @param {string} filename (Required) Name of the file to create.\n * @param {object} params (Optional) Body parameters to send to the Asset API. Required if the `options.transport.contentType` is `application/json`, otherwise ignored.\n * @param {string} params.encoding Either `HEX` or `BASE_64`. Required if `options.transport.contentType` is `application/json`.\n * @param {string} params.data The encoded data for the file. Required if `options.transport.contentType` is `application/json`.\n * @param {string} params.contentType The mime type of the file. Optional.\n * @param {object} options (Optional) Options object to override global options.\n * @return {Promise}\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 * @return {Promise}\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 * @return {Promise}\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.resolveWith(me, [fullPathFiles]);\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 * @return {Promise}\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 * @return {Promise}\n */\n delete: function (filename, options) {\n return upload('delete', filename, {}, options);\n },\n\n assetUrl: function (filename, options) {\n var urlOptions = $.extend({}, serviceOptions, options);\n return buildUrl(filename, urlOptions);\n }\n };\n $.extend(this, publicAPI);\n};\n","/**\n *\n * ## Authentication API Service\n *\n * The Authentication API Service provides a method for logging in, which creates and returns a user access token.\n *\n * User access tokens are required for each call to Epicenter. (See [Project Access](../../../project_access/) for more information.)\n *\n * If you need additional functionality -- such as tracking session information, easily retrieving the user token, or getting the groups to which an end user belongs -- consider using the [Authorization Manager](../auth-manager/) instead.\n *\n * var auth = new F.service.Auth();\n * auth.login({ userName: 'jsmith@acmesimulations.com',\n * password: 'passw0rd' });\n */\n\n'use strict';\n\nvar ConfigService = require('./configuration-service');\nvar TransportFactory = require('../transport/http-transport-factory');\n\nmodule.exports = function (config) {\n var defaults = {\n /**\n * Email or username to use for logging in. Defaults to empty string.\n * @type {String}\n */\n userName: '',\n\n /**\n * Password for specified `userName`. Defaults to empty string.\n * @type {String}\n */\n password: '',\n\n /**\n * The account id for this `userName`. In the Epicenter UI, this is the **Team ID** (for team projects) or the **User ID** (for personal projects). Required if the `userName` is for an [end user](../../../glossary/#users). Defaults to empty string.\n * @type {String}\n */\n account: '',\n\n /**\n * Options to pass on to the underlying transport layer. All jquery.ajax options at http://api.jquery.com/jQuery.ajax/ are available. Defaults to empty object.\n * @type {Object}\n */\n transport: {}\n };\n var serviceOptions = $.extend({}, defaults, config);\n var urlConfig = new ConfigService(serviceOptions).get('server');\n\n var transportOptions = $.extend(true, {}, serviceOptions.transport, {\n url: urlConfig.getAPIPath('authentication')\n });\n var http = new TransportFactory(transportOptions);\n\n var publicAPI = {\n\n /**\n * Logs user in, returning the user access token.\n *\n * If no `userName` or `password` were provided in the initial configuration options, they are required in the `options` here. If no `account` was provided in the initial configuration options and the `userName` is for an [end user](../../../glossary/#users), the `account` is required as well.\n *\n * **Example**\n *\n * auth.login({\n * userName: 'jsmith',\n * password: 'passw0rd',\n * account: 'acme-simulations' })\n * .then(function (token) {\n * console.log(\"user access token is: \", token.access_token);\n * });\n *\n * **Parameters**\n * @param {Object} options (Optional) Overrides for configuration options.\n * @return {Promise}\n */\n login: function (options) {\n var httpOptions = $.extend(true, { success: $.noop }, serviceOptions, options);\n if (!httpOptions.userName || !httpOptions.password) {\n var resp = { status: 401, statusMessage: 'No username or password specified.' };\n if (options.error) {\n options.error.call(this, resp);\n }\n\n return $.Deferred().reject(resp).promise();\n }\n\n var postParams = {\n userName: httpOptions.userName,\n password: httpOptions.password,\n };\n if (httpOptions.account) {\n //pass in null for account under options if you don't want it to be sent\n postParams.account = httpOptions.account;\n }\n\n return http.post(postParams, httpOptions);\n },\n\n // (replace with /* */ comment block, to make visible in docs, once this is more than a noop)\n //\n // Logs user out from specified accounts.\n //\n // Epicenter logout is not implemented yet, so for now this is a dummy promise that gets automatically resolved.\n //\n // **Example**\n //\n // auth.logout();\n //\n // **Parameters**\n // @param {Object} `options` (Optional) Overrides for configuration options.\n //\n logout: function (options) {\n var dtd = $.Deferred();\n dtd.resolve();\n return dtd.promise();\n }\n };\n\n $.extend(this, publicAPI);\n};\n","/**\n * ## 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 * If you are developing with Epicenter.js, you should use the [Epicenter Channel Manager](../epicenter-channel-manager/) directly. The Epicenter Channel Manager documentation also has more [background](../epicenter-channel-manager/#background) information on channels and their use.\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 * 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 * If you are working through the [Epicenter Channel Manager](../epicenter-channel-manager/), when you ask to \"get\" a particular channel, you are really asking for an instance of the Channel Service with a topic already set, for example to the appropriate group or world:\n *\n * var cm = new F.manager.ChannelManager();\n * var gc = cm.getGroupChannel();\n * // because we used an Epicenter Channel Manager to get the group channel,\n * // subscribe() and publish() here default to the base topic for the group\n * gc.subscribe('', function(data) { console.log(data); });\n * gc.publish('', { message: 'a new message to the group' });\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 */\n\n'use strict';\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 * @param {String} topic topic to resolve\n * @return {String}\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 * @return {string} Subscription ID\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 * @return {Array | Object} Responses to published data\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 * @return {Object} reference to current instance\n */\n unsubscribe: function (token) {\n this.channelOptions.transport.unsubscribe(token);\n return this;\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","/**\n * @class ConfigurationService\n *\n * All services take in a configuration settings object to configure themselves. A JS hash {} is a valid configuration object, but optionally you can use the configuration service to toggle configs based on the environment\n *\n * @example\n * var cs = require('configuration-service')({\n * dev: { //environment\n port: 3000,\n host: 'localhost',\n },\n prod: {\n port: 8080,\n host: 'api.forio.com',\n logLevel: 'none'\n },\n logLevel: 'DEBUG' //global\n * });\n *\n * cs.get('logLevel'); //returns 'DEBUG'\n *\n * cs.setEnv('dev');\n * cs.get('logLevel'); //returns 'DEBUG'\n *\n * cs.setEnv('prod');\n * cs.get('logLevel'); //returns 'none'\n *\n */\n\n'use strict';\nvar urlService = require('./url-config-service');\n\nmodule.exports = function (config) {\n //TODO: Environments\n var defaults = {\n logLevel: 'NONE'\n };\n var serviceOptions = $.extend({}, defaults, config);\n serviceOptions.server = urlService(serviceOptions.server);\n\n return {\n\n data: serviceOptions,\n\n /**\n * Set the environment key to get configuration options from\n * @param { string} env\n */\n setEnv: function (env) {\n\n },\n\n /**\n * Get configuration.\n * @param { string} property optional\n * @return {*} Value of property if specified, the entire config object otherwise\n */\n get: function (property) {\n return serviceOptions[property];\n },\n\n /**\n * Set configuration.\n * @param { string|Object} key if a key is provided, set a key to that value. Otherwise merge object with current config\n * @param {*} value value for provided key\n */\n set: function (key, value) {\n serviceOptions[key] = value;\n }\n };\n};\n\n","/**\n * ## Data API Service\n *\n * The Data API Service allows you to create, access, and manipulate data related to any of your projects. Data are organized in collections. Each collection contains a document; each element of this top-level document is a JSON object. (See additional information on the underlying [Data API](../../../rest_apis/data_api/).)\n *\n * All API calls take in an \"options\" object as the last parameter. The options can be used to extend/override the Data API Service defaults. In particular, there are three required parameters when you instantiate the Data Service:\n *\n * * `account`: Epicenter account id (**Team ID** for team projects, **User ID** for personal projects).\n * * `project`: Epicenter project id.\n * * `root`: The the name of the collection. If you have multiple collections within each of your projects, you can also pass the collection name as an option for each call.\n *\n * var ds = new F.service.Data({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * root: 'survey-responses',\n * server: { host: 'api.forio.com' }\n * });\n * ds.saveAs('user1',\n * { 'question1': 2, 'question2': 10,\n * 'question3': false, 'question4': 'sometimes' } );\n * ds.saveAs('user2',\n * { 'question1': 3, 'question2': 8,\n * 'question3': true, 'question4': 'always' } );\n * ds.query('',{ 'question2': { '$gt': 9} });\n *\n * Note that in addition to the `account`, `project`, and `root`, the Data Service parameters optionally include a `server` object, whose `host` field contains the URI of the Forio server. This is automatically set, but you can pass it explicitly if desired. It is most commonly used for clarity when you are [hosting an Epicenter project on your own server](../../../how_to/self_hosting/).\n */\n\n'use strict';\n\nvar ConfigService = require('./configuration-service');\nvar qutil = require('../util/query-util');\nvar TransportFactory = require('../transport/http-transport-factory');\nvar SessionManager = require('../store/session-manager');\n\nmodule.exports = function (config) {\n var defaults = {\n /**\n * Name of collection. Required. Defaults to `/`, that is, the root level of your project at `forio.com/app/your-account-id/your-project-id/`, but must be set to a collection name.\n * @type {String}\n */\n root: '/',\n\n /**\n * The account id. In the Epicenter UI, this is the **Team ID** (for team projects) or **User ID** (for personal projects). Defaults to empty string. If left undefined, taken from the URL.\n * @type {String}\n */\n account: undefined,\n\n /**\n * The project id. Defaults to empty string. If left undefined, taken from the URL.\n * @type {String}\n */\n project: undefined,\n\n /**\n * For operations that require authentication, pass in the user access token (defaults to empty string). If the user is already logged in to Epicenter, the user access token is already set in a cookie and automatically loaded from there. (See [more background on access tokens](../../../project_access/)).\n * @see [Authentication API Service](../auth-api-service/) for getting tokens.\n * @type {String}\n */\n token: undefined,\n\n //Options to pass on to the underlying transport layer\n transport: {}\n };\n this.sessionManager = new SessionManager();\n var serviceOptions = this.sessionManager.getMergedOptions(defaults, config);\n\n var urlConfig = new ConfigService(serviceOptions).get('server');\n if (serviceOptions.account) {\n urlConfig.accountPath = serviceOptions.account;\n }\n if (serviceOptions.project) {\n urlConfig.projectPath = serviceOptions.project;\n }\n\n var getURL = function (key, root) {\n if (!root) {\n root = serviceOptions.root;\n }\n var url = urlConfig.getAPIPath('data') + qutil.addTrailingSlash(root);\n if (key) {\n url += qutil.addTrailingSlash(key);\n }\n return url;\n };\n\n var httpOptions = $.extend(true, {}, serviceOptions.transport, {\n url: getURL\n });\n if (serviceOptions.token) {\n httpOptions.headers = {\n Authorization: 'Bearer ' + serviceOptions.token\n };\n }\n var http = new TransportFactory(httpOptions);\n\n var publicAPI = {\n\n /**\n * Search for data within a collection.\n *\n * Searching using comparison or logical operators (as opposed to exact matches) requires MongoDB syntax. See the underlying [Data API](../../../rest_apis/data_api/#searching) for additional details.\n *\n * **Examples**\n *\n * // request all data associated with document 'user1'\n * ds.query('user1');\n *\n * // exact matching:\n * // request all documents in collection where 'question2' is 9\n * ds.query('', { 'question2': 9});\n *\n * // comparison operators:\n * // request all documents in collection\n * // where 'question2' is greater than 9\n * ds.query('', { 'question2': { '$gt': 9} });\n *\n * // logical operators:\n * // request all documents in collection\n * // where 'question2' is less than 10, and 'question3' is false\n * ds.query('', { '$and': [ { 'question2': { '$lt':10} }, { 'question3': false }] });\n *\n * // regular expresssions: use any Perl-compatible regular expressions\n * // request all documents in collection\n * // where 'question5' contains the string '.*day'\n * ds.query('', { 'question5': { '$regex': '.*day' } });\n *\n * **Parameters**\n * @param {String} key The name of the document to search. Pass the empty string ('') to search the entire collection.\n * @param {Object} query The query object. For exact matching, this object contains the field name and field value to match. For matching based on comparison, this object contains the field name and the comparison expression. For matching based on logical operators, this object contains an expression using MongoDB syntax. See the underlying [Data API](../../../rest_apis/data_api/#searching) for additional examples.\n * @param {Object} outputModifier (Optional) Available fields include: `startrecord`, `endrecord`, `sort`, and `direction` (`asc` or `desc`).\n * @param {Object} options (Optional) Overrides for configuration options.\n * @return {Promise} \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 in an anonymous document within the collection.\n *\n * The `root` of the collection must be specified. By default the `root` is taken from the Data Service configuration options; you can also pass the `root` to the `save` call explicitly by overriding the options (third parameter).\n *\n * (Additional background: 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 more information. The `save` method is making a `POST` request.)\n *\n * **Example**\n *\n * // Create a new document, with one element, at the default root level\n * ds.save('question1', 'yes');\n *\n * // Create a new document, with two elements, at the default root level\n * ds.save({ question1:'yes', question2: 32 });\n *\n * // Create a new document, with two elements, at `/students/`\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. If you want to override the default `root` of the collection, do so here.\n * @return {Promise} \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 (create or replace) data in a named document or element within the collection. \n * \n * The `root` of the collection must be specified. By default the `root` is taken from the Data Service configuration options; you can also pass the `root` to the `saveAs` call explicitly by overriding the options (third parameter).\n *\n * Optionally, the named document or element can include path information, so that you are saving just part of the document.\n *\n * (Additional background: 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 more information. The `saveAs` method is making a `PUT` request.)\n *\n * **Example**\n *\n * // Create (or replace) the `user1` document at the default root level.\n * // Note that this replaces any existing content in the `user1` document.\n * ds.saveAs('user1',\n * { 'question1': 2, 'question2': 10,\n * 'question3': false, 'question4': 'sometimes' } );\n *\n * // Create (or replace) the `student1` document at the `students` root, \n * // that is, the data at `/students/student1/`.\n * // Note that this replaces any existing content in the `/students/student1/` document.\n * // However, this will keep existing content in other paths of this collection.\n * // For example, the data at `/students/student2/` is unchanged by this call.\n * ds.saveAs('student1',\n * { firstName: 'john', lastName: 'smith' },\n * { root: 'students' });\n *\n * // Create (or replace) the `mgmt100/groupB` document at the `myclasses` root,\n * // that is, the data at `/myclasses/mgmt100/groupB/`.\n * // Note that this replaces any existing content in the `/myclasses/mgmt100/groupB/` document.\n * // However, this will keep existing content in other paths of this collection.\n * // For example, the data at `/myclasses/mgmt100/groupA/` is unchanged by this call.\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. If you want to override the default `root` of the collection, do so here.\n * @return {Promise} \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 * @return {Promise} \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 * @return {Promise} \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 * ## Group API Adapter\n *\n * The Group API Adapter provides methods to look up, create, change or remove information about groups in a project. It is based on query capabilities of the underlying RESTful [Group API](../../../rest_apis/user_management/group/).\n *\n * This is only needed for Authenticated projects, that is, team projects with [end users and groups](../../../groups_and_end_users/).\n *\n * var ma = new F.service.Group({ token: 'user-or-project-access-token' });\n * ma.getGroupsForProject({ account: 'acme', project: 'sample' });\n */\n\n'use strict';\n\nvar serviceUtils = require('./service-utils');\nvar TransportFactory = require('../transport/http-transport-factory');\nvar objectAssign = require('object-assign');\n\nvar apiEndpoint = 'group/local';\n\nvar GroupService = function (config) {\n var defaults = {\n /**\n * Epicenter account name. Defaults to undefined.\n * @type {string}\n */\n account: undefined,\n\n /**\n * Epicenter project name. Defaults to undefined.\n * @type {string}\n */\n project: undefined,\n\n /**\n * Options to pass on to the underlying transport layer. All jquery.ajax options at http://api.jquery.com/jQuery.ajax/ are available. Defaults to empty object.\n * @type {object}\n */\n transport: {}\n };\n var serviceOptions = serviceUtils.getDefaultOptions(defaults, config, { apiEndpoint: apiEndpoint });\n var transportOptions = serviceOptions.transport;\n delete serviceOptions.transport;\n var http = new TransportFactory(transportOptions, serviceOptions);\n var publicAPI = {\n /**\n * Gets information for a group or multiple groups.\n * @param {Object} params object with query parameters\n * @patam {string} params.q partial match for name, organization or event.\n * @patam {string} params.account Epicenter's Team ID\n * @patam {string} params.project Epicenter's Project ID\n * @patam {string} params.name Epicenter's Group Name\n * @param {Object} options (Optional) Overrides for configuration options.\n * @return {Promise}\n */\n getGroups: function (params, options) {\n //groupID is part of the URL\n //q, account and project are part of the query string\n var finalOpts = objectAssign({}, serviceOptions, options);\n var finalParams;\n if (typeof params === 'string') {\n finalOpts.url = serviceUtils.getApiUrl(apiEndpoint + '/' + params, finalOpts);\n } else {\n finalParams = params;\n }\n return http.get(finalParams, finalOpts);\n }\n };\n objectAssign(this, publicAPI);\n};\n\nmodule.exports = GroupService;\n","/**\n *\n * ## Introspection API Service\n *\n * The Introspection API Service allows you to view a list of the variables and operations in a model. Typically used in conjunction with the [Run API Service](../run-api-service/).\n *\n * The Introspection API Service is not available for Forio SimLang.\n *\n * var intro = new F.service.Introspect({\n * account: 'acme-simulations',\n * project: 'supply-chain-game'\n * });\n * intro.byModel('supply-chain.py').then(function(data){ ... });\n * intro.byRunID('2b4d8f71-5c34-435a-8c16-9de674ab72e6').then(function(data){ ... });\n *\n */\n\n'use strict';\n\nvar ConfigService = require('./configuration-service');\nvar TransportFactory = require('../transport/http-transport-factory');\nvar SessionManager = require('../store/session-manager');\n\nvar apiEndpoint = 'model/introspect';\n\nmodule.exports = function (config) {\n var defaults = {\n /**\n * For projects that require authentication, pass in the user access token (defaults to empty string). If the user is already logged in to Epicenter, the user access token is already set in a cookie and automatically loaded from there. (See [more background on access tokens](../../../project_access/)).\n * @see [Authentication API Service](../auth-api-service/) for getting tokens.\n * @type {String}\n */\n token: undefined,\n\n /**\n * The account id. In the Epicenter UI, this is the **Team ID** (for team projects) or **User ID** (for personal projects). Defaults to empty string. If left undefined, taken from the URL.\n * @type {String}\n */\n account: undefined,\n\n /**\n * The project id. Defaults to empty string. If left undefined, taken from the URL.\n * @type {String}\n */\n project: undefined,\n\n };\n\n var sessionManager = new SessionManager();\n var serviceOptions = sessionManager.getMergedOptions(defaults, config);\n\n var urlConfig = new ConfigService(serviceOptions).get('server');\n if (serviceOptions.account) {\n urlConfig.accountPath = serviceOptions.account;\n }\n if (serviceOptions.project) {\n urlConfig.projectPath = serviceOptions.project;\n }\n\n var transportOptions = $.extend(true, {}, serviceOptions.transport, {\n url: urlConfig.getAPIPath(apiEndpoint)\n });\n if (serviceOptions.token) {\n transportOptions.headers = {\n Authorization: 'Bearer ' + serviceOptions.token\n };\n }\n var http = new TransportFactory(transportOptions);\n\n var publicAPI = {\n /**\n * Get the available variables and operations for a given model file.\n *\n * Note: This does not work for any model which requires additional parameters, such as `files`.\n *\n * **Example**\n *\n * intro.byModel('abc.vmf')\n * .then(function(data) {\n * // data contains an object with available functions (used with operations API) and available variables (used with variables API)\n * console.log(data.functions);\n * console.log(data.variables);\n * });\n *\n * **Parameters**\n * @param {String} modelFile Name of the model file to introspect.\n * @param {Object} options (Optional) Overrides for configuration options.\n * @return {Promise} \n */\n byModel: function (modelFile, options) {\n var opts = $.extend(true, {}, serviceOptions, options);\n if (!opts.account || !opts.project) {\n throw new Error('Account and project are required when using introspect#byModel');\n }\n if (!modelFile) {\n throw new Error('modelFile is required when using introspect#byModel');\n }\n var url = { url: urlConfig.getAPIPath(apiEndpoint) + [opts.account, opts.project, modelFile].join('/') };\n var httpOptions = $.extend(true, {}, serviceOptions, options, url);\n return http.get('', httpOptions);\n },\n\n /**\n * Get the available variables and operations for a given model file.\n *\n * Note: This does not work for any model which requires additional parameters such as `files`.\n *\n * **Example**\n *\n * intro.byRunID('2b4d8f71-5c34-435a-8c16-9de674ab72e6')\n * .then(function(data) {\n * // data contains an object with available functions (used with operations API) and available variables (used with variables API)\n * console.log(data.functions);\n * console.log(data.variables);\n * });\n *\n * **Parameters**\n * @param {String} runID Id of the run to introspect.\n * @param {Object} options (Optional) Overrides for configuration options.\n * @return {Promise} \n */\n byRunID: function (runID, options) {\n if (!runID) {\n throw new Error('runID is required when using introspect#byModel');\n }\n var url = { url: urlConfig.getAPIPath(apiEndpoint) + runID };\n var httpOptions = $.extend(true, {}, serviceOptions, options, url);\n return http.get('', httpOptions);\n }\n };\n $.extend(this, publicAPI);\n};\n","/**\n *\n * ## Member API Adapter\n *\n * The Member API Adapter provides methods to look up information about end users for your project and how they are divided across groups. It is based on query capabilities of the underlying RESTful [Member API](../../../rest_apis/user_management/member/).\n *\n * This is only needed for Authenticated projects, that is, team projects with [end users and groups](../../../groups_and_end_users/). For example, if some of your end users are facilitators, or if your end users should be treated differently based on which group they are in, use the Member API to find that information.\n *\n * var ma = new F.service.Member({ token: 'user-or-project-access-token' });\n * ma.getGroupsForUser({ userId: 'b6b313a3-ab84-479c-baea-206f6bff337' });\n * ma.getGroupDetails({ groupId: '00b53308-9833-47f2-b21e-1278c07d53b8' });\n */\n\n'use strict';\n\nvar ConfigService = require('./configuration-service');\nvar TransportFactory = require('../transport/http-transport-factory');\nvar SessionManager = require('../store/session-manager');\nvar _pick = require('../util/object-util')._pick;\nvar apiEndpoint = 'member/local';\n\nmodule.exports = function (config) {\n var defaults = {\n /**\n * Epicenter user id. Defaults to a blank string.\n * @type {string}\n */\n userId: undefined,\n\n /**\n * Epicenter group id. Defaults to a blank string. Note that this is the group *id*, not the group *name*.\n * @type {string}\n */\n groupId: undefined,\n\n /**\n * Options to pass on to the underlying transport layer. All jquery.ajax options at http://api.jquery.com/jQuery.ajax/ are available. Defaults to empty object.\n * @type {object}\n */\n transport: {}\n };\n this.sessionManager = new SessionManager();\n var serviceOptions = this.sessionManager.getMergedOptions(defaults, config);\n var urlConfig = new ConfigService(serviceOptions).get('server');\n\n var transportOptions = $.extend(true, {}, serviceOptions.transport, {\n url: urlConfig.getAPIPath(apiEndpoint)\n });\n\n if (serviceOptions.token) {\n transportOptions.headers = {\n Authorization: 'Bearer ' + serviceOptions.token\n };\n }\n var http = new TransportFactory(transportOptions, serviceOptions);\n\n var getFinalParams = function (params) {\n if (typeof params === 'object') {\n return $.extend(true, serviceOptions, params);\n }\n return serviceOptions;\n };\n\n var patchUserActiveField = function (params, active, options) {\n var httpOptions = $.extend(true, serviceOptions, options, {\n url: urlConfig.getAPIPath(apiEndpoint) + params.groupId + '/' + params.userId\n });\n\n return http.patch({ active: active }, httpOptions);\n };\n\n var publicAPI = {\n\n /**\n * Retrieve details about all of the group memberships for one end user. The membership details are returned in an array, with one element (group record) for each group to which the end user belongs.\n *\n * In the membership array, each group record includes the group id, project id, account (team) id, and an array of members. However, only the user whose userId is included in the call is listed in the members array (regardless of whether there are other members in this group).\n *\n * **Example**\n *\n * var ma = new F.service.Member({ token: 'user-or-project-access-token' });\n * ma.getGroupsForUser('42836d4b-5b61-4fe4-80eb-3136e956ee5c')\n * .then(function(memberships){\n * for (var i=0; i 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 model or marked for saving in your [model context file](../../../model_code/context/)).\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 * @return {Promise}\n */\n query: function (qs, outputModifier, options) {\n var httpOptions = $.extend(true, {}, serviceOptions, { url: urlConfig.getFilterURL(qs) }, options);\n httpOptions = urlConfig.addAutoRestoreHeader(httpOptions);\n\n return http.splitGet(outputModifier, httpOptions).then(function (r) {\n return ($.isPlainObject(r) && Object.keys(r).length === 0) ? [] : r;\n });\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 model or marked for saving in your [model context file](../../../model_code/context/)).\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 * @return {Promise}\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).then(function (r) {\n return ($.isPlainObject(r) && Object.keys(r).length === 0) ? [] : r;\n });\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 or run record 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 or saved in your 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 * @return {Promise}\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 * Removes specified runid from memory\n *\n * See [details on run persistence](../../../run_persistence/#runs-in-memory)\n * @param {String} [runID] id of run to remove\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 * @return {Promise}\n */\n removeFromMemory: function (runID, filters, options) {\n var httpOptions = $.extend(true, {}, serviceOptions, options);\n if (runID) {\n httpOptions.url = urlConfig.getAPIPath('run') + runID;\n }\n return http.delete({}, httpOptions);\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 * // update 'saved' field of run record for a particular run\n * rs.save({ saved: true }, { id: '0000015bf2a04995880df6b868d23eb3d229' });\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 * @return {Promise}\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 an operation from the model.\n *\n * Depending on the language in which you have written your model, the operation (function or 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 * // operation \"solve\" takes no arguments\n * rs.do('solve');\n * // operation \"echo\" takes one argument, a string\n * rs.do('echo', ['hello']);\n * // operation \"echo\" takes one argument, a string\n * rs.do('echo', 'hello');\n * // operation \"sumArray\" takes one argument, an array\n * rs.do('sumArray', [[4,2,1]]);\n * // operation \"add\" takes two arguments, both integers\n * rs.do({ name:'add', params:[2,4] });\n * // call operation \"solve\" on a different run \n * rs.do('solve', { id: '0000015bf2a04995880df6b868d23eb3d229' });\n *\n * **Parameters**\n * @param {String} operation Name of operation.\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 * @return {Promise}\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 if ($.isPlainObject(params)) {\n opsArgs = null;\n postOptions = params;\n } else {\n opsArgs = params;\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 operations from the model, sequentially.\n *\n * Depending on the language in which you have written your model, the operation (function or 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 * **Examples**\n *\n * // operations \"initialize\" and \"solve\" do not take any arguments\n * rs.serial(['initialize', 'solve']);\n * // operations \"init\" and \"reset\" take two arguments each\n * rs.serial([ { name: 'init', params: [1,2] },\n * { name: 'reset', params: [2,3] }]);\n * // operation \"init\" takes two arguments,\n * // operation \"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 operations take parameters, pass an array of the operation names (strings). If any of the operations do take parameters, pass an array of objects, each of which contains an operation 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 * @return {Promise} The parameter to the callback is an array. Each array element is an object containing the results of one operation.\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 responses = [];\n var doSingleOp = function () {\n var op = ops.shift();\n var arg = args.shift();\n\n me.do(op, arg, {\n success: function (result) {\n responses.push(result);\n if (ops.length) {\n doSingleOp();\n } else {\n $d.resolve(responses);\n postOptions.success(responses, me);\n }\n },\n error: function (err) {\n responses.push(err);\n $d.reject(responses);\n postOptions.error(responses, me);\n }\n });\n };\n\n doSingleOp();\n\n return $d.promise();\n },\n\n /**\n * Call several operations from the model, executing them in parallel.\n *\n * Depending on the language in which you have written your model, the operation (function or 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 * **Example**\n *\n * // operations \"solve\" and \"reset\" do not take any arguments\n * rs.parallel(['solve', 'reset']);\n * // operations \"add\" and \"subtract\" take two arguments each\n * rs.parallel([ { name: 'add', params: [1,2] },\n * { name: 'subtract', params:[2,3] }]);\n * // operations \"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 operations take parameters, pass an array of the operation names (as strings). If any of the operations do take parameters, you have two options. You can pass an array of objects, each of which contains an operation name and its own (possibly empty) array of parameters. Alternatively, you can pass a single object with the operation 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 * @return {Promise} The parameter to the callback is an array. Each array element is an object containing the results of one operation.\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\n var me = this;\n $.when.apply(this, queue)\n .then(function () {\n var args = Array.prototype.slice.call(arguments);\n var actualResponse = args.map(function (a) {\n return a[0];\n });\n $d.resolve(actualResponse);\n postOptions.success(actualResponse, me);\n })\n .fail(function () {\n var args = Array.prototype.slice.call(arguments);\n var actualResponse = args.map(function (a) {\n return a[0];\n });\n $d.reject(actualResponse);\n postOptions.error(actualResponse, me);\n });\n\n return $d.promise();\n },\n\n /**\n * Shortcut to using the [Introspection API Service](../introspection-api-service/). Allows you to view a list of the variables and operations in a model.\n *\n * **Example**\n *\n * rs.introspect({ runID: 'cbf85437-b539-4977-a1fc-23515cf071bb' }).then(function (data) {\n * console.log(data.functions);\n * console.log(data.variables);\n * });\n *\n * **Parameters**\n * @param {Object} options Options can either be of the form `{ runID: }` or `{ model: }`. Note that the `runID` is optional if the Run Service is already associated with a particular run (because `id` was passed in when the Run Service was initialized). If provided, the `runID` overrides the `id` currently associated with the Run Service.\n * @param {Object} introspectionConfig (Optional) Service options for Introspection Service\n * @return {Promise}\n */\n introspect: function (options, introspectionConfig) {\n var introspection = new IntrospectionService($.extend(true, {}, serviceOptions, introspectionConfig));\n if (options) {\n if (options.runID) {\n return introspection.byRunID(options.runID);\n } else if (options.model) {\n return introspection.byModel(options.model);\n }\n } else if (serviceOptions.id) {\n return introspection.byRunID(serviceOptions.id);\n } else {\n throw new Error('Please specify either the model or runid to introspect');\n }\n }\n };\n\n var publicSyncAPI = {\n getCurrentConfig: function () {\n return serviceOptions;\n },\n updateConfig: function (config) {\n if (config && config.id) {\n config.filter = config.id;\n } else if (config && config.filter) {\n config.id = config.filter;\n }\n serviceOptions = $.extend(true, {}, serviceOptions, config);\n urlConfig = updateURLConfig(serviceOptions);\n this.urlConfig = urlConfig;\n updateHTTPConfig(serviceOptions, urlConfig);\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 * @return {Object} variablesService Instance\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","'use strict';\n\nvar ConfigService = require('./configuration-service');\nvar SessionManager = require('../store/session-manager');\nvar objectAssign = require('object-assign');\n\nvar serviceUtils = {\n /*\n * Gets the default options for a api service.\n * It will merge:\n * - The Session options (Using the Session Manager)\n * - The Authorization Header from the token option\n * - The full url from the endpoint option\n * With the supplied overrides and defaults\n *\n */\n getDefaultOptions: function (defaults) {\n var rest = Array.prototype.slice.call(arguments, 1);\n var sessionManager = new SessionManager();\n var serviceOptions = sessionManager.getMergedOptions.apply(sessionManager, [defaults].concat(rest));\n\n serviceOptions.transport = objectAssign({}, serviceOptions.transport, {\n url: this.getApiUrl(serviceOptions.apiEndpoint, serviceOptions)\n });\n\n if (serviceOptions.token) {\n serviceOptions.transport.headers = {\n Authorization: 'Bearer ' + serviceOptions.token\n };\n }\n return serviceOptions;\n },\n\n getApiUrl: function (apiEndpoint, serviceOptions) {\n var urlConfig = new ConfigService(serviceOptions).get('server');\n return urlConfig.getAPIPath(apiEndpoint);\n }\n};\n\nmodule.exports = serviceUtils;","'use strict';\n/**\n * ## State API Adapter\n *\n * The State API Adapter allows you to view the history of a run, and to replay or clone runs. \n *\n * The State API Adapter brings existing, persisted run data from the database back into memory, using the same run id (`replay`) or a new run id (`clone`). Runs must be in memory in order for you to update variables or call operations on them.\n *\n * Specifically, the State API Adapter works by \"re-running\" the run (user interactions) from the creation of the run up to the time it was last persisted in the database. This process uses the current version of the run's model. Therefore, if the model has changed since the original run was created, the retrieved run will use the new model — and may end up having different values or behavior as a result. Use with care!\n *\n * To use the State API Adapter, instantiate it and then call its methods:\n *\n * var sa = new F.service.State();\n * sa.replay({runId: '1842bb5c-83ad-4ba8-a955-bd13cc2fdb4f'});\n *\n * The constructor takes an optional `options` parameter in which you can specify the `account` and `project` if they are not already available in the current context.\n *\n */\n\nvar ConfigService = require('./configuration-service');\nvar TransportFactory = require('../transport/http-transport-factory');\nvar _pick = require('../util/object-util')._pick;\nvar SessionManager = require('../store/session-manager');\nvar apiEndpoint = 'model/state';\n\nmodule.exports = function (config) {\n\n var defaults = {\n\n };\n\n this.sessionManager = new SessionManager();\n var serviceOptions = this.sessionManager.getMergedOptions(defaults, config);\n var urlConfig = new ConfigService(serviceOptions).get('server');\n\n var transportOptions = $.extend(true, {}, serviceOptions.transport, {\n url: urlConfig.getAPIPath(apiEndpoint)\n });\n\n if (serviceOptions.token) {\n transportOptions.headers = {\n Authorization: 'Bearer ' + serviceOptions.token\n };\n }\n\n var http = new TransportFactory(transportOptions);\n var parseRunIdOrError = function (params) {\n if ($.isPlainObject(params) && params.runId) {\n return params.runId;\n } else {\n throw new Error('Please pass in a run id');\n }\n };\n\n var publicAPI = {\n\n /**\n * View the history of a run.\n * \n * **Example**\n *\n * var sa = new F.service.State();\n * sa.load('0000015a06bb58613b28b57365677ec89ec5').then(function(history) {\n * console.log('history = ', history);\n * });\n *\n * **Parameters**\n * @param {string} runId The id of the run.\n * @param {object} options (Optional) Overrides for configuration options.\n * @return {Promise}\n */\n load: function (runId, options) {\n var httpParams = $.extend(true, {},\n serviceOptions,\n options,\n { url: urlConfig.getAPIPath(apiEndpoint) + runId }\n );\n return http.get('', httpParams);\n },\n\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 * @return {Promise}\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 * @return {Promise}\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\nvar epiVersion = require('../api-version.json');\n\n//TODO: urlutils to get host, since no window on node\nvar defaults = {\n host: window.location.host,\n pathname: window.location.pathname\n};\n\nfunction getLocalHost(existingFn, host) {\n var localHostFn;\n if (existingFn !== undefined) {\n if (!$.isFunction(existingFn)) {\n localHostFn = function () { return existingFn; };\n } else {\n localHostFn = existingFn;\n }\n } else {\n localHostFn = function () {\n var isLocal = !host || //phantomjs\n host === '127.0.0.1' || \n host.indexOf('local.') === 0 || \n host.indexOf('localhost') === 0;\n return isLocal;\n };\n }\n return localHostFn;\n}\n\nvar UrlConfigService = function (config) {\n var envConf = UrlConfigService.defaults;\n\n if (!config) {\n config = {};\n }\n // console.log(this.defaults);\n var overrides = $.extend({}, envConf, config);\n var options = $.extend({}, defaults, overrides);\n\n overrides.isLocalhost = options.isLocalhost = getLocalHost(options.isLocalhost, options.host);\n \n // console.log(isLocalhost(), '___________');\n var actingHost = config && config.host;\n if (!actingHost && options.isLocalhost()) {\n actingHost = 'forio.com';\n } else {\n actingHost = options.host;\n }\n\n var API_PROTOCOL = 'https';\n var HOST_API_MAPPING = {\n 'forio.com': 'api.forio.com',\n 'foriodev.com': 'api.epicenter.foriodev.com'\n };\n\n var publicExports = {\n protocol: API_PROTOCOL,\n\n api: '',\n\n //TODO: this should really be called 'apihost', but can't because that would break too many things\n host: (function () {\n var apiHost = (HOST_API_MAPPING[actingHost]) ? HOST_API_MAPPING[actingHost] : actingHost;\n // console.log(actingHost, config, apiHost);\n return apiHost;\n }()),\n\n isCustomDomain: (function () {\n var path = options.pathname.split('\\/');\n var pathHasApp = path && path[1] === 'app';\n return (!options.isLocalhost() && !pathHasApp);\n }()),\n\n appPath: (function () {\n var path = options.pathname.split('\\/');\n\n return path && path[1] || '';\n }()),\n\n accountPath: (function () {\n var accnt = '';\n var path = options.pathname.split('\\/');\n if (path && path[1] === 'app') {\n accnt = path[2];\n }\n return accnt;\n }()),\n\n projectPath: (function () {\n var prj = '';\n var path = options.pathname.split('\\/');\n if (path && path[1] === 'app') {\n prj = path[3]; //eslint-disable-line no-magic-numbers\n }\n return prj;\n }()),\n\n versionPath: (function () {\n var version = epiVersion.version ? epiVersion.version + '/' : '';\n return version;\n }()),\n\n getAPIPath: function (api) {\n var PROJECT_APIS = ['run', 'data', 'file', 'presence'];\n var apiMapping = {\n channel: 'channel/subscribe'\n };\n var apiEndpoint = apiMapping[api] || api;\n \n if (apiEndpoint === 'config') {\n var actualProtocol = window.location.protocol.replace(':', '');\n var configProtocol = (options.isLocalhost()) ? this.protocol : actualProtocol;\n return configProtocol + '://' + actingHost + '/epicenter/' + this.versionPath + 'config';\n }\n var apiPath = this.protocol + '://' + this.host + '/' + this.versionPath + apiEndpoint + '/';\n\n if ($.inArray(apiEndpoint, PROJECT_APIS) !== -1) {\n apiPath += this.accountPath + '/' + this.projectPath + '/';\n }\n return apiPath;\n }\n };\n\n\n $.extend(publicExports, overrides);\n return publicExports;\n};\n// This data can be set by external scripts, for loading from an env server for eg;\nUrlConfigService.defaults = {};\n\nmodule.exports = UrlConfigService;\n","'use strict';\n/**\n* ## User API Adapter\n*\n* The User API Adapter allows you to retrieve details about end users in your team (account). It is based on the querying capabilities of the underlying RESTful [User API](../../../rest_apis/user_management/user/).\n*\n* To use the User API Adapter, instantiate it and then call its methods.\n*\n* var ua = new F.service.User({\n* account: 'acme-simulations',\n* token: 'user-or-project-access-token'\n* });\n* ua.getById('42836d4b-5b61-4fe4-80eb-3136e956ee5c');\n* ua.get({ userName: 'jsmith' });\n* ua.get({ id: ['42836d4b-5b61-4fe4-80eb-3136e956ee5c',\n* '4ea75631-4c8d-4872-9d80-b4600146478e'] });\n*\n* The constructor takes an optional `options` parameter in which you can specify the `account` and `token` if they are not already available in the current context.\n*/\n\nvar ConfigService = require('./configuration-service');\nvar TransportFactory = require('../transport/http-transport-factory');\nvar SessionManager = require('../store/session-manager');\nvar qutil = require('../util/query-util');\n\nmodule.exports = function (config) {\n var defaults = {\n\n /**\n * The account id. In the Epicenter UI, this is the **Team ID** (for team projects) or **User ID** (for personal projects). Defaults to empty string.\n * @type {String}\n */\n account: undefined,\n\n /**\n * The access token to use when searching for end users. (See [more background on access tokens](../../../project_access/)).\n * @type {String}\n */\n token: undefined,\n\n /**\n * Options to pass on to the underlying transport layer. All jquery.ajax options at http://api.jquery.com/jQuery.ajax/ are available. Defaults to empty object.\n * @type {Object}\n */\n transport: {}\n };\n\n this.sessionManager = new SessionManager();\n var serviceOptions = this.sessionManager.getMergedOptions(defaults, config);\n var urlConfig = new ConfigService(serviceOptions).get('server');\n var transportOptions = $.extend(true, {}, serviceOptions.transport, {\n url: urlConfig.getAPIPath('user')\n });\n\n if (serviceOptions.token) {\n transportOptions.headers = {\n Authorization: 'Bearer ' + serviceOptions.token\n };\n }\n\n var http = new TransportFactory(transportOptions);\n\n var publicAPI = {\n\n /**\n * Retrieve details about particular end users in your team, based on user name or user id.\n *\n * **Example**\n *\n * var ua = new F.service.User({\n * account: 'acme-simulations',\n * token: 'user-or-project-access-token'\n * });\n * ua.get({ userName: 'jsmith' });\n * ua.get({ id: ['42836d4b-5b61-4fe4-80eb-3136e956ee5c',\n * '4ea75631-4c8d-4872-9d80-b4600146478e'] });\n *\n * **Parameters**\n * @param {object} filter Object with field `userName` and value of the username. Alternatively, object with field `id` and value of an array of user ids.\n * @param {object} options (Optional) Overrides for configuration options.\n * @return {Promise}\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 * @return {Promise}\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 * ## 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\n module.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 //TODO: Replace with getCurrentconfig instead?\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 * @return {Promise}\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 * @return {Promise}\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 * @return {Promise}\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 * ## World API Adapter\n *\n * A [run](../../../glossary/#run) is a collection of end user interactions with a project and its model -- including setting variables, making decisions, and calling operations. For building multiplayer simulations you typically want multiple end users to share the same set of interactions, and work within a common state. Epicenter allows you to create \"worlds\" to handle such cases. Only [team projects](../../../glossary/#team) can be multiplayer.\n *\n * The World API Adapter allows you to create, access, and manipulate multiplayer worlds within your Epicenter project. You can use this to add and remove end users from the world, and to create, access, and remove their runs. Because of this, typically the World Adapter is used for facilitator pages in your project. (The related [World Manager](../world-manager/) provides an easy way to access runs and worlds for particular end users, so is typically used in pages that end users will interact with.)\n *\n * As with all the other [API Adapters](../../), all methods take in an \"options\" object as the last parameter. The options can be used to extend/override the World API Service defaults.\n *\n * To use the World Adapter, instantiate it and then access the methods provided. Instantiating requires the account id (**Team ID** in the Epicenter user interface), project id (**Project ID**), and group (**Group Name**).\n *\n * var wa = new F.service.World({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * group: 'team1' });\n * wa.create()\n * .then(function(world) {\n * // call methods, e.g. wa.addUsers()\n * });\n */\n\n'use strict';\n\nvar ConfigService = require('./configuration-service');\n// var qutil = require('../util/query-util');\nvar TransportFactory = require('../transport/http-transport-factory');\nvar SessionManager = require('../store/session-manager');\nvar _pick = require('../util/object-util')._pick;\n\nvar apiBase = 'multiplayer/';\nvar assignmentEndpoint = apiBase + 'assign';\nvar apiEndpoint = apiBase + 'world';\nvar projectEndpoint = apiBase + 'project';\n\nmodule.exports = function (config) {\n var defaults = {\n /**\n * For projects that require authentication, pass in the user access token (defaults to empty string). If the user is already logged in to Epicenter, the user access token is already set in a cookie and automatically loaded from there. (See [more background on access tokens](../../../project_access/)).\n * @see [Authentication API Service](../auth-api-service/) for getting tokens.\n * @type {String}\n */\n token: undefined,\n\n /**\n * The project id. If left undefined, taken from the URL.\n * @type {String}\n */\n project: undefined,\n\n /**\n * The account id. In the Epicenter UI, this is the **Team ID** (for team projects). If left undefined, taken from the URL.\n * @type {String}\n */\n account: undefined,\n\n /**\n * The group name. Defaults to undefined.\n * @type {String}\n */\n group: undefined,\n\n /**\n * The model file to use to create runs in this world. Defaults to undefined.\n * @type {String}\n */\n model: undefined,\n\n /**\n * Criteria by which to filter world. Currently only supports world-ids as filters.\n * @type {String}\n */\n filter: '',\n\n /**\n * Convenience alias for filter\n * @type {String}\n */\n id: '',\n\n /**\n * Options to pass on to the underlying transport layer. All jquery.ajax options at http://api.jquery.com/jQuery.ajax/ are available. Defaults to empty object.\n * @type {Object}\n */\n transport: {},\n\n /**\n * Called when the call completes successfully. Defaults to `$.noop`.\n * @type {function}\n */\n success: $.noop,\n\n /**\n * Called when the call fails. Defaults to `$.noop`.\n * @type {function}\n */\n error: $.noop\n };\n\n this.sessionManager = new SessionManager();\n var serviceOptions = this.sessionManager.getMergedOptions(defaults, config);\n if (serviceOptions.id) {\n serviceOptions.filter = serviceOptions.id;\n }\n\n var urlConfig = new ConfigService(serviceOptions).get('server');\n\n if (!serviceOptions.account) {\n serviceOptions.account = urlConfig.accountPath;\n }\n\n if (!serviceOptions.project) {\n serviceOptions.project = urlConfig.projectPath;\n }\n\n var transportOptions = $.extend(true, {}, serviceOptions.transport, {\n url: urlConfig.getAPIPath(apiEndpoint)\n });\n\n if (serviceOptions.token) {\n transportOptions.headers = {\n Authorization: 'Bearer ' + serviceOptions.token\n };\n }\n\n var http = new TransportFactory(transportOptions);\n\n var setIdFilterOrThrowError = function (options) {\n if (options.id) {\n serviceOptions.filter = options.id;\n }\n if (options.filter) {\n serviceOptions.filter = options.filter;\n }\n if (!serviceOptions.filter) {\n throw new Error('No world id specified to apply operations against. This could happen if the user is not assigned to a world and is trying to work with runs from that world.');\n }\n };\n\n var validateModelOrThrowError = function (options) {\n if (!options.model) {\n throw new Error('No model specified to get the current run');\n }\n };\n\n var publicAPI = {\n\n /**\n * Creates a new World.\n *\n * Using this method is rare. It is more common to create worlds automatically while you `autoAssign()` end users to worlds. (In this case, configuration data for the world, such as the roles, are read from the project-level world configuration information, for example by `getProjectSettings()`.)\n *\n * **Example**\n *\n * var wa = new F.service.World({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * group: 'team1' });\n * wa.create({\n * roles: ['VP Marketing', 'VP Sales', 'VP Engineering']\n * });\n *\n * **Parameters**\n * @param {object} params Parameters to create the world.\n * @param {string} params.group (Optional) The **Group Name** to create this world under. Only end users in this group are eligible to join the world. Optional here; required when instantiating the service (`new F.service.World()`).\n * @param {object} params.roles (Optional) The list of roles (strings) for this world. Some worlds have specific roles that **must** be filled by end users. Listing the roles allows you to autoassign users to worlds and ensure that all roles are filled in each world.\n * @param {object} params.optionalRoles (Optional) The list of optional roles (strings) for this world. Some worlds have specific roles that **may** be filled by end users. Listing the optional roles as part of the world object allows you to autoassign users to worlds and ensure that all roles are filled in each world.\n * @param {integer} params.minUsers (Optional) The minimum number of users for the world. Including this number allows you to autoassign end users to worlds and ensure that the correct number of users are in each world.\n * @param {object} options (Optional) Options object to override global options.\n * @return {Promise}\n */\n create: function (params, options) {\n var createOptions = $.extend(true, {}, serviceOptions, options, { url: urlConfig.getAPIPath(apiEndpoint) });\n var worldApiParams = ['scope', 'files', 'roles', 'optionalRoles', 'minUsers', 'group', 'name'];\n var validParams = _pick(serviceOptions, ['account', 'project', 'group']);\n // whitelist the fields that we actually can send to the api\n params = _pick(params, worldApiParams);\n\n // account and project go in the body, not in the url\n params = $.extend({}, validParams, params);\n\n var oldSuccess = createOptions.success;\n createOptions.success = function (response) {\n serviceOptions.filter = response.id; //all future chained calls to operate on this id\n return oldSuccess.apply(this, arguments);\n };\n\n return http.post(params, createOptions);\n },\n\n /**\n * Updates a World, for example to replace the roles in the world.\n *\n * Typically, you complete world configuration at the project level, rather than at the world level. For example, each world in your project probably has the same roles for end users. And your project is probably either configured so that all end users share the same world (and run), or smaller sets of end users share worlds — but not both. However, this method is available if you need to update the configuration of a particular world.\n *\n * **Example**\n *\n * var wa = new F.service.World({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * group: 'team1' });\n * wa.create()\n * .then(function(world) {\n * wa.update({ roles: ['VP Marketing', 'VP Sales', 'VP Engineering'] });\n * });\n *\n * **Parameters**\n * @param {object} params Parameters to update the world.\n * @param {string} params.name A string identifier for the linked end users, for example, \"name\": \"Our Team\".\n * @param {object} params.roles (Optional) The list of roles (strings) for this world. Some worlds have specific roles that **must** be filled by end users. Listing the roles allows you to autoassign users to worlds and ensure that all roles are filled in each world.\n * @param {object} params.optionalRoles (Optional) The list of optional roles (strings) for this world. Some worlds have specific roles that **may** be filled by end users. Listing the optional roles as part of the world object allows you to autoassign users to worlds and ensure that all roles are filled in each world.\n * @param {integer} params.minUsers (Optional) The minimum number of users for the world. Including this number allows you to autoassign end users to worlds and ensure that the correct number of users are in each world.\n * @param {object} options (Optional) Options object to override global options.\n * @return {Promise}\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 * @return {Promise}\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 * @return {Object} reference to current instance\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 * @return {Promise}\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 * @return {Promise}\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 * @return {Promise}\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 * @return {Promise}\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 * @return {Promise}\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 * @return {Promise}\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 * @return {Promise}\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 * @return {Promise}\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.resolveWith(me, [currentWorld]);\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 * @return {Promise}\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 * @return {Promise}\n */\n newRunForWorld: function (worldId, options) {\n var currentRunOptions = $.extend(true, {},\n serviceOptions,\n options,\n { filter: worldId || serviceOptions.filter }\n );\n var me = this;\n\n validateModelOrThrowError(currentRunOptions);\n\n return this.deleteRun(worldId, options)\n .then(function () {\n return me.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 * @param {number} options.maxUsers Sets the maximum number of users in a world.\n * @param {string[]} options.userIds A list of users to be assigned be assigned instead of all end users in the group.\n * @return {Promise}\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 if (opt.userIds) {\n params.userIds = opt.userIds;\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 * @return {Promise}\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 return http.get(null, opt);\n }\n\n };\n\n $.extend(this, publicAPI);\n};\n","/**\n * @class Cookie Storage Service\n *\n * @example\n * var people = require('cookie-store')({ root: 'people' });\n people\n .save({lastName: 'smith' })\n\n */\n\n\n'use strict';\n\n// Thin document.cookie wrapper to allow unit testing\nvar Cookie = function () {\n this.get = function () {\n return document.cookie;\n };\n\n this.set = function (newCookie) {\n document.cookie = newCookie;\n };\n};\n\nmodule.exports = function (config) {\n var host = window.location.hostname;\n var validHost = host.split('.').length > 1;\n var domain = validHost ? '.' + host : null;\n\n var defaults = {\n /**\n * Name of collection\n * @type { string}\n */\n root: '/',\n\n domain: domain,\n cookie: new Cookie()\n };\n this.serviceOptions = $.extend({}, defaults, config);\n\n var publicAPI = {\n // * TBD\n // * Query collection; uses MongoDB syntax\n // * @see \n // *\n // * @param { string} qs Query Filter\n // * @param { string} limiters @see \n // *\n // * @example\n // * cs.query(\n // * { name: 'John', className: 'CSC101' },\n // * {limit: 10}\n // * )\n\n // query: function (qs, limiters) {\n\n // },\n\n /**\n * Save cookie value\n * @param { string|Object} key If given a key save values under it, if given an object directly, save to top-level api\n * @param {Object} value (Optional)\n * @param {Object} options Overrides for service options\n *\n * @return {*} The saved value\n *\n * @example\n * cs.set('person', { firstName: 'john', lastName: 'smith' });\n * cs.set({ name:'smith', age:'32' });\n */\n set: function (key, value, options) {\n var setOptions = $.extend(true, {}, this.serviceOptions, options);\n\n var domain = setOptions.domain;\n var path = setOptions.root;\n var cookie = setOptions.cookie;\n\n cookie.set(encodeURIComponent(key) + '=' +\n encodeURIComponent(value) +\n (domain ? '; domain=' + domain : '') +\n (path ? '; path=' + path : '')\n );\n\n return value;\n },\n\n /**\n * Load cookie value\n * @param { string|Object} key If given a key save values under it, if given an object directly, save to top-level api\n * @return {*} The value stored\n *\n * @example\n * cs.get('person');\n */\n get: function (key) {\n var cookie = this.serviceOptions.cookie;\n var cookieReg = new RegExp('(?:^|;)\\\\s*' + encodeURIComponent(key).replace(/[\\-\\.\\+\\*]/g, '\\\\$&') + '\\\\s*\\\\=\\\\s*([^;]*).*$');\n var res = cookieReg.exec(cookie.get());\n var val = res ? decodeURIComponent(res[1]) : null;\n return val;\n },\n\n /**\n * Removes key from collection\n * @param { string} key key to remove\n * @param {object} options (optional) overrides for service options\n * @return { string} key The key removed\n *\n * @example\n * cs.remove('person');\n */\n remove: function (key, options) {\n var remOptions = $.extend(true, {}, this.serviceOptions, options);\n\n var domain = remOptions.domain;\n var path = remOptions.root;\n var cookie = remOptions.cookie;\n\n cookie.set(encodeURIComponent(key) +\n '=; expires=Thu, 01 Jan 1970 00:00:00 GMT' +\n (domain ? '; domain=' + domain : '') +\n (path ? '; path=' + path : '')\n );\n return key;\n },\n\n /**\n * Removes collection being referenced\n * @return { array} keys All the keys removed\n */\n destroy: function () {\n var cookie = this.serviceOptions.cookie;\n var aKeys = cookie.get().replace(/((?:^|\\s*;)[^\\=]+)(?=;|$)|^\\s*|\\s*(?:\\=[^;]*)?(?:\\1|$)/g, '').split(/\\s*(?:\\=[^;]*)?;\\s*/);\n for (var nIdx = 0; nIdx < aKeys.length; nIdx++) {\n var cookieKey = decodeURIComponent(aKeys[nIdx]);\n this.remove(cookieKey);\n }\n return aKeys;\n }\n };\n\n $.extend(this, publicAPI);\n};\n","'use strict';\n\nvar keyNames = require('../managers/key-names');\nvar StorageFactory = require('./store-factory');\nvar optionUtils = require('../util/option-utils');\n\nvar EPI_SESSION_KEY = keyNames.EPI_SESSION_KEY;\nvar EPI_MANAGER_KEY = 'epicenter.token'; //can't be under key-names, or logout will clear this too\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 SessionManager = function (managerOptions) {\n managerOptions = managerOptions || {};\n function getBaseOptions(overrides) {\n overrides = overrides || {};\n var libOptions = optionUtils.getOptions();\n var finalOptions = $.extend(true, {}, defaults, libOptions, managerOptions, overrides);\n return finalOptions;\n }\n\n function getStore(overrides) {\n var baseOptions = getBaseOptions(overrides);\n var storeOpts = baseOptions.store || {};\n var isEpicenterDomain = !baseOptions.isLocal && !baseOptions.isCustomDomain;\n if (storeOpts.root === undefined && baseOptions.account && baseOptions.project && isEpicenterDomain) {\n storeOpts.root = '/app/' + baseOptions.account + '/' + baseOptions.project;\n }\n return new StorageFactory(storeOpts);\n }\n\n var publicAPI = {\n saveSession: function (userInfo, options) {\n var serialized = JSON.stringify(userInfo);\n getStore(options).set(EPI_SESSION_KEY, serialized);\n },\n getSession: function (options) {\n var store = getStore(options);\n var finalOpts = store.serviceOptions;\n var serialized = store.get(EPI_SESSION_KEY) || '{}';\n var session = JSON.parse(serialized);\n // If the url contains the project and account\n // validate the account and project in the session\n // and override project, groupName, groupId and isFac\n // Otherwise (i.e. localhost) use the saved session values\n var account = finalOpts.account;\n var project = finalOpts.project;\n if (account && session.account !== account) {\n // This means that the token was not used to login to the same account\n return {};\n }\n if (session.groups && account && project) {\n var group = session.groups[project] || { groupId: '', groupName: '', isFac: false };\n $.extend(session, { project: project }, group);\n }\n return session;\n },\n removeSession: function (options) {\n var store = getStore(options);\n Object.keys(keyNames).forEach(function (cookieKey) {\n var cookieName = keyNames[cookieKey];\n store.remove(cookieName);\n });\n return true;\n },\n getStore: function (options) {\n return getStore(options);\n },\n\n getMergedOptions: function () {\n var args = Array.prototype.slice.call(arguments);\n var overrides = $.extend.apply($, [true, {}].concat(args));\n var baseOptions = getBaseOptions(overrides);\n var session = this.getSession(overrides);\n\n var token = session.auth_token;\n if (!token) {\n var factory = new StorageFactory();\n token = factory.get(EPI_MANAGER_KEY);\n }\n\n var sessionDefaults = {\n /**\n * For projects that require authentication, pass in the user access token (defaults to empty string). If the user is already logged in to Epicenter, the user access token is already set in a cookie and automatically loaded from there. (See [more background on access tokens](../../../project_access/)).\n * @see [Authentication API Service](../auth-api-service/) for getting tokens.\n * @type {String}\n */\n token: token,\n\n /**\n * The account. If left undefined, taken from the cookie session.\n * @type {String}\n */\n account: session.account,\n\n /**\n * The project. If left undefined, taken from the cookie session.\n * @type {String}\n */\n project: session.project,\n\n\n /**\n * The group name. If left undefined, taken from the cookie session.\n * @type {String}\n */\n group: session.groupName,\n /**\n * Alias for group. \n * @type {String}\n */\n groupName: session.groupName, //It's a little weird that it's called groupName in the cookie, but 'group' in all the service options, so normalize for both\n /**\n * The group id. If left undefined, taken from the cookie session.\n * @type {String}\n */\n groupId: session.groupId,\n userId: session.userId,\n userName: session.userName,\n };\n return $.extend(true, sessionDefaults, baseOptions);\n }\n };\n $.extend(this, publicAPI);\n};\n\nmodule.exports = SessionManager;","/**\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';\n\nvar qutils = require('../util/query-util');\n\nmodule.exports = function (config) {\n\n var defaults = {\n url: '',\n\n contentType: 'application/json',\n headers: {},\n statusCode: {\n 404: $.noop\n },\n\n /**\n * ONLY for strings in the url. All GET & DELETE params are run through this\n * @type {[type] }\n */\n parameterParser: qutils.toQueryFormat,\n\n // To allow epicenter.token and other session cookies to be passed\n // with the requests\n xhrFields: {\n withCredentials: true\n }\n };\n\n var transportOptions = $.extend({}, defaults, config);\n\n var result = function (d) {\n return ($.isFunction(d)) ? d() : d;\n };\n\n var connect = function (method, params, connectOptions) {\n params = result(params);\n params = ($.isPlainObject(params) || $.isArray(params)) ? JSON.stringify(params) : params;\n\n var options = $.extend(true, {}, transportOptions, connectOptions, {\n type: method,\n data: params\n });\n var ALLOWED_TO_BE_FUNCTIONS = ['data', 'url'];\n $.each(options, function (key, value) {\n if ($.isFunction(value) && $.inArray(key, ALLOWED_TO_BE_FUNCTIONS) !== -1) {\n options[key] = value();\n }\n });\n\n if (options.logLevel && options.logLevel === 'DEBUG') {\n console.log(options.url);\n var oldSuccessFn = options.success || $.noop;\n options.success = function (response, ajaxStatus, ajaxReq) {\n console.log(response);\n oldSuccessFn.apply(this, arguments);\n };\n }\n\n var beforeSend = options.beforeSend;\n options.beforeSend = function (xhr, settings) {\n xhr.requestUrl = (connectOptions || {}).url;\n if (beforeSend) {\n beforeSend.apply(this, arguments);\n }\n };\n\n return $.ajax(options);\n };\n\n var publicAPI = {\n get: function (params, ajaxOptions) {\n var options = $.extend({}, transportOptions, ajaxOptions);\n params = options.parameterParser(result(params));\n return connect.call(this, 'GET', params, options);\n },\n splitGet: function () {\n\n },\n post: function () {\n return connect.apply(this, ['post'].concat([].slice.call(arguments)));\n },\n patch: function () {\n return connect.apply(this, ['patch'].concat([].slice.call(arguments)));\n },\n put: function () {\n return connect.apply(this, ['put'].concat([].slice.call(arguments)));\n },\n delete: function (params, ajaxOptions) {\n //DELETE doesn't support body params, but jQuery thinks it does.\n var options = $.extend({}, transportOptions, ajaxOptions);\n params = options.parameterParser(result(params));\n if ($.trim(params)) {\n var delimiter = (result(options.url).indexOf('?') === -1) ? '?' : '&';\n options.url = result(options.url) + delimiter + params;\n }\n return connect.call(this, 'DELETE', null, options);\n },\n head: function () {\n return connect.apply(this, ['head'].concat([].slice.call(arguments)));\n },\n options: function () {\n return connect.apply(this, ['options'].concat([].slice.call(arguments)));\n }\n };\n\n return $.extend(this, publicAPI);\n};\n","'use strict';\n\n// var isNode = false; FIXME: Browserify/minifyify has issues with the next link\n// var transport = (isNode) ? require('./node-http-transport') : require('./ajax-http-transport');\nvar transport = require('./ajax-http-transport');\nmodule.exports = transport;\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* @param {Object} dest object to extend\n* @return {Object} extended 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 < obj.length; j++) {\n if (!(current = obj[j])) { //eslint-disable-line\n continue;\n }\n\n // do not wrap inner in dest.hasOwnProperty or bad things will happen\n for (var key in current) { //eslint-disable-line\n dest[key] = current[key];\n }\n }\n\n return dest;\n};\n\nmodule.exports = function (base, props, staticProps) {\n var parent = base;\n var child;\n\n child = props && props.hasOwnProperty('constructor') ? props.constructor : function () { return parent.apply(this, arguments); };\n\n // add static properties to the child constructor function\n extend(child, parent, staticProps);\n\n // associate prototype chain\n inherit(child, parent);\n\n // add instance properties\n if (props) {\n extend(child.prototype, props);\n }\n\n // done\n return child;\n};\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 isEmpty: function isEmpty(value) {\n return (!value || ($.isPlainObject(value) && Object.keys(value).length === 0));\n }\n};\n","'use strict';\n\nvar ConfigService = require('../service/configuration-service');\n\nvar urlConfig = new ConfigService().get('server');\nvar customDefaults = {};\nvar libDefaults = {\n /**\n * The account id. In the Epicenter UI, this is the **Team ID** (for team projects) or **User ID** (for personal projects). Defaults to empty string. If left undefined, taken from the URL.\n * @type {String}\n */\n account: urlConfig.accountPath || undefined,\n /**\n * The account id. In the Epicenter UI, this is the **Team ID** (for team projects) or **User ID** (for personal projects). Defaults to empty string. If left undefined, taken from the URL.\n * @type {String}\n */\n project: urlConfig.projectPath || undefined,\n isLocal: urlConfig.isLocalhost(),\n isCustomDomain: urlConfig.isCustomDomain,\n store: {}\n};\n\nvar optionUtils = {\n /**\n * Gets the final options by overriding the global options set with\n * optionUtils#setDefaults() and the lib defaults.\n * @param {object} options The final options object.\n * @return {object} Extended object\n */\n getOptions: function (options) {\n return $.extend(true, {}, libDefaults, customDefaults, options);\n },\n /**\n * Sets the global defaults for the optionUtils#getOptions() method.\n * @param {object} defaults The defaults object.\n */\n setDefaults: function (defaults) {\n customDefaults = defaults;\n }\n};\nmodule.exports = optionUtils;\n","/**\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 * 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 * normalizes different types of operation inputs\n * @param {Object|Array|String} operations operations to perform\n * @param {Array} args arguments for operation\n * @return {String} operations of the form `{ ops: [], args: [] }`\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; //eslint-disable-line\n var getValue = function (name) {\n var value = options[name] || httpOptions[name];\n if (typeof value === 'function') {\n value = value();\n }\n return value;\n };\n var getFinalUrl = function (params) {\n var url = getValue('url', options);\n var data = params;\n // There is easy (or known) way to get the final URL jquery is going to send so\n // we're replicating it. The process might change at some point but it probably will not.\n // 1. Remove hash\n url = url.replace(/#.*$/, '');\n // 1. Append query string\n var queryParams = qutil.toQueryFormat(data);\n var questionIdx = url.indexOf('?');\n if (queryParams && questionIdx > -1) {\n return url + '&' + queryParams;\n } else if (queryParams) {\n return url + '?' + queryParams;\n }\n return url;\n };\n var url = getFinalUrl(params);\n // We must split the GET in multiple short URL's\n // The only property allowed to be split is \"include\"\n if (params && params.include && encodeURI(url).length > MAX_URL_LENGTH) {\n var dtd = $.Deferred();\n var paramsCopy = $.extend(true, {}, params);\n delete paramsCopy.include;\n var urlNoIncludes = getFinalUrl(paramsCopy);\n var diff = MAX_URL_LENGTH - urlNoIncludes.length;\n var oldSuccess = options.success || httpOptions.success || $.noop;\n var oldError = options.error || httpOptions.error || $.noop;\n // remove the original success and error callbacks\n options.success = $.noop;\n options.error = $.noop;\n\n var include = params.include;\n var currIncludes = [];\n var includeOpts = [currIncludes];\n var currLength = encodeURIComponent('?include=').length;\n var variable = include.pop();\n while (variable) {\n var varLenght = encodeURIComponent(variable).length;\n // Use a greedy approach for now, can be optimized to be solved in a more\n // efficient way\n // + 1 is the comma\n if (currLength + varLenght + 1 < diff) {\n currIncludes.push(variable);\n currLength += varLenght + 1;\n } else {\n currIncludes = [variable];\n includeOpts.push(currIncludes);\n currLength = '?include='.length + varLenght;\n }\n variable = include.pop();\n }\n var reqs = $.map(includeOpts, function (include) {\n var reqParams = $.extend({}, params, { include: include });\n return http.get(reqParams, options);\n });\n $.when.apply($, reqs).then(function () {\n // Each argument are arrays of the arguments of each done request\n // So the first argument of the first array of arguments is the data\n var isValid = arguments[0] && arguments[0][0];\n if (!isValid) {\n // Should never happen...\n oldError();\n return dtd.reject();\n }\n var firstResponse = arguments[0][0];\n var isObject = $.isPlainObject(firstResponse);\n var isRunAPI = (isObject && $.isPlainObject(firstResponse.variables)) || !isObject;\n if (isRunAPI) {\n if (isObject) {\n // aggregate the variables property only\n var aggregateRun = arguments[0][0];\n $.each(arguments, function (idx, args) {\n var run = args[0];\n $.extend(true, aggregateRun.variables, run.variables);\n });\n oldSuccess(aggregateRun, arguments[0][1], arguments[0][2]);\n dtd.resolve(aggregateRun, arguments[0][1], arguments[0][2]);\n } else {\n // array of runs\n // Agregate variables in each run\n var aggregatedRuns = {};\n $.each(arguments, function (idx, args) {\n var runs = args[0];\n if (!$.isArray(runs)) {\n return;\n }\n $.each(runs, function (idxRun, run) {\n if (run.id && !aggregatedRuns[run.id]) {\n run.variables = run.variables || {};\n aggregatedRuns[run.id] = run;\n } else if (run.id) {\n $.extend(true, aggregatedRuns[run.id].variables, run.variables);\n }\n });\n });\n // turn it into an array\n aggregatedRuns = $.map(aggregatedRuns, function (run) { return run; });\n oldSuccess(aggregatedRuns, arguments[0][1], arguments[0][2]);\n dtd.resolve(aggregatedRuns, arguments[0][1], arguments[0][2]);\n }\n } else {\n // is variables API\n // aggregate the response\n var aggregatedVariables = {};\n $.each(arguments, function (idx, args) {\n var vars = args[0];\n $.extend(true, aggregatedVariables, vars);\n });\n oldSuccess(aggregatedVariables, arguments[0][1], arguments[0][2]);\n dtd.resolve(aggregatedVariables, arguments[0][1], arguments[0][2]);\n }\n }, function () {\n oldError.apply(http, arguments);\n dtd.reject.apply(dtd, arguments);\n });\n return dtd.promise();\n } else {\n return http.get(params, options);\n }\n };\n }\n };\n}());\n"]} \ No newline at end of file +{"version":3,"sources":["node_modules/browser-pack/_prelude.js","src/api-version.json","node_modules/Base64/base64.js","node_modules/object-assign/index.js","src/app.js","src/env-load.js","src/managers/auth-manager.js","src/managers/channel-manager.js","src/managers/epicenter-channel-manager.js","src/managers/key-names.js","src/managers/run-manager.js","src/managers/run-strategies/conditional-creation-strategy.js","src/managers/run-strategies/deprecated/new-if-initialized-strategy.js","src/managers/run-strategies/deprecated/new-if-persisted-strategy.js","src/managers/run-strategies/index.js","src/managers/run-strategies/multiplayer-strategy.js","src/managers/run-strategies/none-strategy.js","src/managers/run-strategies/reuse-across-sessions.js","src/managers/run-strategies/reuse-last-initialized.js","src/managers/run-strategies/reuse-never.js","src/managers/run-strategies/reuse-per-session.js","src/managers/saved-runs-manager.js","src/managers/scenario-manager.js","src/managers/scenario-strategies/baseline-strategy.js","src/managers/scenario-strategies/reuse-last-unsaved.js","src/managers/special-operations.js","src/managers/strategy-utils.js","src/managers/world-manager.js","src/service/admin-file-service.js","src/service/asset-api-adapter.js","src/service/auth-api-service.js","src/service/channel-service.js","src/service/configuration-service.js","src/service/data-api-service.js","src/service/group-api-service.js","src/service/introspection-api-service.js","src/service/member-api-adapter.js","src/service/presence-api-service.js","src/service/run-api-service.js","src/service/service-utils.js","src/service/state-api-adapter.js","src/service/url-config-service.js","src/service/user-api-adapter.js","src/service/variables-api-service.js","src/service/world-api-adapter.js","src/store/cookie-store.js","src/store/session-manager.js","src/store/store-factory.js","src/transport/ajax-http-transport.js","src/transport/http-transport-factory.js","src/util/inherit.js","src/util/object-util.js","src/util/option-utils.js","src/util/query-util.js","src/util/run-util.js"],"names":["InvalidCharacterError","message","this","object","exports","self","chars","prototype","Error","name","btoa","input","str","String","block","charCode","idx","map","output","charAt","charCodeAt","atob","replace","length","bs","buffer","bc","fromCharCode","indexOf","toObject","val","undefined","TypeError","Object","shouldUseNative","assign","test1","getOwnPropertyNames","test2","i","order2","n","join","test3","split","forEach","letter","keys","e","hasOwnProperty","propIsEnumerable","propertyIsEnumerable","module","target","source","from","to","symbols","s","arguments","key","call","getOwnPropertySymbols","F","_private","util","factory","transport","store","service","manager","strategy","load","require","global","SKIP_ENV_LOAD","query","run","classFrom","strategyutils","Transport","Ajax","URL","Config","Run","File","Variables","Data","Auth","World","State","User","Member","Asset","Group","Introspect","Presence","Cookie","Store","ScenarioManager","RunManager","AuthManager","WorldManager","SavedRunsManager","strategies","list","ChannelManager","Channel","version","api","constants","URLConfigService","envLoad","callback","urlService","infoUrl","getAPIPath","envPromise","$","ajax","url","async","then","res","overrides","defaults","extend","fail","options","sessionManager","SessionManager","getMergedOptions","authAdapter","AuthAdapter","MemberAdapter","GroupService","_pick","objectAssign","window","requiresGroup","_findUserInGroup","members","id","j","userId","login","me","$d","Deferred","adapterOptions","success","noop","error","outSuccess","outError","groupId","decodeToken","token","encoded","JSON","parse","handleGroupError","statusCode","data","type","logout","statusText","status","reject","handleSuccess","response","access_token","userInfo","oldGroups","getSession","groups","userGroupOpts","auth","user","project","isTeamMember","parent_account_id","userName","user_name","sessionInfo","auth_token","account","user_id","saveSession","apply","resolve","handleGroupList","groupList","userGroups","group","filteredGroups","grep","resGroup","isFac","role","groupData","groupName","sessionInfoWithGroup","opts","groupService","getGroups","getUserGroups","promise","removeCookieFn","removeSession","getToken","httpOptions","session","params","memberInfo","memberAdapter","server","getGroupsForUser","isLoggedIn","getCurrentUserSessionInfo","addGroups","isArray","Array","each","index","extendedGroup","validProps","cometd","logLevel","websocketEnabled","ackEnabled","shareConnection","channel","handshake","defaultCometOptions","currentSubscriptions","_cometd","CometD","isConnected","connectionBroken","trigger","connectionSucceeded","configure","addListener","wasConnected","successful","bind","batch","subs","resubscribe","getChannel","isPlainObject","base","subscribe","subid","concat","unsubs","unsubscribe","removed","splice","on","event","off","ConfigService","validTypes","world","general","chat","getFromSessionOrError","value","sessionKeyName","settings","isPresenceData","payload","__super","EpicenterChannelManager","constructor","urlConfig","get","userProp","ext","authorization","channelOpts","allowAllChannels","baseParts","channelType","getGroupChannel","baseTopic","oldsubs","topic","context","callbackWithoutPresenceData","getWorldChannel","worldid","getUserChannel","userid","getPresenceChannel","callbackWithOnlyPresenceData","getDataChannel","collection","callbackWithCleanData","meta","path","subType","date","dataPath","actualData","EPI_SESSION_KEY","STRATEGY_SESSION_KEY","patchRunService","patched","orig","do","operation","reservedOps","specialOperations","sessionKeyFromOptions","runService","config","getCurrentConfig","sessionKey","isFunction","setRunInSession","variables","getStore","set","stringify","RunService","isEmpty","getBestStrategy","keyNames","baseKey","reduce","accum","getRun","sessionStore","sessionContents","runSession","runId","authSession","requiresAuth","console","updateConfig","filter","results","catch","err","reset","Base","Strategy","condition","userSession","opt","scope","create","freshlyCreated","loadAndCheck","shouldCreate","msg","headers","ConditionalStrategy","createIf","warn","getResponseHeader","initialized","conditional-creation","new-if-initialized","new-if-persisted","none","multiplayer","reuse-never","reuse-per-session","reuse-across-sessions","reuse-last-initialized","byName","strategyName","strategyOptions","initOperation","StrategyCtor","strategyInstance","register","IdentityStrategy","WorldApiAdapter","worldApi","curUserId","curGroupName","getCurrentWorldForUser","newRunForWorld","runid","model","dtd","loadRunFromWorld","getCurrentRunId","serverError","injectFiltersFromSession","injectScopeFromSession","startrecord","endrecord","sort","direction","runs","flag","isInitComplete","createResponse","serial","save","patchResponse","sessionFilter","runopts","trashed","scopeByGroup","scopeByUser","otherFields","param","saved","mark","remove","toMark","rs","existingOptions","proms","r","when","autoRestore","getRuns","modifiers","scopedFilter","opModifiers","include","cookieNameFromOptions","prefix","advanceOperation","BaselineStrategyToUse","includeBaseLine","BaselineStrategy","NoneStrategy","baseline","strategyUtils","mergeRunOptions","baselineName","runName","savedRuns","origGetRuns","args","current","LastUnsavedStrategy","saveAndAdvance","metadata","clone","sa","StateService","advanceOpns","rutil","normalizeOperations","exclude","ops","markSaved","savedResponse","advance","ReuseinitStrategy","stepTo","outputModifiers","currentFilter","currentParams","buildStrategy","worldId","resolveWith","WorldApi","_auth","getCurrentWorld","getCurrentRun","getAndRestoreLatestRun","currentWorldId","runOpts","rm","TransportFactory","uploadBody","fileName","contents","boundary","body","uploadFileOptions","filePath","pop","serviceOptions","folderType","extraParams","FormData","processData","contentType","upload","accountPath","projectPath","Authorization","http","publicAsyncAPI","getContents","put","replaceExisting","prom","post","xhr","conflictStatus","delete","rename","newName","patch","apiEndpoint","fullUrl","transportOptions","assetApiParams","scopeConfig","validateFilename","filename","validateUrlParams","partKeys","buildUrl","parts","method","toLowerCase","urlOptions","createOptions","publicAPI","getServiceOptions","getOptions","files","fullPathFiles","file","assetUrl","password","resp","statusMessage","postParams","topicResolver","channelOptions","makeName","channelName","topics","subscriptionIds","push","publish","returnObjs","setEnv","env","property","qutil","root","getURL","addTrailingSlash","outputModifier","q","attrs","saveAs","serviceUtils","getDefaultOptions","finalOpts","finalParams","getApiUrl","byModel","modelFile","byRunID","runID","getFinalParams","patchUserActiveField","active","isString","objParams","getParms","getGroupDetails","makeUserActive","makeUserInactive","markOnline","markOffline","getStatus","cm","VariablesService","IntrospectionService","updateURLConfig","getFilterURL","filterMatrix","toMatrixFormat","addAutoRestoreHeader","isFilterRunId","autorestoreOpts","X-AutoRestore","updateHTTPConfig","splitGet","splitGetFactory","setFilterOrThrowError","runApiParams","oldSuccess","qs","filters","removeFromMemory","attributes","opsArgs","postOptions","result","prms","operations","opParams","responses","doSingleOp","op","shift","arg","parallel","queue","slice","actualResponse","a","introspect","introspectionConfig","introspection","publicSyncAPI","vs","rest","parseRunIdOrError","httpParams","replay","replayOptions","action","getLocalHost","existingFn","host","localHostFn","isLocal","epiVersion","location","pathname","UrlConfigService","envConf","isLocalhost","actingHost","API_PROTOCOL","HOST_API_MAPPING","forio.com","foriodev.com","publicExports","protocol","apiHost","isCustomDomain","pathHasApp","appPath","accnt","prj","versionPath","PROJECT_APIS","apiMapping","actualProtocol","configProtocol","apiPath","inArray","toQFilter","toIdFilters","getFilters","toQueryFormat","threshold","getById","variable","apiBase","assignmentEndpoint","projectEndpoint","setIdFilterOrThrowError","validateModelOrThrowError","worldApiParams","validParams","update","whitelist","updateOptions","deleteOptions","getWorldsForUser","addUsers","users","u","isObject","updateUser","patchOptions","removeUser","worlds","b","Date","lastModified","currentWorld","deleteRun","currentRunOptions","autoAssign","maxUsers","userIds","getProjectSettings","document","cookie","newCookie","hostname","validHost","domain","setOptions","encodeURIComponent","cookieReg","RegExp","exec","decodeURIComponent","remOptions","destroy","aKeys","nIdx","cookieKey","StorageFactory","optionUtils","EPI_MANAGER_KEY","synchronous","managerOptions","getBaseOptions","libOptions","finalOptions","baseOptions","storeOpts","isEpicenterDomain","serialized","cookieName","sessionDefaults","qutils","404","parameterParser","xhrFields","withCredentials","d","connect","connectOptions","ALLOWED_TO_BE_FUNCTIONS","log","oldSuccessFn","ajaxStatus","ajaxReq","beforeSend","requestUrl","ajaxOptions","trim","delimiter","head","inherit","C","P","dest","obj","props","staticProps","parent","child","p","customDefaults","libDefaults","setDefaults","returnArray","OPERATORS","mtrx","qsToObject","qsArray","returnObj","qKey","qVal","mergeQS","qs1","qs2","obj1","obj2","MAX_URL_LENGTH","returnList","_concat","arr","_normalizePlainObjects","opn","_normalizeStructuredObjects","_normalizeObject","_normalizeLiterals","_normalizeArrays","getValue","getFinalUrl","queryParams","questionIdx","encodeURI","paramsCopy","urlNoIncludes","diff","oldError","currIncludes","includeOpts","currLength","varLenght","reqs","reqParams","isValid","firstResponse","isRunAPI","aggregateRun","aggregatedRuns","idxRun","aggregatedVariables","vars"],"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> 8 - idx % 1 * 8)\n ) {\n charCode = str.charCodeAt(idx += 3/4);\n if (charCode > 0xFF) {\n throw new InvalidCharacterError(\"'btoa' failed: The string to be encoded contains characters outside of the Latin1 range.\");\n }\n block = block << 8 | charCode;\n }\n return output;\n });\n\n // decoder\n // [https://gist.github.com/1020396] by [https://github.com/atk]\n object.atob || (\n object.atob = function (input) {\n var str = String(input).replace(/=+$/, '');\n if (str.length % 4 == 1) {\n throw new InvalidCharacterError(\"'atob' failed: The string to be decoded is not correctly encoded.\");\n }\n for (\n // initialize result and counters\n var bc = 0, bs, buffer, idx = 0, output = '';\n // get next character\n buffer = str.charAt(idx++);\n // character found in table? initialize bit storage and add its ascii value;\n ~buffer && (bs = bc % 4 ? bs * 64 + buffer : buffer,\n // and if not first of each 4 characters,\n // convert the first 8 bits to one ascii character\n bc++ % 4) ? output += String.fromCharCode(255 & bs >> (-2 * bc & 6)) : 0\n ) {\n // try to find character in table (0-63, not found => -1)\n buffer = chars.indexOf(buffer);\n }\n return output;\n });\n\n}());\n","'use strict';\n/* eslint-disable no-unused-vars */\nvar hasOwnProperty = Object.prototype.hasOwnProperty;\nvar propIsEnumerable = Object.prototype.propertyIsEnumerable;\n\nfunction toObject(val) {\n\tif (val === null || val === undefined) {\n\t\tthrow new TypeError('Object.assign cannot be called with null or undefined');\n\t}\n\n\treturn Object(val);\n}\n\nfunction shouldUseNative() {\n\ttry {\n\t\tif (!Object.assign) {\n\t\t\treturn false;\n\t\t}\n\n\t\t// Detect buggy property enumeration order in older V8 versions.\n\n\t\t// https://bugs.chromium.org/p/v8/issues/detail?id=4118\n\t\tvar test1 = new String('abc'); // eslint-disable-line\n\t\ttest1[5] = 'de';\n\t\tif (Object.getOwnPropertyNames(test1)[0] === '5') {\n\t\t\treturn false;\n\t\t}\n\n\t\t// https://bugs.chromium.org/p/v8/issues/detail?id=3056\n\t\tvar test2 = {};\n\t\tfor (var i = 0; i < 10; i++) {\n\t\t\ttest2['_' + String.fromCharCode(i)] = i;\n\t\t}\n\t\tvar order2 = Object.getOwnPropertyNames(test2).map(function (n) {\n\t\t\treturn test2[n];\n\t\t});\n\t\tif (order2.join('') !== '0123456789') {\n\t\t\treturn false;\n\t\t}\n\n\t\t// https://bugs.chromium.org/p/v8/issues/detail?id=3056\n\t\tvar test3 = {};\n\t\t'abcdefghijklmnopqrst'.split('').forEach(function (letter) {\n\t\t\ttest3[letter] = letter;\n\t\t});\n\t\tif (Object.keys(Object.assign({}, test3)).join('') !==\n\t\t\t\t'abcdefghijklmnopqrst') {\n\t\t\treturn false;\n\t\t}\n\n\t\treturn true;\n\t} catch (e) {\n\t\t// We don't expect any of the above to throw, but better to be safe.\n\t\treturn false;\n\t}\n}\n\nmodule.exports = shouldUseNative() ? Object.assign : function (target, source) {\n\tvar from;\n\tvar to = toObject(target);\n\tvar symbols;\n\n\tfor (var s = 1; s < arguments.length; s++) {\n\t\tfrom = Object(arguments[s]);\n\n\t\tfor (var key in from) {\n\t\t\tif (hasOwnProperty.call(from, key)) {\n\t\t\t\tto[key] = from[key];\n\t\t\t}\n\t\t}\n\n\t\tif (Object.getOwnPropertySymbols) {\n\t\t\tsymbols = Object.getOwnPropertySymbols(from);\n\t\t\tfor (var i = 0; i < symbols.length; i++) {\n\t\t\t\tif (propIsEnumerable.call(from, symbols[i])) {\n\t\t\t\t\tto[symbols[i]] = from[symbols[i]];\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\treturn to;\n};\n","/**\n * Epicenter Javascript libraries\n * v<%= version %>\n * https://github.com/forio/epicenter-js-libs\n */\n\nvar F = {\n _private: {}, //need this hook now because tests expect everything to be global. Delete once tests are browserified\n util: {},\n factory: {},\n transport: {},\n store: {},\n service: {},\n manager: {\n strategy: {}\n },\n\n};\n\nF.load = require('./env-load');\n\nif (!global.SKIP_ENV_LOAD) {\n F.load();\n}\n\nF.util.query = require('./util/query-util');\nF.util.run = require('./util/run-util');\nF.util.classFrom = require('./util/inherit');\nF._private.strategyutils = require('./managers/strategy-utils');\n\nF.factory.Transport = require('./transport/http-transport-factory');\nF.transport.Ajax = require('./transport/ajax-http-transport');\n\nF.service.URL = require('./service/url-config-service');\nF.service.Config = require('./service/configuration-service');\nF.service.Run = require('./service/run-api-service');\nF.service.File = require('./service/admin-file-service');\nF.service.Variables = require('./service/variables-api-service');\nF.service.Data = require('./service/data-api-service');\nF.service.Auth = require('./service/auth-api-service');\nF.service.World = require('./service/world-api-adapter');\nF.service.State = require('./service/state-api-adapter');\nF.service.User = require('./service/user-api-adapter');\nF.service.Member = require('./service/member-api-adapter');\nF.service.Asset = require('./service/asset-api-adapter');\nF.service.Group = require('./service/group-api-service');\nF.service.Introspect = require('./service/introspection-api-service');\nF.service.Presence = require('./service/presence-api-service');\n\nF.store.Cookie = require('./store/cookie-store');\nF.factory.Store = require('./store/store-factory');\n\nF.manager.ScenarioManager = require('./managers/scenario-manager');\nF.manager.RunManager = require('./managers/run-manager');\nF.manager.AuthManager = require('./managers/auth-manager');\nF.manager.WorldManager = require('./managers/world-manager');\nF.manager.SavedRunsManager = require('./managers/saved-runs-manager');\n\nvar strategies = require('./managers/run-strategies');\nF.manager.strategy = strategies.list; //TODO: this is not really a manager so namespace this better\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\nF.constants = require('./managers/key-names');\n\nglobal.F = F;\nmodule.exports = F;\n","'use strict';\n\nvar URLConfigService = require('./service/url-config-service');\n\nvar envLoad = function (callback) {\n var urlService = new URLConfigService();\n var infoUrl = urlService.getAPIPath('config');\n var envPromise = $.ajax({ url: infoUrl, async: false });\n envPromise = envPromise.then(function (res) {\n var overrides = res.api;\n URLConfigService.defaults = $.extend(URLConfigService.defaults, overrides);\n });\n return envPromise.then(callback).fail(callback);\n};\n\nmodule.exports = envLoad;\n","/**\n* ## Authorization Manager\n*\n* The Authorization Manager provides an easy way to manage user authentication (logging in and out) and authorization (keeping track of tokens, sessions, and groups) for projects.\n*\n* The Authorization Manager is most useful for [team projects](../../../glossary/#team) with an access level of [Authenticated](../../../glossary/#access). These projects are accessed by [end users](../../../glossary/#users) who are members of one or more [groups](../../../glossary/#groups).\n*\n* #### Using the Authorization Manager\n*\n* To use the Authorization Manager, instantiate it. Then, make calls to any of the methods you need:\n*\n* var authMgr = new F.manager.AuthManager({\n* account: 'acme-simulations',\n* userName: 'enduser1',\n* password: 'passw0rd'\n* });\n* authMgr.login().then(function () {\n* authMgr.getCurrentUserSessionInfo();\n* });\n*\n*\n* The `options` object passed to the `F.manager.AuthManager()` call can include:\n*\n* * `account`: The account id for this `userName`. In the Epicenter UI, this is the **Team ID** (for team projects) or the **User ID** (for personal projects).\n* * `userName`: Email or username to use for logging in.\n* * `password`: Password for specified `userName`.\n* * `project`: The **Project ID** for the project to log this user into. Optional.\n* * `groupId`: Id of the group to which `userName` belongs. Required for end users if the `project` is specified.\n*\n* If you prefer starting from a template, the Epicenter JS Libs [Login Component](../../#components) uses the Authorization Manager as well. This sample HTML page (and associated CSS and JS files) provides a login form for team members and end users of your project. It also includes a group selector for end users that are members of multiple groups.\n*/\n\n'use strict';\nvar AuthAdapter = require('../service/auth-api-service');\nvar MemberAdapter = require('../service/member-api-adapter');\nvar GroupService = require('../service/group-api-service');\nvar SessionManager = require('../store/session-manager');\nvar _pick = require('../util/object-util')._pick;\nvar objectAssign = require('object-assign');\n\nvar atob = window.atob || require('Base64').atob;\n\nvar defaults = {\n requiresGroup: true\n};\n\nfunction AuthManager(options) {\n options = $.extend(true, {}, defaults, options);\n this.sessionManager = new SessionManager(options);\n this.options = this.sessionManager.getMergedOptions();\n\n this.authAdapter = new AuthAdapter(this.options);\n}\n\nvar _findUserInGroup = function (members, id) {\n for (var j = 0; j < members.length; j++) {\n if (members[j].userId === id) {\n return members[j];\n }\n }\n return null;\n};\n\nAuthManager.prototype = $.extend(AuthManager.prototype, {\n\n /**\n * Logs user in.\n *\n * **Example**\n *\n * authMgr.login({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * userName: 'enduser1',\n * password: 'passw0rd'\n * })\n * .then(function(statusObj) {\n * // if enduser1 belongs to exactly one group\n * // (or if the login() call is modified to include the group id)\n * // continue here\n * })\n * .fail(function(statusObj) {\n * // if enduser1 belongs to multiple groups,\n * // the login() call fails\n * // and returns all groups of which the user is a member\n * for (var i=0; i < statusObj.userGroups.length; i++) {\n * console.log(statusObj.userGroups[i].name, statusObj.userGroups[i].groupId);\n * }\n * });\n *\n * **Parameters**\n *\n * @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:\n * @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).\n * @param {string} options.userName Email or username to use for logging in.\n * @param {string} options.password Password for specified `userName`.\n * @param {string} options.project (Optional) The **Project ID** for the project to log this user into.\n * @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.\n * @return {Promise}\n */\n login: function (options) {\n var me = this;\n var $d = $.Deferred();\n var sessionManager = this.sessionManager;\n var adapterOptions = sessionManager.getMergedOptions({ success: $.noop, error: $.noop }, options);\n var outSuccess = adapterOptions.success;\n var outError = adapterOptions.error;\n var groupId = adapterOptions.groupId;\n\n var decodeToken = function (token) {\n var encoded = token.split('.')[1];\n while (encoded.length % 4 !== 0) { //eslint-disable-line\n encoded += '=';\n }\n return JSON.parse(atob(encoded));\n };\n\n var handleGroupError = function (message, statusCode, data, type) {\n // logout the user since it's in an invalid state with no group selected\n me.logout().then(function () {\n var error = $.extend(true, {}, data, { statusText: message, status: statusCode, type: type });\n $d.reject(error);\n });\n };\n\n var handleSuccess = function (response) {\n var token = response.access_token;\n var userInfo = decodeToken(token);\n var oldGroups = sessionManager.getSession(adapterOptions).groups || {};\n var userGroupOpts = $.extend(true, {}, adapterOptions, { success: $.noop });\n var data = { auth: response, user: userInfo };\n var project = adapterOptions.project;\n var isTeamMember = userInfo.parent_account_id === null;\n var requiresGroup = adapterOptions.requiresGroup && project;\n\n var userName = (userInfo.user_name || '').split('/')[0]; //of form /\n var sessionInfo = {\n auth_token: token,\n account: adapterOptions.account,\n project: project,\n userId: userInfo.user_id,\n groups: oldGroups,\n isTeamMember: isTeamMember,\n userName: userName,\n };\n // The group is not required if the user is not logging into a project\n if (!requiresGroup) {\n sessionManager.saveSession(sessionInfo);\n outSuccess.apply(this, [data]);\n $d.resolve(data);\n return;\n }\n\n var handleGroupList = function (groupList) {\n data.userGroups = groupList;\n\n var group = null;\n if (groupList.length === 0) {\n handleGroupError('The user has no groups associated in this account', 403, data, 'NO_GROUPS');\n return;\n } else if (groupList.length === 1) {\n // Select the only group\n group = groupList[0];\n } else if (groupList.length > 1) {\n if (groupId) {\n var filteredGroups = $.grep(groupList, function (resGroup) {\n return resGroup.groupId === groupId;\n });\n group = filteredGroups.length === 1 ? filteredGroups[0] : null;\n }\n }\n\n if (group) {\n // A team member does not get the group members because is calling the Group API\n // but it's automatically a fac user\n var isFac = isTeamMember ? true : _findUserInGroup(group.members, userInfo.user_id).role === 'facilitator';\n var groupData = {\n groupId: group.groupId,\n groupName: group.name,\n isFac: isFac\n };\n var sessionInfoWithGroup = objectAssign({}, sessionInfo, groupData);\n sessionInfo.groups[project] = groupData;\n me.sessionManager.saveSession(sessionInfoWithGroup, adapterOptions);\n outSuccess.apply(this, [data]);\n $d.resolve(data);\n } else {\n handleGroupError('This user is associated with more than one group. Please specify a group id to log into and try again', 403, data, 'MULTIPLE_GROUPS');\n }\n };\n\n if (!isTeamMember) {\n me.getUserGroups({ userId: userInfo.user_id, token: token }, userGroupOpts)\n .then(handleGroupList, $d.reject);\n } else {\n var opts = objectAssign({}, userGroupOpts, { token: token });\n var groupService = new GroupService(opts);\n groupService.getGroups({ account: adapterOptions.account, project: project })\n .then(function (groups) {\n // Group API returns id instead of groupId\n groups.forEach(function (group) {\n group.groupId = group.id;\n });\n\n if (groups.length) {\n handleGroupList(groups);\n } else {\n //either it's a private project or there are no groups\n sessionManager.saveSession(sessionInfo);\n outSuccess.apply(this, [data]);\n $d.resolve(data);\n return;\n }\n }, $d.reject);\n }\n };\n\n adapterOptions.success = handleSuccess;\n adapterOptions.error = function (response) {\n if (adapterOptions.account) {\n // Try to login as a system user\n adapterOptions.account = null;\n adapterOptions.error = function () {\n outError.apply(this, arguments);\n $d.reject(response);\n };\n\n me.authAdapter.login(adapterOptions);\n return;\n }\n\n outError.apply(this, arguments);\n $d.reject(response);\n };\n\n this.authAdapter.login(adapterOptions);\n return $d.promise();\n },\n\n /**\n * Logs user out by clearing all session information.\n *\n * **Example**\n *\n * authMgr.logout();\n *\n * **Parameters**\n *\n * @param {Object} options (Optional) Overrides for configuration options.\n * @return {Promise}\n */\n logout: function (options) {\n var me = this;\n var adapterOptions = this.sessionManager.getMergedOptions(options);\n\n var removeCookieFn = function (response) {\n me.sessionManager.removeSession();\n };\n\n return this.authAdapter.logout(adapterOptions).then(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 * @return {Promise}\n */\n getToken: function (options) {\n var httpOptions = this.sessionManager.getMergedOptions(options);\n\n var session = this.sessionManager.getSession(httpOptions);\n var $d = $.Deferred();\n if (session.auth_token) {\n $d.resolve(session.auth_token);\n } else {\n this.login(httpOptions).then($d.resolve);\n }\n return $d.promise();\n },\n\n /**\n * Returns an array of group records, one for each group of which the current user is a member. Each group record includes the group `name`, `account`, `project`, and `groupId`.\n *\n * If some end users in your project are members of multiple groups, this is a useful method to call on your project's login page. When the user attempts to log in, you can use this to display the groups of which the user is member, and have the user select the correct group to log in to for this session.\n *\n * **Example**\n *\n * // get groups for current user\n * var sessionObj = authMgr.getCurrentUserSessionInfo();\n * authMgr.getUserGroups({ userId: sessionObj.userId, token: sessionObj.auth_token })\n * .then(function (groups) {\n * for (var i=0; i < groups.length; i++)\n * { console.log(groups[i].name); }\n * });\n *\n * // get groups for particular user\n * authMgr.getUserGroups({userId: 'b1c19dda-2d2e-4777-ad5d-3929f17e86d3', token: savedProjAccessToken });\n *\n * **Parameters**\n * @param {Object} params Object with a userId and token properties.\n * @param {String} params.userId The userId. If looking up groups for the currently logged in user, this is in the session information. Otherwise, pass a string.\n * @param {String} params.token The authorization credentials (access token) to use for checking the groups for this user. If looking up groups for the currently logged in user, this is in the session information. A team member's token or a project access token can access all the groups for all end users in the team or project.\n * @param {Object} options (Optional) Overrides for configuration options.\n * @return {Promise}\n */\n getUserGroups: function (params, options) {\n var adapterOptions = this.sessionManager.getMergedOptions({ success: $.noop }, options);\n var $d = $.Deferred();\n var outSuccess = adapterOptions.success;\n\n adapterOptions.success = function (memberInfo) {\n // The member API is at the account scope, we filter by project\n if (adapterOptions.project) {\n memberInfo = $.grep(memberInfo, function (group) {\n return group.project === adapterOptions.project;\n });\n }\n\n outSuccess.apply(this, [memberInfo]);\n $d.resolve(memberInfo);\n };\n\n var memberAdapter = new MemberAdapter({ token: params.token, server: adapterOptions.server });\n memberAdapter.getGroupsForUser(params, adapterOptions).fail($d.reject);\n return $d.promise();\n },\n\n /**\n * Helper method to check if you're currently logged in\n *\n * **Example**\n * \n * var amILoggedIn = authMgr.isLoggedIn();\n *\n * **Parameters**\n * @param {none} none\n * @return {Boolean} true if you're logged in\n */\n isLoggedIn: function () {\n var session = this.getCurrentUserSessionInfo();\n return !!(session && session.userId);\n },\n\n /**\n * Returns session information for the current user, including the `userId`, `account`, `project`, `groupId`, `groupName`, `isFac` (whether the end user is a facilitator of this group), and `auth_token` (user access token).\n *\n * *Important*: This method is synchronous. The session information is returned immediately in an object; no callbacks or promises are needed.\n *\n * Session information is stored in a cookie in the browser.\n *\n * **Example**\n *\n * var sessionObj = authMgr.getCurrentUserSessionInfo();\n *\n * **Parameters**\n * @param {Object} options (Optional) Overrides for configuration options.\n * @return {Object} session information\n */\n getCurrentUserSessionInfo: function (options) {\n var adapterOptions = this.sessionManager.getMergedOptions({ success: $.noop }, options);\n return this.sessionManager.getSession(adapterOptions);\n },\n\n /*\n * Adds one or more groups to the current session. \n *\n * This method assumes that the project and group exist and the user specified in the session is part of this project and group.\n *\n * Returns the new session object.\n *\n * **Example**\n *\n * authMgr.addGroups({ project: 'hello-world', groupName: 'groupName', groupId: 'groupId' });\n * authMgr.addGroups([{ project: 'hello-world', groupName: 'groupName', groupId: 'groupId' }, { project: 'hello-world', groupName: '...' }]);\n *\n * **Parameters**\n * @param {object|array} groups (Required) The group object must contain the `project` (**Project ID**) and `groupName` properties. If passing an array of such objects, all of the objects must contain *different* `project` (**Project ID**) values: although end users may be logged in to multiple projects at once, they may only be logged in to one group per project at a time.\n * @param {string} group.isFac (optional) Defaults to `false`. Set to `true` if the user in the session should be a facilitator in this group.\n * @param {string} group.groupId (optional) Defaults to undefined. Needed mostly for the Members API.\n * @return {Object} session information\n */\n addGroups: function (groups) {\n var session = this.getCurrentUserSessionInfo();\n var isArray = Array.isArray(groups);\n groups = isArray ? groups : [groups];\n\n $.each(groups, function (index, group) {\n var extendedGroup = $.extend({}, { isFac: false }, group);\n var project = extendedGroup.project;\n var validProps = ['groupName', 'groupId', 'isFac'];\n if (!project || !extendedGroup.groupName) {\n throw new Error('No project or groupName specified.');\n }\n // filter object\n extendedGroup = _pick(extendedGroup, validProps);\n session.groups[project] = extendedGroup;\n });\n this.sessionManager.saveSession(session);\n return session;\n }\n});\n\nmodule.exports = AuthManager;\n","'use strict';\n\n/**\n * ## Channel Manager\n *\n * There are two main use cases for the channel: event notifications and chat messages.\n *\n * If you are developing with Epicenter.js, you should use the [Epicenter Channel Manager](../epicenter-channel-manager/) rather than this more generic Channel Manager. (The Epicenter Channel Manager is a wrapper that instantiates a Channel Manager with Epicenter-specific defaults.) The Epicenter Channel Manager documentation also has more [background](../epicenter-channel-manager/#background) information on channels and their use. \n *\n * However, you can work directly with the Channel Manager if you like. (This might be useful if you are working through Node.js, for example, `require('manager/channel-manager')`.)\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 * 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 a particular channel -- that is, an instance of a [Channel Service](../channel-service/) -- 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 * // because we used an Epicenter Channel Manager to get the group channel,\n * // subscribe() and publish() here default to the base topic for the group;\n * gc.subscribe('', function(data) { console.log(data); });\n * gc.publish('', { message: 'a new message to the group' });\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 */\n\nvar Channel = require('../service/channel-service');\nvar SessionManager = require('../store/session-manager');\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 `true`.\n * @type {boolean}\n */\n websocketEnabled: true,\n\n /**\n * Whether the ACK extension is enabled. Defaults to `true`. See [https://docs.cometd.org/current/reference/#_extensions_acknowledge](https://docs.cometd.org/current/reference/#_extensions_acknowledge) for more info.\n * @type {boolean}\n */\n ackEnabled: true,\n\n /**\n * If false each instance of Channel will have a separate cometd connection to server, which could be noisy. Set to true to re-use the same connection across instances.\n * @type {boolean}\n */\n shareConnection: false,\n\n /**\n * Other defaults to pass on to instances of the underlying [Channel Service](../channel-service/), which are created through `getChannel()`.\n * @type {object}\n */\n channel: {\n\n },\n\n /**\n * Options to pass to the channel handshake.\n *\n * For example, the [Epicenter Channel Manager](../epicenter-channel-manager/) passes `ext` and authorization information. More information on possible options is in the details of the underlying [Push Channel API](../../../rest_apis/multiplayer/channel/).\n *\n * @type {object}\n */\n handshake: undefined\n };\n this.sessionManager = new SessionManager();\n var defaultCometOptions = this.sessionManager.getMergedOptions(defaults, options);\n this.currentSubscriptions = [];\n this.options = defaultCometOptions;\n\n if (defaultCometOptions.shareConnection && ChannelManager.prototype._cometd) {\n this.cometd = ChannelManager.prototype._cometd;\n return this;\n }\n var cometd = new $.CometD();\n ChannelManager.prototype._cometd = cometd;\n\n cometd.websocketEnabled = defaultCometOptions.websocketEnabled;\n cometd.ackEnabled = defaultCometOptions.ackEnabled;\n\n this.isConnected = false;\n var connectionBroken = function (message) {\n $(this).trigger('disconnect', message);\n };\n var connectionSucceeded = function (message) {\n $(this).trigger('connect', message);\n };\n var me = this;\n\n cometd.configure(defaultCometOptions);\n\n cometd.addListener('/meta/connect', function (message) {\n var wasConnected = this.isConnected;\n this.isConnected = (message.successful === true);\n if (!wasConnected && this.isConnected) { //Connecting for the first time\n connectionSucceeded.call(this, message);\n } else if (wasConnected && !this.isConnected) { //Only throw disconnected message fro the first disconnect, not once per try\n connectionBroken.call(this, message);\n }\n }.bind(this));\n\n cometd.addListener('/meta/disconnect', connectionBroken);\n\n cometd.addListener('/meta/handshake', function (message) {\n if (message.successful) {\n //http://docs.cometd.org/reference/javascript_subscribe.html#javascript_subscribe_meta_channels\n // ^ \"dynamic subscriptions are cleared (like any other subscription) and the application needs to figure out which dynamic subscription must be performed again\"\n cometd.batch(function () {\n $(me.currentSubscriptions).each(function (index, subs) {\n cometd.resubscribe(subs);\n });\n });\n }\n });\n\n //Other interesting events for reference\n cometd.addListener('/meta/subscribe', function (message) {\n $(me).trigger('subscribe', message);\n });\n cometd.addListener('/meta/unsubscribe', function (message) {\n $(me).trigger('unsubscribe', message);\n });\n cometd.addListener('/meta/publish', function (message) {\n $(me).trigger('publish', message);\n });\n cometd.addListener('/meta/unsuccessful', function (message) {\n $(me).trigger('error', message);\n });\n\n cometd.handshake(defaultCometOptions.handshake);\n\n this.cometd = cometd;\n};\n\n\nChannelManager.prototype = $.extend(ChannelManager.prototype, {\n\n /**\n * Creates and returns a channel, that is, an instance of a [Channel Service](../channel-service/).\n *\n * **Example**\n *\n * var cm = new F.manager.ChannelManager();\n * var channel = cm.getChannel();\n *\n * channel.subscribe('topic', callback);\n * channel.publish('topic', { myData: 100 });\n *\n * **Parameters**\n * @param {Object|String} options (Optional) If string, assumed to be the base channel url. If object, assumed to be configuration options for the constructor.\n * @return {Channel} Channel instance\n */\n getChannel: function (options) {\n //If you just want to pass in a string\n if (options && !$.isPlainObject(options)) {\n options = {\n base: options\n };\n }\n var defaults = {\n transport: this.cometd\n };\n var channel = new Channel($.extend(true, {}, this.options.channel, defaults, options));\n\n\n //Wrap subs and unsubs so we can use it to re-attach handlers after being disconnected\n var subs = channel.subscribe;\n channel.subscribe = function () {\n var subid = subs.apply(channel, arguments);\n this.currentSubscriptions = this.currentSubscriptions.concat(subid);\n return subid;\n }.bind(this);\n\n\n var unsubs = channel.unsubscribe;\n channel.unsubscribe = function () {\n var removed = unsubs.apply(channel, arguments);\n for (var i = 0; i < this.currentSubscriptions.length; i++) {\n if (this.currentSubscriptions[i].id === removed.id) {\n this.currentSubscriptions.splice(i, 1);\n }\n }\n return removed;\n }.bind(this);\n\n return channel;\n },\n\n /**\n * Start listening for events on this instance. Signature is same as for jQuery Events: http://api.jquery.com/on/.\n *\n * Supported events are: `connect`, `disconnect`, `subscribe`, `unsubscribe`, `publish`, `error`.\n *\n * **Parameters**\n *\n * @param {string} event The event type. See more detail at jQuery Events: http://api.jquery.com/on/.\n */\n on: function (event) {\n $(this).on.apply($(this), arguments);\n },\n\n /**\n * Stop listening for events on this instance. Signature is same as for jQuery Events: http://api.jquery.com/off/.\n *\n * **Parameters**\n *\n * @param {string} event The event type. See more detail at jQuery Events: http://api.jquery.com/off/.\n */\n off: function (event) {\n $(this).off.apply($(this), arguments);\n },\n\n /**\n * Trigger events and execute handlers. Signature is same as for jQuery Events: http://api.jquery.com/trigger/.\n *\n * **Parameters**\n *\n * @param {string} event The event type. See more detail at jQuery Events: http://api.jquery.com/trigger/.\n */\n trigger: function (event) {\n $(this).trigger.apply($(this), arguments);\n }\n});\n\nmodule.exports = ChannelManager;\n","'use strict';\n\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).\n *\n * \n * ### Channel Background\n *\n * Channel notifications are only available for [team projects](../../../glossary/#team). There are two main use cases for the push channel: event notifications and chat messages.\n *\n * #### Event Notifications\n *\n * Within a [multiplayer simulation or world](../../../glossary/#world), it is often useful for your project's [model](../../../writing_your_model/) to alert the [user interface (browser)](../../../creating_your_interface/) that something new has happened.\n *\n * Usually, this \"something new\" is an event within the project, group, or world, such as:\n *\n * * An end user comes online (logs in) or goes offline. (This is especially interesting in a multiplayer world; only available if you have [enabled authorization](../../../updating_your_settings/#general-settings) for the channel.)\n * * An end user is assigned to a world.\n * * An end user updates a variable / makes a decision.\n * * An end user creates or updates data stored in the [Data API](../data-api-service/).\n * * An operation (method) is called. (This is especially interesting if the model is advanced, for instance, the Vensim `step` operation is called.)\n *\n * When these events occur, you often want to have the user interface for one or more end users automatically update with new information.\n *\n * #### Chat Messages\n *\n * Another reason to use the push channel is to allow players (end users) to send chat messages to other players, and to have those messages appear immediately.\n *\n * #### Getting Started\n *\n * For both the event notification and chat message use cases:\n *\n * * First, enable channel notifications for your project.\n * * Channel notifications are only available for [team projects](../../../glossary/#team). To enable notifications for your project, [update your project settings](../../../updating_your_settings/#general-settings) to turn on the **Push Channel** setting, and optionally require authorization for the channel.\n * * Then, instantiate an Epicenter Channel Manager.\n * * Next, get the channel with the scope you want (user, world, group, data).\n * * Finally, use the channel's `subscribe()` and `publish()` methods to subscribe to topics or publish data to topics.\n *\n * Here's an example of those last three steps (instantiate, get channel, subscribe):\n *\n * var cm = new F.manager.ChannelManager();\n * var gc = cm.getGroupChannel();\n * gc.subscribe('', function(data) { console.log(data); });\n * gc.publish('', { message: 'a new message to the group' });\n *\n * For a more detailed example, see a [complete publish and subscribe example](../../../rest_apis/multiplayer/channel/#epijs-example).\n *\n * For details on what data is published automatically to which channels, see [Automatic Publishing of Events](../../../rest_apis/multiplayer/channel/#publish-message-auto).\n *\n * #### Creating an Epicenter Channel Manager\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 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 * The parameters for instantiating an Epicenter Channel Manager include:\n *\n * * `options` Object with details about the Epicenter project for this Epicenter Channel Manager instance.\n * * `options.account` The Epicenter account id (**Team ID** for team projects, **User ID** for personal projects).\n * * `options.project` Epicenter project id.\n * * `options.userName` Epicenter userName used for authentication.\n * * `options.userId` Epicenter user id used for authentication. Optional; `options.userName` is preferred.\n * * `options.token` Epicenter token used for authentication. (You can retrieve this using `authManager.getToken()` from the [Authorization Manager](../auth-manager/).)\n * * `options.allowAllChannels` If not included or if set to `false`, all channel paths are validated; if your project requires [Push Channel Authorization](../../../updating_your_settings/), you should use this option. If you want to allow other channel paths, set to `true`; this is not common.\n */\n\nvar ChannelManager = require('./channel-manager');\nvar ConfigService = require('../service/configuration-service');\nvar classFrom = require('../util/inherit');\nvar SessionManager = require('../store/session-manager');\n\nvar validTypes = {\n project: true,\n group: true,\n world: true,\n user: true,\n data: true,\n general: true,\n chat: true\n};\nvar getFromSessionOrError = function (value, sessionKeyName, settings) {\n if (!value) {\n if (settings && settings[sessionKeyName]) {\n value = settings[sessionKeyName];\n } else {\n throw new Error(sessionKeyName + ' not found. Please log-in again, or specify ' + sessionKeyName + ' explicitly');\n }\n }\n return value;\n};\n\nvar isPresenceData = function (payload) {\n return payload.data && payload.data.type === 'user' && payload.data.user;\n};\n\nvar __super = ChannelManager.prototype;\nvar EpicenterChannelManager = classFrom(ChannelManager, {\n constructor: function (options) {\n this.sessionManager = new SessionManager(options);\n var defaultCometOptions = this.sessionManager.getMergedOptions(options);\n\n var urlConfig = new ConfigService(defaultCometOptions).get('server');\n if (!defaultCometOptions.url) {\n defaultCometOptions.url = urlConfig.getAPIPath('channel');\n }\n\n if (defaultCometOptions.handshake === undefined) {\n var userName = defaultCometOptions.userName;\n var userId = defaultCometOptions.userId;\n var token = defaultCometOptions.token;\n if ((userName || userId) && token) {\n var userProp = userName ? 'userName' : 'userId';\n var ext = {\n authorization: 'Bearer ' + token\n };\n ext[userProp] = userName ? userName : userId;\n\n defaultCometOptions.handshake = {\n ext: ext\n };\n }\n }\n\n this.options = defaultCometOptions;\n return __super.constructor.call(this, defaultCometOptions);\n },\n\n /**\n * Creates and returns a channel, that is, an instance of a [Channel Service](../channel-service/).\n *\n * This method enforces Epicenter-specific channel naming: all channels requested must be in the form `/{type}/{account id}/{project id}/{...}`, where `type` is one of `run`, `data`, `user`, `world`, or `chat`.\n *\n * **Example**\n *\n * var cm = new F.manager.EpicenterChannelManager();\n * var channel = cm.getChannel('/group/acme/supply-chain-game/');\n *\n * channel.subscribe('topic', callback);\n * channel.publish('topic', { myData: 100 });\n *\n * **Parameters**\n * @param {Object|String} options (Optional) If string, assumed to be the base channel url. If object, assumed to be configuration options for the constructor.\n * @return {Channel} Channel instance\n */\n getChannel: function (options) {\n if (options && typeof options !== 'object') {\n options = {\n base: options\n };\n }\n var channelOpts = $.extend({}, this.options, options);\n var base = channelOpts.base;\n if (!base) {\n throw new Error('No base topic was provided');\n }\n\n if (!channelOpts.allowAllChannels) {\n var baseParts = base.split('/');\n var channelType = baseParts[1];\n if (baseParts.length < 4) { //eslint-disable-line\n throw new Error('Invalid channel base name, it must be in the form /{type}/{account id}/{project id}/{...}');\n }\n if (!validTypes[channelType]) {\n throw new Error('Invalid channel type');\n }\n }\n return __super.getChannel.apply(this, arguments);\n },\n\n /**\n * Create and return a publish/subscribe channel (from the underlying [Channel Manager](../channel-manager/)) for the given [group](../../../glossary/#groups). The group must exist in the account (team) and project provided.\n *\n * There are no notifications from Epicenter on this channel; all messages are user-originated.\n *\n * **Example**\n *\n * var cm = new F.manager.ChannelManager();\n * var gc = cm.getGroupChannel();\n * gc.subscribe('broadcasts', callback);\n *\n * **Return Value**\n *\n * * *Channel* Returns the channel (an instance of the [Channel Service](../channel-service/)).\n *\n * **Parameters**\n *\n * @param {String} groupName (Optional) Group to broadcast to. If not provided, picks up group from current session if end user is logged in.\n * @return {Channel} Channel instance\n */\n getGroupChannel: function (groupName) {\n var session = this.sessionManager.getMergedOptions(this.options);\n groupName = getFromSessionOrError(groupName, 'groupName', session);\n var account = getFromSessionOrError('', 'account', session);\n var project = getFromSessionOrError('', 'project', session);\n\n var baseTopic = ['/group', account, project, groupName].join('/');\n var channel = __super.getChannel.call(this, { base: baseTopic });\n var oldsubs = channel.subscribe;\n channel.subscribe = function (topic, callback, context, options) {\n var callbackWithoutPresenceData = function (payload) {\n if (!isPresenceData(payload)) {\n callback.call(context, payload);\n }\n };\n return oldsubs.call(channel, topic, callbackWithoutPresenceData, context, options);\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 [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 * @return {Channel} Channel instance\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 var session = this.sessionManager.getMergedOptions(this.options);\n\n groupName = getFromSessionOrError(groupName, 'groupName', session);\n var account = getFromSessionOrError('', 'account', session);\n var project = getFromSessionOrError('', 'project', session);\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 * @return {Channel} Channel instance\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 session = this.sessionManager.getMergedOptions(this.options);\n\n var userid = ($.isPlainObject(user) && user.id) ? user.id : user;\n userid = getFromSessionOrError(userid, 'userId', session);\n groupName = getFromSessionOrError(groupName, 'groupName', session);\n\n var account = getFromSessionOrError('', 'account', session);\n var project = getFromSessionOrError('', 'project', session);\n\n var baseTopic = ['/user', account, project, groupName, worldid, userid].join('/');\n return __super.getChannel.call(this, { base: baseTopic });\n },\n\n /**\n * Create and return a publish/subscribe channel (from the underlying [Channel Manager](../channel-manager/)) that automatically tracks the presence of an [end user](../../../glossary/#users), that is, whether the end user is currently online in this group. 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 group are also online.\n *\n * Note that the presence channel is tracking all end users in a group. In particular, if the project additionally splits each group into [worlds](../world-manager/), this channel continues to show notifications for all end users in the group (not restricted by worlds).\n *\n * **Example**\n *\n * var cm = new F.manager.ChannelManager();\n * var pc = cm.getPresenceChannel();\n * pc.subscribe('', function (data) {\n * // 'data' is the entire message object to the channel;\n * // parse for information of interest\n * if (data.data.subType === 'disconnect') {\n * console.log('user ', data.data.user.userName, 'disconnected at ', data.data.date);\n * }\n * if (data.data.subType === 'connect') {\n * console.log('user ', data.data.user.userName, 'connected at ', data.data.date);\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} groupName (Optional) Group the end user is in. If not provided, picks up group from current session if end user is logged in.\n * @return {Channel} Channel instance\n */\n getPresenceChannel: function (groupName) {\n var session = this.sessionManager.getMergedOptions(this.options);\n groupName = getFromSessionOrError(groupName, 'groupName', session);\n var account = getFromSessionOrError('', 'account', session);\n var project = getFromSessionOrError('', 'project', session);\n\n var baseTopic = ['/group', account, project, groupName].join('/');\n var channel = __super.getChannel.call(this, { base: baseTopic });\n var oldsubs = channel.subscribe;\n channel.subscribe = function (topic, callback, context, options) {\n var callbackWithOnlyPresenceData = function (payload) {\n if (isPresenceData(payload)) {\n callback.call(context, payload);\n }\n };\n return oldsubs.call(channel, topic, callbackWithOnlyPresenceData, context, options);\n };\n return channel;\n },\n\n /**\n * Create and return a publish/subscribe channel (from the underlying [Channel Manager](../channel-manager/)) for the given collection. (The collection name is specified in the `root` argument when the [Data Service](../data-api-service/) is instantiated.) Must be one of the collections in this account (team) and project.\n *\n * There are automatic notifications from Epicenter on this channel when data is created, updated, or deleted in this collection. See more on [automatic messages to the data channel](../../../rest_apis/multiplayer/channel/#data-messages).\n *\n * **Example**\n *\n * var cm = new F.manager.ChannelManager();\n * var dc = cm.getDataChannel('survey-responses');\n * dc.subscribe('', function(data, meta) {\n * console.log(data);\n *\n * // meta.date is time of change,\n * // meta.subType is the kind of change: new, update, or delete\n * // meta.path is the full path to the changed data\n * console.log(meta);\n * });\n *\n * **Return Value**\n *\n * * *Channel* Returns the channel (an instance of the [Channel Service](../channel-service/)).\n *\n * **Parameters**\n *\n * @param {String} collection Name of collection whose automatic notifications you want to receive.\n * @return {Channel} Channel instance\n */\n getDataChannel: function (collection) {\n if (!collection) {\n throw new Error('Please specify a collection to listen on.');\n }\n\n var session = this.sessionManager.getMergedOptions(this.options);\n var account = getFromSessionOrError('', 'account', session);\n var project = getFromSessionOrError('', 'project', session);\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 dataPath: payload.data.data.path,\n };\n var actualData = payload.data.data;\n if (actualData.data !== undefined) { //Delete notifications are one data-level behind of course\n actualData = actualData.data;\n }\n\n callback.call(context, actualData, meta);\n };\n return oldsubs.call(channel, topic, callbackWithCleanData, context, options);\n };\n\n return channel;\n }\n});\n\nmodule.exports = EpicenterChannelManager;\n","'use strict';\n\nmodule.exports = {\n EPI_SESSION_KEY: 'epicenterjs.session',\n STRATEGY_SESSION_KEY: 'epicenter-scenario'\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)](../strategies/) 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/) and the RESFTful [Run API](../../../rest_apis/aggregate_run_api). 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.\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 optionally pass a `files` object with the names of the files, for example: `\"files\": {\"data\": \"myExtraData.xls\"}`. (See more on [Using External Data in Vensim](../../../model_code/vensim/vensim_example_xls/).)\n*\n* * `strategy`: (optional) Run creation strategy for when to create a new run and when to reuse an end user's existing run. This is *optional*; by default, the Run Manager selects `reuse-per-session`, or `reuse-last-initialized` if you also pass in an initial operation. See [below](#using-the-run-manager-to-access-and-register-strategies) for more information on strategies.\n*\n* * `strategyOptions`: (optional) Additional options passed directly to the [run creation strategy](../strategies/).\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. This can also be a function which returns a string, if you'd like to control this at runtime.\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: 'reuse-never',\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* ### Using the Run Manager to access and register strategies\n*\n* The `strategy` for a Run Manager describes when to create a new run and when to reuse an end user's existing run. The Run Manager is responsible for passing a strategy everything it might need to determine the 'correct' run, that is, how to find the best existing run and how to decide when to create a new run.\n*\n* There are several common strategies provided as part of Epicenter.js, which you can list by accessing `F.manager.RunManager.strategies`. You can also create your own strategies, and register them to use with Run Managers. See [Run Manager Strategies](../strategies/) for details.\n* \n*/\n\n'use strict';\nvar strategies = require('./run-strategies');\nvar specialOperations = require('./special-operations');\n\nvar RunService = require('../service/run-api-service');\nvar SessionManager = require('../store/session-manager');\n\nvar util = require('../util/object-util');\nvar keyNames = require('./key-names');\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\nfunction sessionKeyFromOptions(options, runService) {\n var config = runService.getCurrentConfig();\n var sessionKey = $.isFunction(options.sessionKey) ? options.sessionKey(config) : options.sessionKey;\n return sessionKey;\n}\n\nfunction setRunInSession(sessionKey, run, sessionManager) {\n if (sessionKey) {\n delete run.variables;\n sessionManager.getStore().set(sessionKey, JSON.stringify(run));\n }\n}\n\nvar defaults = {\n sessionKey: function (config) { \n var baseKey = keyNames.STRATEGY_SESSION_KEY;\n var key = ['account', 'project', 'model'].reduce(function (accum, key) {\n return config[key] ? accum + '-' + config[key] : accum; \n }, baseKey);\n return key;\n }\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 if (!util.isEmpty(this.options.run)) {\n this.run = new RunService(this.options.run);\n } else {\n throw new Error('No run options passed to RunManager');\n }\n patchRunService(this.run, this);\n\n this.strategy = strategies.getBestStrategy(this.options);\n this.sessionManager = new SessionManager(this.options);\n}\n\nRunManager.prototype = {\n /**\n * Returns the run object for the 'correct' run. The correct run is defined by the strategy. \n *\n * For example, if the strategy is `reuse-never`, the call\n * to `getRun()` always returns a newly created run; if the strategy is `reuse-per-session`,\n * `getRun()` returns the run currently referenced in the browser cookie, and if there is none, creates a new run. \n * See [Run Manager Strategies](../strategies/) 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 * rm.getRun(['sample_int']).then(function (run) {\n * // an object whose fields are the name : value pairs of the variables passed to getRun()\n * console.log(run.variables);\n * // the value of sample_int\n * console.log(run.variables.sample_int); \n * });\n *\n * @param {Array} variables (Optional) The run object is populated with the provided model variables, if provided. Note: `getRun()` does not throw an error if you try to get a variable which doesn't exist. Instead, the variables list is empty, and any errors are logged to the console.\n * @param {Object} options (Optional) Configuration options; passed on to [RunService#create](../run-api-service/#create) if the strategy does create a new run.\n * @return {$promise} Promise to complete the call.\n */\n getRun: function (variables, options) {\n var me = this;\n var sessionStore = this.sessionManager.getStore();\n\n var sessionContents = sessionStore.get(sessionKeyFromOptions(this.options, me.run));\n var runSession = JSON.parse(sessionContents || '{}');\n \n if (runSession.runId) {\n //EpiJS < 2.2 used runId as key, so maintain comptaibility. Remove at some future date (Summer `17?)\n runSession.id = runSession.runId;\n }\n\n var authSession = this.sessionManager.getSession();\n if (this.strategy.requiresAuth && util.isEmpty(authSession)) {\n console.error('No user-session available', this.options.strategy, 'requires authentication.');\n return $.Deferred().reject('No user-session available').promise();\n }\n return this.strategy\n .getRun(this.run, authSession, runSession, options).then(function (run) {\n if (run && run.id) {\n me.run.updateConfig({ filter: run.id });\n var sessionKey = sessionKeyFromOptions(me.options, me.run);\n setRunInSession(sessionKey, run, me.sessionManager);\n\n if (variables && variables.length) {\n return me.run.variables().query(variables).then(function (results) {\n run.variables = results;\n return run;\n }).catch(function (err) {\n run.variables = {};\n console.error(err);\n return run;\n });\n }\n }\n return run;\n });\n },\n\n /**\n * Returns the run object for a 'reset' run. The definition of a reset is defined by the strategy, but typically means forcing the creation of a new run. For example, `reset()` for the default strategies `reuse-per-session` and `reuse-last-initialized` both create new runs.\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} options (Optional) Configuration options; passed on to [RunService#create](../run-api-service/#create).\n * @return {Promise}\n */\n reset: function (options) {\n var me = this;\n var authSession = this.sessionManager.getSession();\n if (this.strategy.requiresAuth && util.isEmpty(authSession)) {\n console.error('No user-session available', this.options.strategy, 'requires authentication.');\n return $.Deferred().reject('No user-session available').promise();\n }\n return this.strategy.reset(this.run, authSession, options).then(function (run) {\n if (run && run.id) {\n me.run.updateConfig({ filter: run.id });\n var sessionKey = sessionKeyFromOptions(me.options, me.run);\n setRunInSession(sessionKey, run.id, me.sessionManager);\n }\n return run;\n });\n }\n};\n\nRunManager.strategies = strategies;\nmodule.exports = RunManager;\n","'use strict';\n\nvar Base = require('./none-strategy');\nvar classFrom = require('../../util/inherit');\n\n/**\n* ## Conditional Creation Strategy\n*\n* This strategy will try to get the run stored in the cookie and\n* evaluate if it needs to create a new run by calling the `condition` function.\n*/\n\nvar Strategy = classFrom(Base, {\n constructor: function Strategy(condition) {\n if (condition == null) { //eslint-disable-line\n throw new Error('Conditional strategy needs a condition to create a run');\n }\n this.condition = typeof condition !== 'function' ? function () { return condition; } : condition;\n },\n\n /**\n * Gets a new 'correct' run, or updates the existing one (the definition of 'correct' depends on strategy implementation).\n * @param {RunService} runService A Run Service instance for the current run, as determined by the Run Manager.\n * @param {Object} userSession Information about the current user session. See [AuthManager#getCurrentUserSessionInfo](../auth-manager/#getcurrentusersessioninfo) for format.\n * @param {Object} options (Optional) See [RunService#create](../run-api-service/#create) for supported options.\n * @return {Promise} \n */\n reset: function (runService, userSession, options) {\n var group = userSession && userSession.groupName;\n var opt = $.extend({\n scope: { group: group }\n }, runService.getCurrentConfig());\n\n return runService\n .create(opt, options)\n .then(function (run) {\n run.freshlyCreated = true;\n return run;\n });\n },\n\n /**\n * Gets the 'correct' run (the definition of 'correct' depends on strategy implementation).\n * @param {RunService} runService A Run Service instance for the current run, as determined by the Run Manager.\n * @param {Object} userSession Information about the current user session. See [AuthManager#getCurrentUserSessionInfo](../auth-manager/#getcurrentusersessioninfo) for format.\n * @param {Object} runSession The Run Manager stores the 'last accessed' run in a cookie and passes it back here.\n * @param {Object} options (Optional) See [RunService#create](../run-api-service/#create) for supported options.\n * @return {Promise} \n */\n getRun: function (runService, userSession, runSession, options) {\n var me = this;\n if (runSession && runSession.id) {\n return this.loadAndCheck(runService, userSession, runSession, options).catch(function () {\n return me.reset(runService, userSession, options); //if it got the wrong cookie for e.g.\n });\n } else {\n return this.reset(runService, userSession, options);\n }\n },\n\n loadAndCheck: function (runService, userSession, runSession, options) {\n var shouldCreate = false;\n var me = this;\n\n return runService\n .load(runSession.id, null, {\n success: function (run, msg, headers) {\n shouldCreate = me.condition(run, headers, userSession, runSession);\n }\n })\n .then(function (run) {\n if (shouldCreate) {\n return me.reset(runService, userSession, options);\n }\n return run;\n });\n }\n});\n\nmodule.exports = Strategy;\n","/**\n * The `new-if-initialized` strategy creates a new run if the current one is in memory or has its `initialized` field set to `true`. The `initialized` field in the run record is automatically set to `true` at run creation, but can be changed.\n * \n * This strategy is useful if your project is structured such that immediately after a run is created, the model is executed completely (for example, a Vensim model is stepped to the end). It is similar to the `new-if-missing` strategy, except that it checks a field of the run record.\n * \n * Specifically, the strategy is:\n *\n * * Check the `sessionKey` cookie. \n * * This cookie is set by the [Run Manager](../run-manager/) and configurable through its options.\n * * If the cookie exists, check whether the run is in memory or only persisted in the database. Additionally, check whether the run's `initialized` field is `true`. \n * * If the run is in memory, create a new run.\n * * If the run's `initialized` field is `true`, create a new run.\n * * Otherwise, use the existing run.\n * * If the cookie does not exist, create a new run for this end user.\n * \n * @deprecated Consider using `reuse-last-initialized` instead\n */\n\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 (options) {\n __super.constructor.call(this, this.createIf, options);\n console.warn('This strategy is deprecated; all runs now default to being initialized by default making this redundant. Consider using `reuse-last-initialized` instead.');\n },\n\n createIf: function (run, headers) {\n return headers.getResponseHeader('pragma') === 'persistent' || run.initialized;\n }\n});\n\nmodule.exports = Strategy;\n","/**\n * The `new-if-persisted` strategy creates a new run when the current one becomes persisted (end user is idle for a set period), but otherwise uses the current one. \n * \n * Using this strategy means that when end users navigate between pages in your project, or refresh their browsers, they will still be working with the same run. \n * \n * However, if they are idle for longer than your project's **Model Session Timeout** (configured in your project's [Settings](../../../updating_your_settings/)), then their run is persisted; the next time they interact with the project, they will get a new run. (See more background on [Run Persistence](../../../run_persistence/).)\n * \n * This strategy is useful for multi-page projects where end users play through a simulation in one sitting, stepping through the model sequentially (for example, a Vensim model that uses the `step` operation) or calling specific functions until the model is \"complete.\" However, you will need to guarantee that your end users will remain engaged with the project from beginning to end — or at least, that if they are idle for longer than the **Model Session Timeout**, it is okay for them to start the project from scratch (with an uninitialized model). \n * \n * Specifically, the strategy is:\n *\n * * Check the `sessionKey` cookie.\n * * This cookie is set by the [Run Manager](../run-manager/) and configurable through its options.\n * * If the cookie exists, check whether the run is in memory or only persisted in the database. \n * * If the run is in memory, use the run.\n * * If the run is only persisted (and not still in memory), create a new run for this end user.\n * * If the cookie does not exist, create a new run for this end user.\n *\n * @deprecated The run-service now sets a header to automatically bring back runs into memory\n */\n\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 (options) {\n __super.constructor.call(this, this.createIf, options);\n console.warn('This strategy is deprecated; the run-service now sets a header to automatically bring back runs into memory');\n },\n\n createIf: function (run, headers) {\n return headers.getResponseHeader('pragma') === 'persistent';\n }\n});\n\nmodule.exports = Strategy;\n","/**\n * ### Working with Run Strategies\n *\n * You can access a list of available strategies using `F.manager.RunManager.strategies.list`. You can also ask for a particular strategy by name.\n *\n * If you decide to [create your own run strategy](#create-your-own), you can register your strategy. Registering your strategy means that:\n *\n * * You can pass the strategy by name to a Run Manager (as opposed to passing the strategy function): `new F.manager.RunManager({ strategy: 'mynewname'})`.\n * * You can pass configuration options to your strategy.\n * * You can specify whether or not your strategy requires authorization (a valid user session) to work.\n */\n\n\nvar list = {\n 'conditional-creation': require('./conditional-creation-strategy'),\n 'new-if-initialized': require('./deprecated/new-if-initialized-strategy'), //deprecated\n 'new-if-persisted': require('./deprecated/new-if-persisted-strategy'), //deprecated\n\n none: require('./none-strategy'),\n\n multiplayer: require('./multiplayer-strategy'),\n 'reuse-never': require('./reuse-never'),\n 'reuse-per-session': require('./reuse-per-session'),\n 'reuse-across-sessions': require('./reuse-across-sessions'),\n 'reuse-last-initialized': require('./reuse-last-initialized'),\n};\n\n//Add back older aliases\nlist['always-new'] = list['reuse-never'];\nlist['new-if-missing'] = list['reuse-per-session'];\nlist['persistent-single-player'] = list['reuse-across-sessions'];\n\n\nmodule.exports = {\n /**\n * List of available strategies. Within this object, each key is the strategy name and the associated value is the strategy constructor.\n * @type {Object} \n */\n list: list,\n\n /**\n * Gets strategy by name.\n *\n * **Example**\n *\n * var reuseStrat = F.manager.RunManager.strategies.byName('reuse-across-sessions');\n * // shows strategy function\n * console.log('reuseStrat = ', reuseStrat);\n * // create a new run manager using this strategy\n * var rm = new F.manager.RunManager({strategy: reuseStrat, run: { model: 'model.vmf'} });\n *\n * **Parameters**\n * @param {String} strategyName Name of strategy to get.\n * @return {Function} Strategy function.\n */\n byName: function (strategyName) {\n return list[strategyName];\n },\n\n getBestStrategy: function (options) {\n var strategy = options.strategy;\n if (!strategy) {\n if (options.strategyOptions && options.strategyOptions.initOperation) {\n strategy = 'reuse-last-initialized';\n } else {\n strategy = 'reuse-per-session';\n }\n }\n\n if (strategy.getRun) {\n return strategy;\n }\n var StrategyCtor = typeof strategy === 'function' ? strategy : this.byName(strategy);\n if (!StrategyCtor) {\n throw new Error('Specified run creation strategy was invalid:', strategy);\n }\n\n var strategyInstance = new StrategyCtor(options);\n if (!strategyInstance.getRun || !strategyInstance.reset) {\n throw new Error('All strategies should implement a `getRun` and `reset` interface', options.strategy);\n }\n strategyInstance.requiresAuth = StrategyCtor.requiresAuth;\n\n return strategyInstance;\n },\n\n /**\n * Adds a new strategy.\n *\n * **Example**\n *\n * // this \"favorite run\" strategy always returns the same run, no matter what\n * // (not a useful strategy, except as an example)\n * F.manager.RunManager.strategies.register(\n * 'favRun', \n * function() { \n * return { getRun: function() { return '0000015a4cd1700209cd0a7d207f44bac289'; },\n * reset: function() { return '0000015a4cd1700209cd0a7d207f44bac289'; } \n * } \n * }, \n * { requiresAuth: true }\n * );\n * \n * var rm = new F.manager.RunManager({strategy: 'favRun', run: { model: 'model.vmf'} });\n *\n * **Parameters**\n * @param {String} name Name for strategy. This string can then be passed to a Run Manager as `new F.manager.RunManager({ strategy: 'mynewname'})`.\n * @param {Function} strategy The strategy constructor. Will be called with `new` on Run Manager initialization.\n * @param {Object} options Options for strategy.\n * @param {Boolean} options.requiresAuth Specify if the strategy requires a valid user session to work.\n */\n register: function (name, strategy, options) {\n strategy.options = options;\n list[name] = strategy;\n }\n};","/**\n * The `multiplayer` strategy is for use with [multiplayer worlds](../../../glossary/#world). It checks the current world for this end user, and always returns the current run for that world. This is equivalent to calling `getCurrentWorldForUser()` and then `getCurrentRunId()` from the [World API Adapater](../world-api-adapter/). If you use the [World Manager](../world-manager/), you are automatically using this strategy.\n * \n * Using this strategy means that end users in projects with multiplayer worlds always see the most current world and run. This ensures that they are in sync with the other end users sharing their world and run. In turn, this allows for competitive or collaborative multiplayer projects.\n */\n'use strict';\n\nvar classFrom = require('../../util/inherit');\n\nvar IdentityStrategy = require('./none-strategy');\nvar WorldApiAdapter = require('../../service/world-api-adapter');\n\nvar defaults = {};\n\nvar Strategy = classFrom(IdentityStrategy, {\n constructor: function (options) {\n this.options = $.extend(true, {}, defaults, options);\n this.worldApi = new WorldApiAdapter(this.options.run);\n },\n\n reset: function (runService, session, options) {\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, options).then(function (runid) {\n return {\n id: runid\n };\n });\n }.bind(this));\n },\n\n getRun: function (runService, session) {\n var curUserId = session.userId;\n var curGroupName = session.groupName;\n var worldApi = this.worldApi;\n var model = this.options.model;\n var me = 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: me.options, session: session });\n }\n return worldApi.getCurrentRunId({ model: model, filter: world.id })\n .then(function (id) {\n return runService.load(id);\n })\n .then(dtd.resolve)\n .fail(dtd.reject);\n };\n\n var serverError = function (error) {\n // is this possible?\n return dtd.reject(error, session, me.options);\n };\n\n this.worldApi\n .getCurrentWorldForUser(curUserId, curGroupName)\n .then(loadRunFromWorld)\n .fail(serverError);\n\n return dtd.promise();\n },\n\n});\n\nmodule.exports = Strategy;\n","/**\n * The `none` strategy never returns a run or tries to create a new run. It simply returns the contents of the current [Run Service instance](../run-api-service/).\n * \n * This strategy is useful if you want to manually decide how to create your own runs and don't want any automatic assistance.\n */\n\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 (options) {\n\n },\n\n reset: function () {\n // return a newly created run\n return $.Deferred().resolve().promise();\n },\n\n getRun: function (runService) {\n // return a usable run\n return $.Deferred().resolve(runService).promise();\n }\n});\n","/**\n * The `reuse-across-sessions` strategy returns the latest (most recent) run for this user, whether it is in memory or not. If there are no runs for this user, it creates a new one.\n *\n * This strategy is useful if end users are using your project for an extended period of time, possibly over several sessions. This is most common in cases where a user of your project executes the model step by step (as opposed to a project where the model is executed completely, for example, a Vensim model that is immediately stepped to the end).\n *\n * Specifically, the strategy is:\n * \n * * Check if there are any runs for this end user.\n * * If there are no runs (either in memory or in the database), create a new one.\n * * If there are runs, take the latest (most recent) one.\n *\n * @name persistent-single-player\n */\n\n'use strict';\n\nvar classFrom = require('../../util/inherit');\nvar IdentityStrategy = require('./none-strategy');\nvar injectFiltersFromSession = require('../strategy-utils').injectFiltersFromSession;\nvar injectScopeFromSession = require('../strategy-utils').injectScopeFromSession;\n\nvar defaults = {\n /**\n * (Optional) Additional criteria to use while selecting the last run\n * @type {Object}\n */\n filter: {},\n};\n\nvar Strategy = classFrom(IdentityStrategy, {\n constructor: function Strategy(options) {\n var strategyOptions = options ? options.strategyOptions : {};\n this.options = $.extend(true, {}, defaults, strategyOptions);\n },\n\n reset: function (runService, userSession, options) {\n var opt = injectScopeFromSession(runService.getCurrentConfig(), userSession);\n return runService\n .create(opt, options)\n .then(function (run) {\n run.freshlyCreated = true;\n return run;\n });\n },\n\n getRun: function (runService, userSession, runSession, options) {\n var filter = injectFiltersFromSession(this.options.filter, userSession);\n var me = this;\n return runService.query(filter, { \n startrecord: 0,\n endrecord: 0,\n sort: 'created', \n direction: 'desc'\n }).then(function (runs) {\n if (!runs.length) {\n return me.reset(runService, userSession, options);\n }\n return runs[0];\n });\n }\n});\n\nmodule.exports = Strategy;\n","/**\n * The `reuse-last-initialized` strategy looks for the most recent run that matches particular criteria; if it cannot find one, it creates a new run and immediately executes a set of \"initialization\" operations. \n *\n * This strategy is useful if you have a time-based model and always want the run you're operating on to start at a particular step. For example:\n *\n * var rm = new F.manager.RunManager({\n * strategy: 'reuse-last-initialized',\n * strategyOptions: {\n * initOperation: [{ step: 10 }]\n * }\n * });\n * \n * This strategy is also useful if you have a custom initialization function in your model, and want to make sure it's always executed for new runs.\n *\n * Specifically, the strategy is:\n *\n * * Look for the most recent run that matches the (optional) `flag` criteria\n * * If there are no runs that match the `flag` criteria, create a new run. Immediately \"initialize\" this new run by:\n * * Calling the model operation(s) specified in the `initOperation` array.\n * * Optionally, setting a `flag` in the run.\n *\n */\n\n'use strict';\nvar classFrom = require('../../util/inherit');\nvar injectFiltersFromSession = require('../strategy-utils').injectFiltersFromSession;\nvar injectScopeFromSession = require('../strategy-utils').injectScopeFromSession;\n\nvar Base = {};\n\nvar defaults = {\n /**\n * Operations to execute in the model for initialization to be considered complete.\n * @type {Array} Can be in any of the formats [Run Service's `serial()`](../run-api-service/#serial) supports.\n */\n initOperation: [],\n\n /**\n * (Optional) Flag to set in run after initialization operations are run. You typically would not override this unless you needed to set additional properties as well.\n * @type {Object}\n */\n flag: null,\n};\nmodule.exports = classFrom(Base, {\n constructor: function (options) {\n var strategyOptions = options ? options.strategyOptions : {};\n this.options = $.extend(true, {}, defaults, strategyOptions);\n if (!this.options.initOperation || !this.options.initOperation.length) {\n throw new Error('Specifying an init function is required for this strategy');\n }\n if (!this.options.flag) {\n this.options.flag = {\n isInitComplete: true\n };\n }\n },\n\n reset: function (runService, userSession, options) {\n var opt = injectScopeFromSession(runService.getCurrentConfig(), userSession);\n var me = this;\n return runService.create(opt, options).then(function (createResponse) {\n return runService.serial([].concat(me.options.initOperation)).then(function () {\n return createResponse;\n });\n }).then(function (createResponse) {\n return runService.save(me.options.flag).then(function (patchResponse) {\n return $.extend(true, {}, createResponse, patchResponse);\n });\n });\n },\n\n getRun: function (runService, userSession, runSession, options) {\n var sessionFilter = injectFiltersFromSession(this.options.flag, userSession);\n var runopts = runService.getCurrentConfig();\n var filter = $.extend(true, { trashed: false }, sessionFilter, { model: runopts.model });\n var me = this;\n return runService.query(filter, { \n startrecord: 0,\n endrecord: 0,\n sort: 'created', \n direction: 'desc'\n }).then(function (runs) {\n if (!runs.length) {\n return me.reset(runService, userSession, options);\n }\n return runs[0];\n });\n }\n});","/**\n * The `reuse-never` strategy always creates a new run for this end user irrespective of current state. This is equivalent to calling `F.service.Run.create()` from the [Run Service](../run-api-service/) every time. \n * \n * This strategy means that every time your end users refresh their browsers, they get a new run. \n * \n * This strategy can be useful for basic, single-page projects. This strategy is also useful for prototyping or project development: it creates a new run each time you refresh the page, and you can easily check the outputs of the model. However, typically you will use one of the other strategies for a production project.\n *\n * @name always-new\n */\n\n'use strict';\n\nvar classFrom = require('../../util/inherit');\nvar ConditionalStrategy = require('./conditional-creation-strategy');\n\nvar __super = ConditionalStrategy.prototype;\n\nvar Strategy = classFrom(ConditionalStrategy, {\n constructor: function (options) {\n __super.constructor.call(this, 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","/**\n * The `reuse-per-session` strategy creates a new run when the current one is not in the browser cookie.\n * \n * Using this strategy means that when end users navigate between pages in your project, or refresh their browsers, they will still be working with the same run. However, if end users log out and return to the project at a later date, a new run is created.\n *\n * This strategy is useful if your project is structured such that immediately after a run is created, the model is executed completely (for example, a Vensim model that is stepped to the end as soon as it is created). In contrast, if end users play with your project for an extended period of time, executing the model step by step, the `reuse-across-sessions` strategy is probably a better choice (it allows end users to pick up where they left off, rather than starting from scratch each browser session).\n * \n * Specifically, the strategy is:\n *\n * * Check the `sessionKey` cookie.\n * * This cookie is set by the [Run Manager](../run-manager/) and configurable through its options. \n * * If the cookie exists, use the run id stored there. \n * * If the cookie does not exist, create a new run for this end user.\n *\n * @name new-if-missing\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 (options) {\n __super.constructor.call(this, 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","/**\n * ## Saved Runs Manager\n *\n * The Saved Runs Manager is a specific type of [Run Manager](../../run-manager/) which provides access to a list of runs (rather than just one run). It also provides utility functions for dealing with multiple runs (e.g. saving, deleting, listing).\n *\n * An instance of a Saved Runs Manager is included automatically in every instance of a [Scenario Manager](../), and is accessible from the Scenario Manager at `.savedRuns`. See [more information](../#properties) on using `.savedRuns` within the Scenario Manager.\n *\n */\n'use strict';\n\nvar RunService = require('../service/run-api-service');\nvar SessionManager = require('../store/session-manager');\n\nvar injectFiltersFromSession = require('./strategy-utils').injectFiltersFromSession;\n\nvar SavedRunsManager = function (config) {\n var defaults = {\n /**\n * If set, will only pull runs from current group. Defaults to `true`.\n * @type {Boolean}\n */\n scopeByGroup: true,\n\n /**\n * If set, will only pull runs from current user. Defaults to `true`.\n *\n * For multiplayer run comparison projects, set this to false so that all end users in a group can view the shared set of saved runs.\n * @type {Boolean}\n */\n scopeByUser: true,\n };\n\n this.sessionManager = new SessionManager();\n\n var options = $.extend(true, {}, defaults, config);\n if (options.run) {\n if (options.run instanceof RunService) {\n this.runService = options.run;\n } else {\n this.runService = new RunService(options.run);\n }\n this.options = options;\n } else {\n throw new Error('No run options passed to SavedRunsManager');\n }\n};\n\nSavedRunsManager.prototype = {\n /**\n * Marks a run as saved. \n *\n * Note that while any run can be saved, only runs which also match the configuration options `scopeByGroup` and `scopeByUser` are returned by the `getRuns()` method.\n *\n * **Example**\n *\n * var sm = new F.manager.ScenarioManager();\n * sm.savedRuns.save('0000015a4cd1700209cd0a7d207f44bac289');\n *\n * @param {String|RunService} run Run to save. Pass in either the run id, as a string, or the [Run Service](../../run-api-service/).\n * @param {Object} otherFields (Optional) Any other meta-data to save with the run.\n * @return {Promise}\n */\n save: function (run, otherFields) {\n var param = $.extend(true, {}, otherFields, { saved: true, trashed: false });\n return this.mark(run, param);\n },\n /**\n * Marks a run as removed; the inverse of marking as saved.\n *\n * **Example**\n *\n * var sm = new F.manager.ScenarioManager();\n * sm.savedRuns.remove('0000015a4cd1700209cd0a7d207f44bac289');\n *\n * @param {String|RunService} run Run to remove. Pass in either the run id, as a string, or the [Run Service](../../run-api-service/).\n * @param {Object} otherFields (Optional) any other meta-data to save with the run.\n * @return {Promise}\n */\n remove: function (run, otherFields) {\n var param = $.extend(true, {}, otherFields, { saved: false, trashed: true });\n return this.mark(run, param);\n },\n\n\n /**\n * Sets additional fields on a run. This is a convenience method for [RunService#save](../../run-api-service/#save).\n *\n * **Example**\n *\n * var sm = new F.manager.ScenarioManager();\n * sm.savedRuns.mark('0000015a4cd1700209cd0a7d207f44bac289', \n * { 'myRunName': 'sample policy decisions' });\n *\n * @param {String|RunService} run Run to operate on. Pass in either the run id, as a string, or the [Run Service](../../run-api-service/).\n * @param {Object} toMark Fields to set, as name : value pairs.\n * @return {Promise}\n */\n mark: function (run, toMark) {\n var rs;\n var existingOptions = this.runService.getCurrentConfig();\n if (run instanceof RunService) {\n rs = run;\n } else if (run && (typeof run === 'string')) {\n rs = new RunService($.extend(true, {}, existingOptions, { id: run, autoRestore: false }));\n } else if ($.isArray(run)) {\n var me = this;\n var proms = run.map(function (r) {\n return me.mark(r, toMark);\n });\n return $.when.apply(null, proms);\n } else {\n throw new Error('Invalid run object provided');\n }\n return rs.save(toMark);\n },\n\n /**\n * Returns a list of saved runs.\n *\n * **Example**\n *\n * var sm = new F.manager.ScenarioManager();\n * sm.savedRuns.getRuns().then(function (runs) {\n * for (var i=0; i\n * //\n * $('#fileupload').on('change', function (e) {\n * var file = e.target.files[0];\n * var data = new FormData();\n * data.append('file', file, file.name);\n * fa.create(file.name, data);\n * });\n */\n\n'use strict';\n\nvar ConfigService = require('./configuration-service');\nvar TransportFactory = require('../transport/http-transport-factory');\nvar SessionManager = require('../store/session-manager');\n\nmodule.exports = function (config) {\n var defaults = {\n /**\n * For projects that require authentication, pass in the user access token (defaults to empty string). If the user is already logged in to Epicenter, the user access token is already set in a cookie and automatically loaded from there. (See [more background on access tokens](../../../project_access/)).\n * @see [Authentication API Service](../auth-api-service/) for getting tokens.\n * @type {String}\n */\n token: undefined,\n\n /**\n * The account id. In the Epicenter UI, this is the **Team ID** (for team projects) or **User ID** (for personal projects). Defaults to undefined.\n * @type {String}\n */\n account: undefined,\n\n /**\n * The project id. Defaults to undefined.\n * @type {String}\n */\n project: undefined,\n\n /**\n * The folder type. One of `model` | `static` | `node`.\n * @type {String}\n */\n folderType: 'static',\n\n\n /**\n * Options to pass on to the underlying transport layer. All jquery.ajax options at http://api.jquery.com/jQuery.ajax/ are available. Defaults to empty object.\n * @type {Object}\n */\n transport: {}\n };\n\n this.sessionManager = new SessionManager();\n var serviceOptions = this.sessionManager.getMergedOptions(defaults, config);\n var urlConfig = new ConfigService(serviceOptions).get('server');\n if (serviceOptions.account) {\n urlConfig.accountPath = serviceOptions.account;\n }\n if (serviceOptions.project) {\n urlConfig.projectPath = serviceOptions.project;\n }\n\n var httpOptions = $.extend(true, {}, serviceOptions.transport, {\n url: urlConfig.getAPIPath('file')\n });\n\n if (serviceOptions.token) {\n httpOptions.headers = {\n Authorization: 'Bearer ' + serviceOptions.token\n };\n }\n var http = new TransportFactory(httpOptions);\n\n function uploadBody(fileName, contents) {\n var boundary = '---------------------------7da24f2e50046';\n\n return {\n body: '--' + boundary + '\\r\\n' +\n 'Content-Disposition: form-data; name=\"file\";' +\n 'filename=\"' + fileName + '\"\\r\\n' +\n 'Content-type: text/html\\r\\n\\r\\n' +\n contents + '\\r\\n' +\n '--' + boundary + '--',\n boundary: boundary\n };\n }\n\n function uploadFileOptions(filePath, contents, options) {\n filePath = filePath.split('/');\n var fileName = filePath.pop();\n filePath = filePath.join('/');\n var path = serviceOptions.folderType + '/' + filePath;\n\n var extraParams = {};\n if (contents instanceof FormData) {\n extraParams = {\n data: contents,\n processData: false,\n contentType: false,\n };\n } else {\n var upload = uploadBody(fileName, contents);\n extraParams = {\n data: upload.body,\n contentType: 'multipart/form-data; boundary=' + upload.boundary\n };\n }\n\n return $.extend(true, {}, serviceOptions, options, {\n url: urlConfig.getAPIPath('file') + path,\n }, extraParams);\n }\n\n var publicAsyncAPI = {\n /**\n * Get a directory listing, or contents of a file.\n * @param {String} filePath Path to the file\n * @param {Object} options (Optional) Overrides for configuration options.\n * @return {Promise}\n */\n getContents: function (filePath, options) {\n var path = serviceOptions.folderType + '/' + filePath;\n var httpOptions = $.extend(true, {}, serviceOptions, options, {\n url: urlConfig.getAPIPath('file') + path\n });\n return http.get('', httpOptions);\n },\n\n /**\n * Replaces the file at the given file path.\n * @param {String} filePath Path to the file\n * @param {String | FormData } contents Contents to write to file\n * @param {Object} options (Optional) Overrides for configuration options\n * @return {Promise}\n */\n replace: function (filePath, contents, options) {\n var httpOptions = uploadFileOptions(filePath, contents, options);\n return http.put(httpOptions.data, httpOptions);\n },\n\n /**\n * Creates a file in the given file path.\n * @param {String} filePath Path to the file\n * @param {String | FormData } contents Contents to write to file\n * @param {Boolean} replaceExisting Replace file if it already exists; defaults to false\n * @param {Object} options (Optional) Overrides for configuration options\n * @return {Promise}\n */\n create: function (filePath, contents, replaceExisting, options) {\n var httpOptions = uploadFileOptions(filePath, contents, options);\n var prom = http.post(httpOptions.data, httpOptions);\n var me = this;\n if (replaceExisting === true) {\n prom = prom.then(null, function (xhr) {\n var conflictStatus = 409;\n if (xhr.status === conflictStatus) {\n return me.replace(filePath, contents, options);\n }\n });\n }\n return prom;\n },\n\n /**\n * Removes the file.\n * @param {String} filePath Path to the file\n * @param {Object} options (Optional) Overrides for configuration options\n * @return {Promise}\n */\n remove: function (filePath, options) {\n var path = serviceOptions.folderType + '/' + filePath;\n var httpOptions = $.extend(true, {}, serviceOptions, options, {\n url: urlConfig.getAPIPath('file') + path\n });\n return http.delete(null, httpOptions);\n },\n\n /**\n * Renames the file.\n * @param {String} filePath Path to the file\n * @param {String} newName New name of file\n * @param {Object} options (Optional) Overrides for configuration options\n * @return {Promise}\n */\n rename: function (filePath, newName, options) {\n var path = serviceOptions.folderType + '/' + filePath;\n var httpOptions = $.extend(true, {}, serviceOptions, options, {\n url: urlConfig.getAPIPath('file') + path\n });\n return http.patch({ name: newName }, httpOptions);\n }\n };\n\n $.extend(this, publicAsyncAPI);\n};\n","/**\n * ## Asset API Adapter\n *\n * The Asset API Adapter allows you to store assets -- resources or files of any kind -- used by a project with a scope that is specific to project, group, or end user.\n *\n * Assets are used with [team projects](../../../project_admin/#team). One common use case is having end users in a [group](../../../glossary/#groups) or in a [multiplayer world](../../../glossary/#world) upload data -- videos created during game play, profile pictures for customizing their experience, etc. -- as part of playing through the project.\n *\n * Resources created using the Asset Adapter are scoped:\n *\n * * Project assets are writable only by [team members](../../../glossary/#team), that is, Epicenter authors.\n * * Group assets are writable by anyone with access to the project that is part of that particular [group](../../../glossary/#groups). This includes all [team members](../../../glossary/#team) (Epicenter authors) and any [end users](../../../glossary/#users) who are members of the group -- both facilitators and standard end users.\n * * User assets are writable by the specific end user, and by the facilitator of the group.\n * * All assets are readable by anyone with the exact URI.\n *\n * To use the Asset Adapter, instantiate it and then access the methods provided. Instantiating requires the account id (**Team ID** in the Epicenter user interface) and project id (**Project ID**). The group name is required for assets with a group scope, and the group name and userId are required for assets with a user scope. If not included, they are taken from the logged in user's session information if needed.\n *\n * When creating an asset, you can pass in text (encoded data) to the `create()` call. Alternatively, you can make the `create()` call as part of an HTML form and pass in a file uploaded via the form.\n *\n * // instantiate the Asset Adapter\n * var aa = new F.service.Asset({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * group: 'team1',\n * userId: '12345'\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\n'use strict';\n\nvar ConfigService = require('./configuration-service');\nvar TransportFactory = require('../transport/http-transport-factory');\nvar _pick = require('../util/object-util')._pick;\nvar SessionManager = require('../store/session-manager');\n\nvar apiEndpoint = 'asset';\n\nmodule.exports = function (config) {\n var defaults = {\n /**\n * For projects that require authentication, pass in the user access token (defaults to empty string). If the user is already logged in to Epicenter, the user access token is already set in a cookie and automatically loaded from there. (See [more background on access tokens](../../../project_access/)).\n * @see [Authentication API Service](../auth-api-service/) for getting tokens.\n * @type {String}\n */\n token: undefined,\n /**\n * The account id. In the Epicenter UI, this is the **Team ID** (for team projects). If left undefined, taken from the URL.\n * @type {String}\n */\n account: undefined,\n /**\n * The project id. If left undefined, taken from the URL.\n * @type {String}\n */\n project: undefined,\n /**\n * The group name. Defaults to session's `groupName`.\n * @type {String}\n */\n group: undefined,\n /**\n * The user id. Defaults to session's `userId`.\n * @type {String}\n */\n userId: undefined,\n /**\n * The scope for the asset. Valid values are: `user`, `group`, and `project`. See above for the required permissions to write to each scope. Defaults to `user`, meaning the current end user or a facilitator in the end user's group can edit the asset.\n * @type {String}\n */\n scope: 'user',\n /**\n * Determines if a request to list the assets in a scope includes the complete URL for each asset (`true`), or only the file names of the assets (`false`). Defaults to `true`.\n * @type {boolean}\n */\n fullUrl: true,\n /**\n * The transport object contains the options passed to the XHR request.\n * @type {object}\n */\n transport: {\n processData: false\n }\n };\n this.sessionManager = new SessionManager();\n var serviceOptions = this.sessionManager.getMergedOptions(defaults, config);\n var urlConfig = new ConfigService(serviceOptions).get('server');\n\n if (!serviceOptions.account) {\n serviceOptions.account = urlConfig.accountPath;\n }\n\n if (!serviceOptions.project) {\n serviceOptions.project = urlConfig.projectPath;\n }\n\n var transportOptions = $.extend(true, {}, serviceOptions.transport, {\n url: urlConfig.getAPIPath(apiEndpoint)\n });\n\n if (serviceOptions.token) {\n transportOptions.headers = {\n Authorization: 'Bearer ' + serviceOptions.token\n };\n }\n\n var http = new TransportFactory(transportOptions);\n\n var assetApiParams = ['encoding', 'data', 'contentType'];\n var scopeConfig = {\n user: ['scope', 'account', 'project', 'group', 'userId'],\n group: ['scope', 'account', 'project', 'group'],\n project: ['scope', 'account', 'project'],\n };\n\n var validateFilename = function (filename) {\n if (!filename) {\n throw new Error('filename is needed.');\n }\n };\n\n var validateUrlParams = function (options) {\n var partKeys = scopeConfig[options.scope];\n if (!partKeys) {\n throw new Error('scope parameter is needed.');\n }\n\n $.each(partKeys, function () {\n if (!options[this]) {\n throw new Error(this + ' parameter is needed.');\n }\n });\n };\n\n var buildUrl = function (filename, options) {\n validateUrlParams(options);\n var partKeys = scopeConfig[options.scope];\n var parts = $.map(partKeys, function (key) {\n return options[key];\n });\n if (filename) {\n // This prevents adding a trailing / in the URL as the Asset API\n // does not work correctly with it\n filename = '/' + filename;\n }\n return urlConfig.getAPIPath(apiEndpoint) + parts.join('/') + filename;\n };\n\n // Private function, all requests follow a more or less same approach to\n // use the Asset API and the difference is the HTTP verb\n //\n // @param {string} method` (Required) HTTP verb\n // @param {string} filename` (Required) Name of the file to delete/replace/create\n // @param {object} params` (Optional) Body parameters to send to the Asset API\n // @param {object} options` (Optional) Options object to override global options.\n var upload = function (method, filename, params, options) {\n validateFilename(filename);\n // make sure the parameter is clean\n method = method.toLowerCase();\n var contentType = params instanceof FormData === true ? false : 'application/json';\n if (contentType === 'application/json') {\n // whitelist the fields that we actually can send to the api\n params = _pick(params, assetApiParams);\n } else { // else we're sending form data which goes directly in request body\n // For multipart/form-data uploads the filename is not set in the URL,\n // it's getting picked by the FormData field filename.\n filename = method === 'post' || method === 'put' ? '' : filename;\n }\n var urlOptions = $.extend({}, serviceOptions, options);\n var url = buildUrl(filename, urlOptions);\n var createOptions = $.extend(true, {}, urlOptions, { url: url, contentType: contentType });\n\n return http[method](params, createOptions);\n };\n\n var publicAPI = {\n /**\n * Creates a file in the Asset API. The server returns an error (status code `409`, conflict) if the file already exists, so\n * check first with a `list()` or a `get()`.\n *\n * **Example**\n *\n * var aa = new F.service.Asset({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * group: 'team1',\n * userId: ''\n * });\n *\n * // create a new asset using encoded text\n * aa.create('test.txt', {\n * encoding: 'BASE_64',\n * data: 'VGhpcyBpcyBhIHRlc3QgZmlsZS4=',\n * contentType: 'text/plain'\n * }, { scope: 'user' });\n *\n * // alternatively, create a new asset using a file uploaded through a form\n * // this sample code goes with an html form that looks like this:\n * //\n * //
\n * // \n * // \n * // \n * //
\n * //\n * $('#upload-file').on('submit', function (e) {\n * e.preventDefault();\n * var filename = $('#filename').val();\n * var data = new FormData();\n * var inputControl = $('#file')[0];\n * data.append('file', inputControl.files[0], filename);\n *\n * aa.create(filename, data, { scope: 'user' });\n * });\n *\n *\n * **Parameters**\n * @param {string} filename (Required) Name of the file to create.\n * @param {object} params (Optional) Body parameters to send to the Asset API. Required if the `options.transport.contentType` is `application/json`, otherwise ignored.\n * @param {string} params.encoding Either `HEX` or `BASE_64`. Required if `options.transport.contentType` is `application/json`.\n * @param {string} params.data The encoded data for the file. Required if `options.transport.contentType` is `application/json`.\n * @param {string} params.contentType The mime type of the file. Optional.\n * @param {object} options (Optional) Options object to override global options.\n * @return {Promise}\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 * @return {Promise}\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 * @return {Promise}\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.resolveWith(me, [fullPathFiles]);\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 * @return {Promise}\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 * @return {Promise}\n */\n delete: function (filename, options) {\n return upload('delete', filename, {}, options);\n },\n\n assetUrl: function (filename, options) {\n var urlOptions = $.extend({}, serviceOptions, options);\n return buildUrl(filename, urlOptions);\n }\n };\n $.extend(this, publicAPI);\n};\n","/**\n *\n * ## Authentication API Service\n *\n * The Authentication API Service provides a method for logging in, which creates and returns a user access token.\n *\n * User access tokens are required for each call to Epicenter. (See [Project Access](../../../project_access/) for more information.)\n *\n * If you need additional functionality -- such as tracking session information, easily retrieving the user token, or getting the groups to which an end user belongs -- consider using the [Authorization Manager](../auth-manager/) instead.\n *\n * var auth = new F.service.Auth();\n * auth.login({ userName: 'jsmith@acmesimulations.com',\n * password: 'passw0rd' });\n */\n\n'use strict';\n\nvar ConfigService = require('./configuration-service');\nvar TransportFactory = require('../transport/http-transport-factory');\n\nmodule.exports = function (config) {\n var defaults = {\n /**\n * Email or username to use for logging in. Defaults to empty string.\n * @type {String}\n */\n userName: '',\n\n /**\n * Password for specified `userName`. Defaults to empty string.\n * @type {String}\n */\n password: '',\n\n /**\n * The account id for this `userName`. In the Epicenter UI, this is the **Team ID** (for team projects) or the **User ID** (for personal projects). Required if the `userName` is for an [end user](../../../glossary/#users). Defaults to empty string.\n * @type {String}\n */\n account: '',\n\n /**\n * Options to pass on to the underlying transport layer. All jquery.ajax options at http://api.jquery.com/jQuery.ajax/ are available. Defaults to empty object.\n * @type {Object}\n */\n transport: {}\n };\n var serviceOptions = $.extend({}, defaults, config);\n var urlConfig = new ConfigService(serviceOptions).get('server');\n\n var transportOptions = $.extend(true, {}, serviceOptions.transport, {\n url: urlConfig.getAPIPath('authentication')\n });\n var http = new TransportFactory(transportOptions);\n\n var publicAPI = {\n\n /**\n * Logs user in, returning the user access token.\n *\n * If no `userName` or `password` were provided in the initial configuration options, they are required in the `options` here. If no `account` was provided in the initial configuration options and the `userName` is for an [end user](../../../glossary/#users), the `account` is required as well.\n *\n * **Example**\n *\n * auth.login({\n * userName: 'jsmith',\n * password: 'passw0rd',\n * account: 'acme-simulations' })\n * .then(function (token) {\n * console.log(\"user access token is: \", token.access_token);\n * });\n *\n * **Parameters**\n * @param {Object} options (Optional) Overrides for configuration options.\n * @return {Promise}\n */\n login: function (options) {\n var httpOptions = $.extend(true, { success: $.noop }, serviceOptions, options);\n if (!httpOptions.userName || !httpOptions.password) {\n var resp = { status: 401, statusMessage: 'No username or password specified.' };\n if (options.error) {\n options.error.call(this, resp);\n }\n\n return $.Deferred().reject(resp).promise();\n }\n\n var postParams = {\n userName: httpOptions.userName,\n password: httpOptions.password,\n };\n if (httpOptions.account) {\n //pass in null for account under options if you don't want it to be sent\n postParams.account = httpOptions.account;\n }\n\n return http.post(postParams, httpOptions);\n },\n\n // (replace with /* */ comment block, to make visible in docs, once this is more than a noop)\n //\n // Logs user out from specified accounts.\n //\n // Epicenter logout is not implemented yet, so for now this is a dummy promise that gets automatically resolved.\n //\n // **Example**\n //\n // auth.logout();\n //\n // **Parameters**\n // @param {Object} `options` (Optional) Overrides for configuration options.\n //\n logout: function (options) {\n var dtd = $.Deferred();\n dtd.resolve();\n return dtd.promise();\n }\n };\n\n $.extend(this, publicAPI);\n};\n","/**\n * ## 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 * If you are developing with Epicenter.js, you should use the [Epicenter Channel Manager](../epicenter-channel-manager/) directly. The Epicenter Channel Manager documentation also has more [background](../epicenter-channel-manager/#background) information on channels and their use.\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 * 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 * If you are working through the [Epicenter Channel Manager](../epicenter-channel-manager/), when you ask to \"get\" a particular channel, you are really asking for an instance of the Channel Service with a topic already set, for example to the appropriate group or world:\n *\n * var cm = new F.manager.ChannelManager();\n * var gc = cm.getGroupChannel();\n * // because we used an Epicenter Channel Manager to get the group channel,\n * // subscribe() and publish() here default to the base topic for the group\n * gc.subscribe('', function(data) { console.log(data); });\n * gc.publish('', { message: 'a new message to the group' });\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 */\n\n'use strict';\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 * @param {String} topic topic to resolve\n * @return {String}\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 * @return {string} Subscription ID\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 * @return {Array | Object} Responses to published data\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 * @return {Object} reference to current instance\n */\n unsubscribe: function (token) {\n this.channelOptions.transport.unsubscribe(token);\n return this;\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","/**\n * @class ConfigurationService\n *\n * All services take in a configuration settings object to configure themselves. A JS hash {} is a valid configuration object, but optionally you can use the configuration service to toggle configs based on the environment\n *\n * @example\n * var cs = require('configuration-service')({\n * dev: { //environment\n port: 3000,\n host: 'localhost',\n },\n prod: {\n port: 8080,\n host: 'api.forio.com',\n logLevel: 'none'\n },\n logLevel: 'DEBUG' //global\n * });\n *\n * cs.get('logLevel'); //returns 'DEBUG'\n *\n * cs.setEnv('dev');\n * cs.get('logLevel'); //returns 'DEBUG'\n *\n * cs.setEnv('prod');\n * cs.get('logLevel'); //returns 'none'\n *\n */\n\n'use strict';\nvar urlService = require('./url-config-service');\n\nmodule.exports = function (config) {\n //TODO: Environments\n var defaults = {\n logLevel: 'NONE'\n };\n var serviceOptions = $.extend({}, defaults, config);\n serviceOptions.server = urlService(serviceOptions.server);\n\n return {\n\n data: serviceOptions,\n\n /**\n * Set the environment key to get configuration options from\n * @param { string} env\n */\n setEnv: function (env) {\n\n },\n\n /**\n * Get configuration.\n * @param { string} property optional\n * @return {*} Value of property if specified, the entire config object otherwise\n */\n get: function (property) {\n return serviceOptions[property];\n },\n\n /**\n * Set configuration.\n * @param { string|Object} key if a key is provided, set a key to that value. Otherwise merge object with current config\n * @param {*} value value for provided key\n */\n set: function (key, value) {\n serviceOptions[key] = value;\n }\n };\n};\n\n","/**\n * ## Data API Service\n *\n * The Data API Service allows you to create, access, and manipulate data related to any of your projects. Data are organized in collections. Each collection contains a document; each element of this top-level document is a JSON object. (See additional information on the underlying [Data API](../../../rest_apis/data_api/).)\n *\n * All API calls take in an \"options\" object as the last parameter. The options can be used to extend/override the Data API Service defaults. In particular, there are three required parameters when you instantiate the Data Service:\n *\n * * `account`: Epicenter account id (**Team ID** for team projects, **User ID** for personal projects).\n * * `project`: Epicenter project id.\n * * `root`: The the name of the collection. If you have multiple collections within each of your projects, you can also pass the collection name as an option for each call.\n *\n * var ds = new F.service.Data({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * root: 'survey-responses',\n * server: { host: 'api.forio.com' }\n * });\n * ds.saveAs('user1',\n * { 'question1': 2, 'question2': 10,\n * 'question3': false, 'question4': 'sometimes' } );\n * ds.saveAs('user2',\n * { 'question1': 3, 'question2': 8,\n * 'question3': true, 'question4': 'always' } );\n * ds.query('',{ 'question2': { '$gt': 9} });\n *\n * Note that in addition to the `account`, `project`, and `root`, the Data Service parameters optionally include a `server` object, whose `host` field contains the URI of the Forio server. This is automatically set, but you can pass it explicitly if desired. It is most commonly used for clarity when you are [hosting an Epicenter project on your own server](../../../how_to/self_hosting/).\n */\n\n'use strict';\n\nvar ConfigService = require('./configuration-service');\nvar qutil = require('../util/query-util');\nvar TransportFactory = require('../transport/http-transport-factory');\nvar SessionManager = require('../store/session-manager');\n\nmodule.exports = function (config) {\n var defaults = {\n /**\n * Name of collection. Required. Defaults to `/`, that is, the root level of your project at `forio.com/app/your-account-id/your-project-id/`, but must be set to a collection name.\n * @type {String}\n */\n root: '/',\n\n /**\n * The account id. In the Epicenter UI, this is the **Team ID** (for team projects) or **User ID** (for personal projects). Defaults to empty string. If left undefined, taken from the URL.\n * @type {String}\n */\n account: undefined,\n\n /**\n * The project id. Defaults to empty string. If left undefined, taken from the URL.\n * @type {String}\n */\n project: undefined,\n\n /**\n * For operations that require authentication, pass in the user access token (defaults to empty string). If the user is already logged in to Epicenter, the user access token is already set in a cookie and automatically loaded from there. (See [more background on access tokens](../../../project_access/)).\n * @see [Authentication API Service](../auth-api-service/) for getting tokens.\n * @type {String}\n */\n token: undefined,\n\n //Options to pass on to the underlying transport layer\n transport: {}\n };\n this.sessionManager = new SessionManager();\n var serviceOptions = this.sessionManager.getMergedOptions(defaults, config);\n\n var urlConfig = new ConfigService(serviceOptions).get('server');\n if (serviceOptions.account) {\n urlConfig.accountPath = serviceOptions.account;\n }\n if (serviceOptions.project) {\n urlConfig.projectPath = serviceOptions.project;\n }\n\n var getURL = function (key, root) {\n if (!root) {\n root = serviceOptions.root;\n }\n var url = urlConfig.getAPIPath('data') + qutil.addTrailingSlash(root);\n if (key) {\n url += qutil.addTrailingSlash(key);\n }\n return url;\n };\n\n var httpOptions = $.extend(true, {}, serviceOptions.transport, {\n url: getURL\n });\n if (serviceOptions.token) {\n httpOptions.headers = {\n Authorization: 'Bearer ' + serviceOptions.token\n };\n }\n var http = new TransportFactory(httpOptions);\n\n var publicAPI = {\n\n /**\n * Search for data within a collection.\n *\n * Searching using comparison or logical operators (as opposed to exact matches) requires MongoDB syntax. See the underlying [Data API](../../../rest_apis/data_api/#searching) for additional details.\n *\n * **Examples**\n *\n * // request all data associated with document 'user1'\n * ds.query('user1');\n *\n * // exact matching:\n * // request all documents in collection where 'question2' is 9\n * ds.query('', { 'question2': 9});\n *\n * // comparison operators:\n * // request all documents in collection\n * // where 'question2' is greater than 9\n * ds.query('', { 'question2': { '$gt': 9} });\n *\n * // logical operators:\n * // request all documents in collection\n * // where 'question2' is less than 10, and 'question3' is false\n * ds.query('', { '$and': [ { 'question2': { '$lt':10} }, { 'question3': false }] });\n *\n * // regular expresssions: use any Perl-compatible regular expressions\n * // request all documents in collection\n * // where 'question5' contains the string '.*day'\n * ds.query('', { 'question5': { '$regex': '.*day' } });\n *\n * **Parameters**\n * @param {String} key The name of the document to search. Pass the empty string ('') to search the entire collection.\n * @param {Object} query The query object. For exact matching, this object contains the field name and field value to match. For matching based on comparison, this object contains the field name and the comparison expression. For matching based on logical operators, this object contains an expression using MongoDB syntax. See the underlying [Data API](../../../rest_apis/data_api/#searching) for additional examples.\n * @param {Object} outputModifier (Optional) Available fields include: `startrecord`, `endrecord`, `sort`, and `direction` (`asc` or `desc`).\n * @param {Object} options (Optional) Overrides for configuration options.\n * @return {Promise} \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 in an anonymous document within the collection.\n *\n * The `root` of the collection must be specified. By default the `root` is taken from the Data Service configuration options; you can also pass the `root` to the `save` call explicitly by overriding the options (third parameter).\n *\n * (Additional background: 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 more information. The `save` method is making a `POST` request.)\n *\n * **Example**\n *\n * // Create a new document, with one element, at the default root level\n * ds.save('question1', 'yes');\n *\n * // Create a new document, with two elements, at the default root level\n * ds.save({ question1:'yes', question2: 32 });\n *\n * // Create a new document, with two elements, at `/students/`\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. If you want to override the default `root` of the collection, do so here.\n * @return {Promise} \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 (create or replace) data in a named document or element within the collection. \n * \n * The `root` of the collection must be specified. By default the `root` is taken from the Data Service configuration options; you can also pass the `root` to the `saveAs` call explicitly by overriding the options (third parameter).\n *\n * Optionally, the named document or element can include path information, so that you are saving just part of the document.\n *\n * (Additional background: 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 more information. The `saveAs` method is making a `PUT` request.)\n *\n * **Example**\n *\n * // Create (or replace) the `user1` document at the default root level.\n * // Note that this replaces any existing content in the `user1` document.\n * ds.saveAs('user1',\n * { 'question1': 2, 'question2': 10,\n * 'question3': false, 'question4': 'sometimes' } );\n *\n * // Create (or replace) the `student1` document at the `students` root, \n * // that is, the data at `/students/student1/`.\n * // Note that this replaces any existing content in the `/students/student1/` document.\n * // However, this will keep existing content in other paths of this collection.\n * // For example, the data at `/students/student2/` is unchanged by this call.\n * ds.saveAs('student1',\n * { firstName: 'john', lastName: 'smith' },\n * { root: 'students' });\n *\n * // Create (or replace) the `mgmt100/groupB` document at the `myclasses` root,\n * // that is, the data at `/myclasses/mgmt100/groupB/`.\n * // Note that this replaces any existing content in the `/myclasses/mgmt100/groupB/` document.\n * // However, this will keep existing content in other paths of this collection.\n * // For example, the data at `/myclasses/mgmt100/groupA/` is unchanged by this call.\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. If you want to override the default `root` of the collection, do so here.\n * @return {Promise} \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 * @return {Promise} \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 * @return {Promise} \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 * ## Group API Adapter\n *\n * The Group API Adapter provides methods to look up, create, change or remove information about groups in a project. It is based on query capabilities of the underlying RESTful [Group API](../../../rest_apis/user_management/group/).\n *\n * This is only needed for Authenticated projects, that is, team projects with [end users and groups](../../../groups_and_end_users/).\n *\n * var ma = new F.service.Group({ token: 'user-or-project-access-token' });\n * ma.getGroupsForProject({ account: 'acme', project: 'sample' });\n */\n\n'use strict';\n\nvar serviceUtils = require('./service-utils');\nvar TransportFactory = require('../transport/http-transport-factory');\nvar objectAssign = require('object-assign');\n\nvar apiEndpoint = 'group/local';\n\nvar GroupService = function (config) {\n var defaults = {\n /**\n * Epicenter account name. Defaults to undefined.\n * @type {string}\n */\n account: undefined,\n\n /**\n * Epicenter project name. Defaults to undefined.\n * @type {string}\n */\n project: undefined,\n\n /**\n * Options to pass on to the underlying transport layer. All jquery.ajax options at http://api.jquery.com/jQuery.ajax/ are available. Defaults to empty object.\n * @type {object}\n */\n transport: {}\n };\n var serviceOptions = serviceUtils.getDefaultOptions(defaults, config, { apiEndpoint: apiEndpoint });\n var transportOptions = serviceOptions.transport;\n delete serviceOptions.transport;\n var http = new TransportFactory(transportOptions, serviceOptions);\n var publicAPI = {\n /**\n * Gets information for a group or multiple groups.\n * @param {Object} params object with query parameters\n * @patam {string} params.q partial match for name, organization or event.\n * @patam {string} params.account Epicenter's Team ID\n * @patam {string} params.project Epicenter's Project ID\n * @patam {string} params.name Epicenter's Group Name\n * @param {Object} options (Optional) Overrides for configuration options.\n * @return {Promise}\n */\n getGroups: function (params, options) {\n //groupID is part of the URL\n //q, account and project are part of the query string\n var finalOpts = objectAssign({}, serviceOptions, options);\n var finalParams;\n if (typeof params === 'string') {\n finalOpts.url = serviceUtils.getApiUrl(apiEndpoint + '/' + params, finalOpts);\n } else {\n finalParams = params;\n }\n return http.get(finalParams, finalOpts);\n }\n };\n objectAssign(this, publicAPI);\n};\n\nmodule.exports = GroupService;\n","/**\n *\n * ## Introspection API Service\n *\n * The Introspection API Service allows you to view a list of the variables and operations in a model. Typically used in conjunction with the [Run API Service](../run-api-service/).\n *\n * The Introspection API Service is not available for Forio SimLang.\n *\n * var intro = new F.service.Introspect({\n * account: 'acme-simulations',\n * project: 'supply-chain-game'\n * });\n * intro.byModel('supply-chain.py').then(function(data){ ... });\n * intro.byRunID('2b4d8f71-5c34-435a-8c16-9de674ab72e6').then(function(data){ ... });\n *\n */\n\n'use strict';\n\nvar ConfigService = require('./configuration-service');\nvar TransportFactory = require('../transport/http-transport-factory');\nvar SessionManager = require('../store/session-manager');\n\nvar apiEndpoint = 'model/introspect';\n\nmodule.exports = function (config) {\n var defaults = {\n /**\n * For projects that require authentication, pass in the user access token (defaults to empty string). If the user is already logged in to Epicenter, the user access token is already set in a cookie and automatically loaded from there. (See [more background on access tokens](../../../project_access/)).\n * @see [Authentication API Service](../auth-api-service/) for getting tokens.\n * @type {String}\n */\n token: undefined,\n\n /**\n * The account id. In the Epicenter UI, this is the **Team ID** (for team projects) or **User ID** (for personal projects). Defaults to empty string. If left undefined, taken from the URL.\n * @type {String}\n */\n account: undefined,\n\n /**\n * The project id. Defaults to empty string. If left undefined, taken from the URL.\n * @type {String}\n */\n project: undefined,\n\n };\n\n var sessionManager = new SessionManager();\n var serviceOptions = sessionManager.getMergedOptions(defaults, config);\n\n var urlConfig = new ConfigService(serviceOptions).get('server');\n if (serviceOptions.account) {\n urlConfig.accountPath = serviceOptions.account;\n }\n if (serviceOptions.project) {\n urlConfig.projectPath = serviceOptions.project;\n }\n\n var transportOptions = $.extend(true, {}, serviceOptions.transport, {\n url: urlConfig.getAPIPath(apiEndpoint)\n });\n if (serviceOptions.token) {\n transportOptions.headers = {\n Authorization: 'Bearer ' + serviceOptions.token\n };\n }\n var http = new TransportFactory(transportOptions);\n\n var publicAPI = {\n /**\n * Get the available variables and operations for a given model file.\n *\n * Note: This does not work for any model which requires additional parameters, such as `files`.\n *\n * **Example**\n *\n * intro.byModel('abc.vmf')\n * .then(function(data) {\n * // data contains an object with available functions (used with operations API) and available variables (used with variables API)\n * console.log(data.functions);\n * console.log(data.variables);\n * });\n *\n * **Parameters**\n * @param {String} modelFile Name of the model file to introspect.\n * @param {Object} options (Optional) Overrides for configuration options.\n * @return {Promise} \n */\n byModel: function (modelFile, options) {\n var opts = $.extend(true, {}, serviceOptions, options);\n if (!opts.account || !opts.project) {\n throw new Error('Account and project are required when using introspect#byModel');\n }\n if (!modelFile) {\n throw new Error('modelFile is required when using introspect#byModel');\n }\n var url = { url: urlConfig.getAPIPath(apiEndpoint) + [opts.account, opts.project, modelFile].join('/') };\n var httpOptions = $.extend(true, {}, serviceOptions, options, url);\n return http.get('', httpOptions);\n },\n\n /**\n * Get the available variables and operations for a given model file.\n *\n * Note: This does not work for any model which requires additional parameters such as `files`.\n *\n * **Example**\n *\n * intro.byRunID('2b4d8f71-5c34-435a-8c16-9de674ab72e6')\n * .then(function(data) {\n * // data contains an object with available functions (used with operations API) and available variables (used with variables API)\n * console.log(data.functions);\n * console.log(data.variables);\n * });\n *\n * **Parameters**\n * @param {String} runID Id of the run to introspect.\n * @param {Object} options (Optional) Overrides for configuration options.\n * @return {Promise} \n */\n byRunID: function (runID, options) {\n if (!runID) {\n throw new Error('runID is required when using introspect#byModel');\n }\n var url = { url: urlConfig.getAPIPath(apiEndpoint) + runID };\n var httpOptions = $.extend(true, {}, serviceOptions, options, url);\n return http.get('', httpOptions);\n }\n };\n $.extend(this, publicAPI);\n};\n","/**\n *\n * ## Member API Adapter\n *\n * The Member API Adapter provides methods to look up information about end users for your project and how they are divided across groups. It is based on query capabilities of the underlying RESTful [Member API](../../../rest_apis/user_management/member/).\n *\n * This is only needed for Authenticated projects, that is, team projects with [end users and groups](../../../groups_and_end_users/). For example, if some of your end users are facilitators, or if your end users should be treated differently based on which group they are in, use the Member API to find that information.\n *\n * var ma = new F.service.Member({ token: 'user-or-project-access-token' });\n * ma.getGroupsForUser({ userId: 'b6b313a3-ab84-479c-baea-206f6bff337' });\n * ma.getGroupDetails({ groupId: '00b53308-9833-47f2-b21e-1278c07d53b8' });\n */\n\n'use strict';\n\nvar ConfigService = require('./configuration-service');\nvar TransportFactory = require('../transport/http-transport-factory');\nvar SessionManager = require('../store/session-manager');\nvar _pick = require('../util/object-util')._pick;\nvar apiEndpoint = 'member/local';\n\nmodule.exports = function (config) {\n var defaults = {\n /**\n * Epicenter user id. Defaults to a blank string.\n * @type {string}\n */\n userId: undefined,\n\n /**\n * Epicenter group id. Defaults to a blank string. Note that this is the group *id*, not the group *name*.\n * @type {string}\n */\n groupId: undefined,\n\n /**\n * Options to pass on to the underlying transport layer. All jquery.ajax options at http://api.jquery.com/jQuery.ajax/ are available. Defaults to empty object.\n * @type {object}\n */\n transport: {}\n };\n this.sessionManager = new SessionManager();\n var serviceOptions = this.sessionManager.getMergedOptions(defaults, config);\n var urlConfig = new ConfigService(serviceOptions).get('server');\n\n var transportOptions = $.extend(true, {}, serviceOptions.transport, {\n url: urlConfig.getAPIPath(apiEndpoint)\n });\n\n if (serviceOptions.token) {\n transportOptions.headers = {\n Authorization: 'Bearer ' + serviceOptions.token\n };\n }\n var http = new TransportFactory(transportOptions, serviceOptions);\n\n var getFinalParams = function (params) {\n if (typeof params === 'object') {\n return $.extend(true, serviceOptions, params);\n }\n return serviceOptions;\n };\n\n var patchUserActiveField = function (params, active, options) {\n var httpOptions = $.extend(true, serviceOptions, options, {\n url: urlConfig.getAPIPath(apiEndpoint) + params.groupId + '/' + params.userId\n });\n\n return http.patch({ active: active }, httpOptions);\n };\n\n var publicAPI = {\n\n /**\n * Retrieve details about all of the group memberships for one end user. The membership details are returned in an array, with one element (group record) for each group to which the end user belongs.\n *\n * In the membership array, each group record includes the group id, project id, account (team) id, and an array of members. However, only the user whose userId is included in the call is listed in the members array (regardless of whether there are other members in this group).\n *\n * **Example**\n *\n * var ma = new F.service.Member({ token: 'user-or-project-access-token' });\n * ma.getGroupsForUser('42836d4b-5b61-4fe4-80eb-3136e956ee5c')\n * .then(function(memberships){\n * for (var i=0; i 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 model or marked for saving in your [model context file](../../../model_code/context/)).\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 * @return {Promise}\n */\n query: function (qs, outputModifier, options) {\n var httpOptions = $.extend(true, {}, serviceOptions, { url: urlConfig.getFilterURL(qs) }, options);\n httpOptions = urlConfig.addAutoRestoreHeader(httpOptions);\n\n return http.splitGet(outputModifier, httpOptions).then(function (r) {\n return ($.isPlainObject(r) && Object.keys(r).length === 0) ? [] : r;\n });\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 model or marked for saving in your [model context file](../../../model_code/context/)).\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 * @return {Promise}\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).then(function (r) {\n return ($.isPlainObject(r) && Object.keys(r).length === 0) ? [] : r;\n });\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 or run record 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 or saved in your 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 * @return {Promise}\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 * Removes specified runid from memory\n *\n * **Example**\n *\n * rs.removeFromMemory('bb589677-d476-4971-a68e-0c58d191e450');\n *\n * See [details on run persistence](../../../run_persistence/#runs-in-memory)\n * @param {String} [runID] id of run to remove\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 * @return {Promise}\n */\n removeFromMemory: function (runID, filters, options) {\n var httpOptions = $.extend(true, {}, serviceOptions, options);\n if (runID) {\n httpOptions.url = urlConfig.getAPIPath('run') + runID;\n }\n return http.delete({}, httpOptions);\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 * // update 'saved' field of run record for a particular run\n * rs.save({ saved: true }, { id: '0000015bf2a04995880df6b868d23eb3d229' });\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 * @return {Promise}\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 an operation from the model.\n *\n * Depending on the language in which you have written your model, the operation (function or 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 * // operation \"solve\" takes no arguments\n * rs.do('solve');\n * // operation \"echo\" takes one argument, a string\n * rs.do('echo', ['hello']);\n * // operation \"echo\" takes one argument, a string\n * rs.do('echo', 'hello');\n * // operation \"sumArray\" takes one argument, an array\n * rs.do('sumArray', [[4,2,1]]);\n * // operation \"add\" takes two arguments, both integers\n * rs.do({ name:'add', params:[2,4] });\n * // call operation \"solve\" on a different run \n * rs.do('solve', { id: '0000015bf2a04995880df6b868d23eb3d229' });\n *\n * **Parameters**\n * @param {String} operation Name of operation.\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 * @return {Promise}\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 if ($.isPlainObject(params)) {\n opsArgs = null;\n postOptions = params;\n } else {\n opsArgs = params;\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 operations from the model, sequentially.\n *\n * Depending on the language in which you have written your model, the operation (function or 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 * **Examples**\n *\n * // operations \"initialize\" and \"solve\" do not take any arguments\n * rs.serial(['initialize', 'solve']);\n * // operations \"init\" and \"reset\" take two arguments each\n * rs.serial([ { name: 'init', params: [1,2] },\n * { name: 'reset', params: [2,3] }]);\n * // operation \"init\" takes two arguments,\n * // operation \"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 operations take parameters, pass an array of the operation names (strings). If any of the operations do take parameters, pass an array of objects, each of which contains an operation 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 * @return {Promise} The parameter to the callback is an array. Each array element is an object containing the results of one operation.\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 responses = [];\n var doSingleOp = function () {\n var op = ops.shift();\n var arg = args.shift();\n\n me.do(op, arg, {\n success: function (result) {\n responses.push(result);\n if (ops.length) {\n doSingleOp();\n } else {\n $d.resolve(responses);\n postOptions.success(responses, me);\n }\n },\n error: function (err) {\n responses.push(err);\n $d.reject(responses);\n postOptions.error(responses, me);\n }\n });\n };\n\n doSingleOp();\n\n return $d.promise();\n },\n\n /**\n * Call several operations from the model, executing them in parallel.\n *\n * Depending on the language in which you have written your model, the operation (function or 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 * **Example**\n *\n * // operations \"solve\" and \"reset\" do not take any arguments\n * rs.parallel(['solve', 'reset']);\n * // operations \"add\" and \"subtract\" take two arguments each\n * rs.parallel([ { name: 'add', params: [1,2] },\n * { name: 'subtract', params:[2,3] }]);\n * // operations \"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 operations take parameters, pass an array of the operation names (as strings). If any of the operations do take parameters, you have two options. You can pass an array of objects, each of which contains an operation name and its own (possibly empty) array of parameters. Alternatively, you can pass a single object with the operation 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 * @return {Promise} The parameter to the callback is an array. Each array element is an object containing the results of one operation.\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\n var me = this;\n $.when.apply(this, queue)\n .then(function () {\n var args = Array.prototype.slice.call(arguments);\n var actualResponse = args.map(function (a) {\n return a[0];\n });\n $d.resolve(actualResponse);\n postOptions.success(actualResponse, me);\n })\n .fail(function () {\n var args = Array.prototype.slice.call(arguments);\n var actualResponse = args.map(function (a) {\n return a[0];\n });\n $d.reject(actualResponse);\n postOptions.error(actualResponse, me);\n });\n\n return $d.promise();\n },\n\n /**\n * Shortcut to using the [Introspection API Service](../introspection-api-service/). Allows you to view a list of the variables and operations in a model.\n *\n * **Example**\n *\n * rs.introspect({ runID: 'cbf85437-b539-4977-a1fc-23515cf071bb' }).then(function (data) {\n * console.log(data.functions);\n * console.log(data.variables);\n * });\n *\n * **Parameters**\n * @param {Object} options Options can either be of the form `{ runID: }` or `{ model: }`. Note that the `runID` is optional if the Run Service is already associated with a particular run (because `id` was passed in when the Run Service was initialized). If provided, the `runID` overrides the `id` currently associated with the Run Service.\n * @param {Object} introspectionConfig (Optional) Service options for Introspection Service\n * @return {Promise}\n */\n introspect: function (options, introspectionConfig) {\n var introspection = new IntrospectionService($.extend(true, {}, serviceOptions, introspectionConfig));\n if (options) {\n if (options.runID) {\n return introspection.byRunID(options.runID);\n } else if (options.model) {\n return introspection.byModel(options.model);\n }\n } else if (serviceOptions.id) {\n return introspection.byRunID(serviceOptions.id);\n } else {\n throw new Error('Please specify either the model or runid to introspect');\n }\n }\n };\n\n var publicSyncAPI = {\n getCurrentConfig: function () {\n return serviceOptions;\n },\n updateConfig: function (config) {\n if (config && config.id) {\n config.filter = config.id;\n } else if (config && config.filter) {\n config.id = config.filter;\n }\n serviceOptions = $.extend(true, {}, serviceOptions, config);\n urlConfig = updateURLConfig(serviceOptions);\n this.urlConfig = urlConfig;\n updateHTTPConfig(serviceOptions, urlConfig);\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 * @return {Object} variablesService Instance\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","'use strict';\n\nvar ConfigService = require('./configuration-service');\nvar SessionManager = require('../store/session-manager');\nvar objectAssign = require('object-assign');\n\nvar serviceUtils = {\n /*\n * Gets the default options for a api service.\n * It will merge:\n * - The Session options (Using the Session Manager)\n * - The Authorization Header from the token option\n * - The full url from the endpoint option\n * With the supplied overrides and defaults\n *\n */\n getDefaultOptions: function (defaults) {\n var rest = Array.prototype.slice.call(arguments, 1);\n var sessionManager = new SessionManager();\n var serviceOptions = sessionManager.getMergedOptions.apply(sessionManager, [defaults].concat(rest));\n\n serviceOptions.transport = objectAssign({}, serviceOptions.transport, {\n url: this.getApiUrl(serviceOptions.apiEndpoint, serviceOptions)\n });\n\n if (serviceOptions.token) {\n serviceOptions.transport.headers = {\n Authorization: 'Bearer ' + serviceOptions.token\n };\n }\n return serviceOptions;\n },\n\n getApiUrl: function (apiEndpoint, serviceOptions) {\n var urlConfig = new ConfigService(serviceOptions).get('server');\n return urlConfig.getAPIPath(apiEndpoint);\n }\n};\n\nmodule.exports = serviceUtils;","'use strict';\n/**\n * ## State API Adapter\n *\n * The State API Adapter allows you to view the history of a run, and to replay or clone runs. \n *\n * The State API Adapter brings existing, persisted run data from the database back into memory, using the same run id (`replay`) or a new run id (`clone`). Runs must be in memory in order for you to update variables or call operations on them.\n *\n * Specifically, the State API Adapter works by \"re-running\" the run (user interactions) from the creation of the run up to the time it was last persisted in the database. This process uses the current version of the run's model. Therefore, if the model has changed since the original run was created, the retrieved run will use the new model — and may end up having different values or behavior as a result. Use with care!\n *\n * To use the State API Adapter, instantiate it and then call its methods:\n *\n * var sa = new F.service.State();\n * sa.replay({runId: '1842bb5c-83ad-4ba8-a955-bd13cc2fdb4f'});\n *\n * The constructor takes an optional `options` parameter in which you can specify the `account` and `project` if they are not already available in the current context.\n *\n */\n\nvar ConfigService = require('./configuration-service');\nvar TransportFactory = require('../transport/http-transport-factory');\nvar _pick = require('../util/object-util')._pick;\nvar SessionManager = require('../store/session-manager');\nvar apiEndpoint = 'model/state';\n\nmodule.exports = function (config) {\n\n var defaults = {\n\n };\n\n this.sessionManager = new SessionManager();\n var serviceOptions = this.sessionManager.getMergedOptions(defaults, config);\n var urlConfig = new ConfigService(serviceOptions).get('server');\n\n var transportOptions = $.extend(true, {}, serviceOptions.transport, {\n url: urlConfig.getAPIPath(apiEndpoint)\n });\n\n if (serviceOptions.token) {\n transportOptions.headers = {\n Authorization: 'Bearer ' + serviceOptions.token\n };\n }\n\n var http = new TransportFactory(transportOptions);\n var parseRunIdOrError = function (params) {\n if ($.isPlainObject(params) && params.runId) {\n return params.runId;\n } else {\n throw new Error('Please pass in a run id');\n }\n };\n\n var publicAPI = {\n\n /**\n * View the history of a run.\n * \n * **Example**\n *\n * var sa = new F.service.State();\n * sa.load('0000015a06bb58613b28b57365677ec89ec5').then(function(history) {\n * console.log('history = ', history);\n * });\n *\n * **Parameters**\n * @param {string} runId The id of the run.\n * @param {object} options (Optional) Overrides for configuration options.\n * @return {Promise}\n */\n load: function (runId, options) {\n var httpParams = $.extend(true, {},\n serviceOptions,\n options,\n { url: urlConfig.getAPIPath(apiEndpoint) + runId }\n );\n return http.get('', httpParams);\n },\n\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 * @return {Promise}\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 * @return {Promise}\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\nvar epiVersion = require('../api-version.json');\n\n//TODO: urlutils to get host, since no window on node\nvar defaults = {\n host: window.location.host,\n pathname: window.location.pathname\n};\n\nfunction getLocalHost(existingFn, host) {\n var localHostFn;\n if (existingFn !== undefined) {\n if (!$.isFunction(existingFn)) {\n localHostFn = function () { return existingFn; };\n } else {\n localHostFn = existingFn;\n }\n } else {\n localHostFn = function () {\n var isLocal = !host || //phantomjs\n host === '127.0.0.1' || \n host.indexOf('local.') === 0 || \n host.indexOf('localhost') === 0;\n return isLocal;\n };\n }\n return localHostFn;\n}\n\nvar UrlConfigService = function (config) {\n var envConf = UrlConfigService.defaults;\n\n if (!config) {\n config = {};\n }\n // console.log(this.defaults);\n var overrides = $.extend({}, envConf, config);\n var options = $.extend({}, defaults, overrides);\n\n overrides.isLocalhost = options.isLocalhost = getLocalHost(options.isLocalhost, options.host);\n \n // console.log(isLocalhost(), '___________');\n var actingHost = config && config.host;\n if (!actingHost && options.isLocalhost()) {\n actingHost = 'forio.com';\n } else {\n actingHost = options.host;\n }\n\n var API_PROTOCOL = 'https';\n var HOST_API_MAPPING = {\n 'forio.com': 'api.forio.com',\n 'foriodev.com': 'api.epicenter.foriodev.com'\n };\n\n var publicExports = {\n protocol: API_PROTOCOL,\n\n api: '',\n\n //TODO: this should really be called 'apihost', but can't because that would break too many things\n host: (function () {\n var apiHost = (HOST_API_MAPPING[actingHost]) ? HOST_API_MAPPING[actingHost] : actingHost;\n // console.log(actingHost, config, apiHost);\n return apiHost;\n }()),\n\n isCustomDomain: (function () {\n var path = options.pathname.split('\\/');\n var pathHasApp = path && path[1] === 'app';\n return (!options.isLocalhost() && !pathHasApp);\n }()),\n\n appPath: (function () {\n var path = options.pathname.split('\\/');\n\n return path && path[1] || '';\n }()),\n\n accountPath: (function () {\n var accnt = '';\n var path = options.pathname.split('\\/');\n if (path && path[1] === 'app') {\n accnt = path[2];\n }\n return accnt;\n }()),\n\n projectPath: (function () {\n var prj = '';\n var path = options.pathname.split('\\/');\n if (path && path[1] === 'app') {\n prj = path[3]; //eslint-disable-line no-magic-numbers\n }\n return prj;\n }()),\n\n versionPath: (function () {\n var version = epiVersion.version ? epiVersion.version + '/' : '';\n return version;\n }()),\n\n getAPIPath: function (api) {\n var PROJECT_APIS = ['run', 'data', 'file', 'presence'];\n var apiMapping = {\n channel: 'channel/subscribe'\n };\n var apiEndpoint = apiMapping[api] || api;\n \n if (apiEndpoint === 'config') {\n var actualProtocol = window.location.protocol.replace(':', '');\n var configProtocol = (options.isLocalhost()) ? this.protocol : actualProtocol;\n return configProtocol + '://' + actingHost + '/epicenter/' + this.versionPath + 'config';\n }\n var apiPath = this.protocol + '://' + this.host + '/' + this.versionPath + apiEndpoint + '/';\n\n if ($.inArray(apiEndpoint, PROJECT_APIS) !== -1) {\n apiPath += this.accountPath + '/' + this.projectPath + '/';\n }\n return apiPath;\n }\n };\n\n\n $.extend(publicExports, overrides);\n return publicExports;\n};\n// This data can be set by external scripts, for loading from an env server for eg;\nUrlConfigService.defaults = {};\n\nmodule.exports = UrlConfigService;\n","'use strict';\n/**\n* ## User API Adapter\n*\n* The User API Adapter allows you to retrieve details about end users in your team (account). It is based on the querying capabilities of the underlying RESTful [User API](../../../rest_apis/user_management/user/).\n*\n* To use the User API Adapter, instantiate it and then call its methods.\n*\n* var ua = new F.service.User({\n* account: 'acme-simulations',\n* token: 'user-or-project-access-token'\n* });\n* ua.getById('42836d4b-5b61-4fe4-80eb-3136e956ee5c');\n* ua.get({ userName: 'jsmith' });\n* ua.get({ id: ['42836d4b-5b61-4fe4-80eb-3136e956ee5c',\n* '4ea75631-4c8d-4872-9d80-b4600146478e'] });\n*\n* The constructor takes an optional `options` parameter in which you can specify the `account` and `token` if they are not already available in the current context.\n*/\n\nvar ConfigService = require('./configuration-service');\nvar TransportFactory = require('../transport/http-transport-factory');\nvar SessionManager = require('../store/session-manager');\nvar qutil = require('../util/query-util');\n\nmodule.exports = function (config) {\n var defaults = {\n\n /**\n * The account id. In the Epicenter UI, this is the **Team ID** (for team projects) or **User ID** (for personal projects). Defaults to empty string.\n * @type {String}\n */\n account: undefined,\n\n /**\n * The access token to use when searching for end users. (See [more background on access tokens](../../../project_access/)).\n * @type {String}\n */\n token: undefined,\n\n /**\n * Options to pass on to the underlying transport layer. All jquery.ajax options at http://api.jquery.com/jQuery.ajax/ are available. Defaults to empty object.\n * @type {Object}\n */\n transport: {}\n };\n\n this.sessionManager = new SessionManager();\n var serviceOptions = this.sessionManager.getMergedOptions(defaults, config);\n var urlConfig = new ConfigService(serviceOptions).get('server');\n var transportOptions = $.extend(true, {}, serviceOptions.transport, {\n url: urlConfig.getAPIPath('user')\n });\n\n if (serviceOptions.token) {\n transportOptions.headers = {\n Authorization: 'Bearer ' + serviceOptions.token\n };\n }\n\n var http = new TransportFactory(transportOptions);\n\n var publicAPI = {\n\n /**\n * Retrieve details about particular end users in your team, based on user name or user id.\n *\n * **Example**\n *\n * var ua = new F.service.User({\n * account: 'acme-simulations',\n * token: 'user-or-project-access-token'\n * });\n * ua.get({ userName: 'jsmith' });\n * ua.get({ id: ['42836d4b-5b61-4fe4-80eb-3136e956ee5c',\n * '4ea75631-4c8d-4872-9d80-b4600146478e'] });\n *\n * **Parameters**\n * @param {object} filter Object with field `userName` and value of the username. Alternatively, object with field `id` and value of an array of user ids.\n * @param {object} options (Optional) Overrides for configuration options.\n * @return {Promise}\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 * @return {Promise}\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 * ## 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\n module.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 //TODO: Replace with getCurrentconfig instead?\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 * @return {Promise}\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 * @return {Promise}\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 * @return {Promise}\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 * ## World API Adapter\n *\n * A [run](../../../glossary/#run) is a collection of end user interactions with a project and its model -- including setting variables, making decisions, and calling operations. For building multiplayer simulations you typically want multiple end users to share the same set of interactions, and work within a common state. Epicenter allows you to create \"worlds\" to handle such cases. Only [team projects](../../../glossary/#team) can be multiplayer.\n *\n * The World API Adapter allows you to create, access, and manipulate multiplayer worlds within your Epicenter project. You can use this to add and remove end users from the world, and to create, access, and remove their runs. Because of this, typically the World Adapter is used for facilitator pages in your project. (The related [World Manager](../world-manager/) provides an easy way to access runs and worlds for particular end users, so is typically used in pages that end users will interact with.)\n *\n * As with all the other [API Adapters](../../), all methods take in an \"options\" object as the last parameter. The options can be used to extend/override the World API Service defaults.\n *\n * To use the World Adapter, instantiate it and then access the methods provided. Instantiating requires the account id (**Team ID** in the Epicenter user interface), project id (**Project ID**), and group (**Group Name**).\n *\n * var wa = new F.service.World({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * group: 'team1' });\n * wa.create()\n * .then(function(world) {\n * // call methods, e.g. wa.addUsers()\n * });\n */\n\n'use strict';\n\nvar ConfigService = require('./configuration-service');\n// var qutil = require('../util/query-util');\nvar TransportFactory = require('../transport/http-transport-factory');\nvar SessionManager = require('../store/session-manager');\nvar _pick = require('../util/object-util')._pick;\n\nvar apiBase = 'multiplayer/';\nvar assignmentEndpoint = apiBase + 'assign';\nvar apiEndpoint = apiBase + 'world';\nvar projectEndpoint = apiBase + 'project';\n\nmodule.exports = function (config) {\n var defaults = {\n /**\n * For projects that require authentication, pass in the user access token (defaults to empty string). If the user is already logged in to Epicenter, the user access token is already set in a cookie and automatically loaded from there. (See [more background on access tokens](../../../project_access/)).\n * @see [Authentication API Service](../auth-api-service/) for getting tokens.\n * @type {String}\n */\n token: undefined,\n\n /**\n * The project id. If left undefined, taken from the URL.\n * @type {String}\n */\n project: undefined,\n\n /**\n * The account id. In the Epicenter UI, this is the **Team ID** (for team projects). If left undefined, taken from the URL.\n * @type {String}\n */\n account: undefined,\n\n /**\n * The group name. Defaults to undefined.\n * @type {String}\n */\n group: undefined,\n\n /**\n * The model file to use to create runs in this world. Defaults to undefined.\n * @type {String}\n */\n model: undefined,\n\n /**\n * Criteria by which to filter world. Currently only supports world-ids as filters.\n * @type {String}\n */\n filter: '',\n\n /**\n * Convenience alias for filter\n * @type {String}\n */\n id: '',\n\n /**\n * Options to pass on to the underlying transport layer. All jquery.ajax options at http://api.jquery.com/jQuery.ajax/ are available. Defaults to empty object.\n * @type {Object}\n */\n transport: {},\n\n /**\n * Called when the call completes successfully. Defaults to `$.noop`.\n * @type {function}\n */\n success: $.noop,\n\n /**\n * Called when the call fails. Defaults to `$.noop`.\n * @type {function}\n */\n error: $.noop\n };\n\n this.sessionManager = new SessionManager();\n var serviceOptions = this.sessionManager.getMergedOptions(defaults, config);\n if (serviceOptions.id) {\n serviceOptions.filter = serviceOptions.id;\n }\n\n var urlConfig = new ConfigService(serviceOptions).get('server');\n\n if (!serviceOptions.account) {\n serviceOptions.account = urlConfig.accountPath;\n }\n\n if (!serviceOptions.project) {\n serviceOptions.project = urlConfig.projectPath;\n }\n\n var transportOptions = $.extend(true, {}, serviceOptions.transport, {\n url: urlConfig.getAPIPath(apiEndpoint)\n });\n\n if (serviceOptions.token) {\n transportOptions.headers = {\n Authorization: 'Bearer ' + serviceOptions.token\n };\n }\n\n var http = new TransportFactory(transportOptions);\n\n var setIdFilterOrThrowError = function (options) {\n if (options.id) {\n serviceOptions.filter = options.id;\n }\n if (options.filter) {\n serviceOptions.filter = options.filter;\n }\n if (!serviceOptions.filter) {\n throw new Error('No world id specified to apply operations against. This could happen if the user is not assigned to a world and is trying to work with runs from that world.');\n }\n };\n\n var validateModelOrThrowError = function (options) {\n if (!options.model) {\n throw new Error('No model specified to get the current run');\n }\n };\n\n var publicAPI = {\n\n /**\n * Creates a new World.\n *\n * Using this method is rare. It is more common to create worlds automatically while you `autoAssign()` end users to worlds. (In this case, configuration data for the world, such as the roles, are read from the project-level world configuration information, for example by `getProjectSettings()`.)\n *\n * **Example**\n *\n * var wa = new F.service.World({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * group: 'team1' });\n * wa.create({\n * roles: ['VP Marketing', 'VP Sales', 'VP Engineering']\n * });\n *\n * **Parameters**\n * @param {object} params Parameters to create the world.\n * @param {string} params.group (Optional) The **Group Name** to create this world under. Only end users in this group are eligible to join the world. Optional here; required when instantiating the service (`new F.service.World()`).\n * @param {object} params.roles (Optional) The list of roles (strings) for this world. Some worlds have specific roles that **must** be filled by end users. Listing the roles allows you to autoassign users to worlds and ensure that all roles are filled in each world.\n * @param {object} params.optionalRoles (Optional) The list of optional roles (strings) for this world. Some worlds have specific roles that **may** be filled by end users. Listing the optional roles as part of the world object allows you to autoassign users to worlds and ensure that all roles are filled in each world.\n * @param {integer} params.minUsers (Optional) The minimum number of users for the world. Including this number allows you to autoassign end users to worlds and ensure that the correct number of users are in each world.\n * @param {object} options (Optional) Options object to override global options.\n * @return {Promise}\n */\n create: function (params, options) {\n var createOptions = $.extend(true, {}, serviceOptions, options, { url: urlConfig.getAPIPath(apiEndpoint) });\n var worldApiParams = ['scope', 'files', 'roles', 'optionalRoles', 'minUsers', 'group', 'name'];\n var validParams = _pick(serviceOptions, ['account', 'project', 'group']);\n // whitelist the fields that we actually can send to the api\n params = _pick(params, worldApiParams);\n\n // account and project go in the body, not in the url\n params = $.extend({}, validParams, params);\n\n var oldSuccess = createOptions.success;\n createOptions.success = function (response) {\n serviceOptions.filter = response.id; //all future chained calls to operate on this id\n return oldSuccess.apply(this, arguments);\n };\n\n return http.post(params, createOptions);\n },\n\n /**\n * Updates a World, for example to replace the roles in the world.\n *\n * Typically, you complete world configuration at the project level, rather than at the world level. For example, each world in your project probably has the same roles for end users. And your project is probably either configured so that all end users share the same world (and run), or smaller sets of end users share worlds — but not both. However, this method is available if you need to update the configuration of a particular world.\n *\n * **Example**\n *\n * var wa = new F.service.World({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * group: 'team1' });\n * wa.create()\n * .then(function(world) {\n * wa.update({ roles: ['VP Marketing', 'VP Sales', 'VP Engineering'] });\n * });\n *\n * **Parameters**\n * @param {object} params Parameters to update the world.\n * @param {string} params.name A string identifier for the linked end users, for example, \"name\": \"Our Team\".\n * @param {object} params.roles (Optional) The list of roles (strings) for this world. Some worlds have specific roles that **must** be filled by end users. Listing the roles allows you to autoassign users to worlds and ensure that all roles are filled in each world.\n * @param {object} params.optionalRoles (Optional) The list of optional roles (strings) for this world. Some worlds have specific roles that **may** be filled by end users. Listing the optional roles as part of the world object allows you to autoassign users to worlds and ensure that all roles are filled in each world.\n * @param {integer} params.minUsers (Optional) The minimum number of users for the world. Including this number allows you to autoassign end users to worlds and ensure that the correct number of users are in each world.\n * @param {object} options (Optional) Options object to override global options.\n * @return {Promise}\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 * @return {Promise}\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 * @return {Object} reference to current instance\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 * @return {Promise}\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 * @return {Promise}\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 * @return {Promise}\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 * @return {Promise}\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 * @return {Promise}\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 * @return {Promise}\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 * @return {Promise}\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 * @return {Promise}\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.resolveWith(me, [currentWorld]);\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 * @return {Promise}\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 * @return {Promise}\n */\n newRunForWorld: function (worldId, options) {\n var currentRunOptions = $.extend(true, {},\n serviceOptions,\n options,\n { filter: worldId || serviceOptions.filter }\n );\n var me = this;\n\n validateModelOrThrowError(currentRunOptions);\n\n return this.deleteRun(worldId, options)\n .then(function () {\n return me.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 * @param {number} options.maxUsers Sets the maximum number of users in a world.\n * @param {string[]} options.userIds A list of users to be assigned be assigned instead of all end users in the group.\n * @return {Promise}\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 if (opt.userIds) {\n params.userIds = opt.userIds;\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 * @return {Promise}\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 return http.get(null, opt);\n }\n\n };\n\n $.extend(this, publicAPI);\n};\n","/**\n * @class Cookie Storage Service\n *\n * @example\n * var people = require('cookie-store')({ root: 'people' });\n people\n .save({lastName: 'smith' })\n\n */\n\n\n'use strict';\n\n// Thin document.cookie wrapper to allow unit testing\nvar Cookie = function () {\n this.get = function () {\n return document.cookie;\n };\n\n this.set = function (newCookie) {\n document.cookie = newCookie;\n };\n};\n\nmodule.exports = function (config) {\n var host = window.location.hostname;\n var validHost = host.split('.').length > 1;\n var domain = validHost ? '.' + host : null;\n\n var defaults = {\n /**\n * Name of collection\n * @type { string}\n */\n root: '/',\n\n domain: domain,\n cookie: new Cookie()\n };\n this.serviceOptions = $.extend({}, defaults, config);\n\n var publicAPI = {\n // * TBD\n // * Query collection; uses MongoDB syntax\n // * @see \n // *\n // * @param { string} qs Query Filter\n // * @param { string} limiters @see \n // *\n // * @example\n // * cs.query(\n // * { name: 'John', className: 'CSC101' },\n // * {limit: 10}\n // * )\n\n // query: function (qs, limiters) {\n\n // },\n\n /**\n * Save cookie value\n * @param { string|Object} key If given a key save values under it, if given an object directly, save to top-level api\n * @param {Object} value (Optional)\n * @param {Object} options Overrides for service options\n *\n * @return {*} The saved value\n *\n * @example\n * cs.set('person', { firstName: 'john', lastName: 'smith' });\n * cs.set({ name:'smith', age:'32' });\n */\n set: function (key, value, options) {\n var setOptions = $.extend(true, {}, this.serviceOptions, options);\n\n var domain = setOptions.domain;\n var path = setOptions.root;\n var cookie = setOptions.cookie;\n\n cookie.set(encodeURIComponent(key) + '=' +\n encodeURIComponent(value) +\n (domain ? '; domain=' + domain : '') +\n (path ? '; path=' + path : '')\n );\n\n return value;\n },\n\n /**\n * Load cookie value\n * @param { string|Object} key If given a key save values under it, if given an object directly, save to top-level api\n * @return {*} The value stored\n *\n * @example\n * cs.get('person');\n */\n get: function (key) {\n var cookie = this.serviceOptions.cookie;\n var cookieReg = new RegExp('(?:^|;)\\\\s*' + encodeURIComponent(key).replace(/[\\-\\.\\+\\*]/g, '\\\\$&') + '\\\\s*\\\\=\\\\s*([^;]*).*$');\n var res = cookieReg.exec(cookie.get());\n var val = res ? decodeURIComponent(res[1]) : null;\n return val;\n },\n\n /**\n * Removes key from collection\n * @param { string} key key to remove\n * @param {object} options (optional) overrides for service options\n * @return { string} key The key removed\n *\n * @example\n * cs.remove('person');\n */\n remove: function (key, options) {\n var remOptions = $.extend(true, {}, this.serviceOptions, options);\n\n var domain = remOptions.domain;\n var path = remOptions.root;\n var cookie = remOptions.cookie;\n\n cookie.set(encodeURIComponent(key) +\n '=; expires=Thu, 01 Jan 1970 00:00:00 GMT' +\n (domain ? '; domain=' + domain : '') +\n (path ? '; path=' + path : '')\n );\n return key;\n },\n\n /**\n * Removes collection being referenced\n * @return { array} keys All the keys removed\n */\n destroy: function () {\n var cookie = this.serviceOptions.cookie;\n var aKeys = cookie.get().replace(/((?:^|\\s*;)[^\\=]+)(?=;|$)|^\\s*|\\s*(?:\\=[^;]*)?(?:\\1|$)/g, '').split(/\\s*(?:\\=[^;]*)?;\\s*/);\n for (var nIdx = 0; nIdx < aKeys.length; nIdx++) {\n var cookieKey = decodeURIComponent(aKeys[nIdx]);\n this.remove(cookieKey);\n }\n return aKeys;\n }\n };\n\n $.extend(this, publicAPI);\n};\n","'use strict';\n\nvar keyNames = require('../managers/key-names');\nvar StorageFactory = require('./store-factory');\nvar optionUtils = require('../util/option-utils');\n\nvar EPI_SESSION_KEY = keyNames.EPI_SESSION_KEY;\nvar EPI_MANAGER_KEY = 'epicenter.token'; //can't be under key-names, or logout will clear this too\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 SessionManager = function (managerOptions) {\n managerOptions = managerOptions || {};\n function getBaseOptions(overrides) {\n overrides = overrides || {};\n var libOptions = optionUtils.getOptions();\n var finalOptions = $.extend(true, {}, defaults, libOptions, managerOptions, overrides);\n return finalOptions;\n }\n\n function getStore(overrides) {\n var baseOptions = getBaseOptions(overrides);\n var storeOpts = baseOptions.store || {};\n var isEpicenterDomain = !baseOptions.isLocal && !baseOptions.isCustomDomain;\n if (storeOpts.root === undefined && baseOptions.account && baseOptions.project && isEpicenterDomain) {\n storeOpts.root = '/app/' + baseOptions.account + '/' + baseOptions.project;\n }\n return new StorageFactory(storeOpts);\n }\n\n var publicAPI = {\n saveSession: function (userInfo, options) {\n var serialized = JSON.stringify(userInfo);\n getStore(options).set(EPI_SESSION_KEY, serialized);\n },\n getSession: function (options) {\n var store = getStore(options);\n var finalOpts = store.serviceOptions;\n var serialized = store.get(EPI_SESSION_KEY) || '{}';\n var session = JSON.parse(serialized);\n // If the url contains the project and account\n // validate the account and project in the session\n // and override project, groupName, groupId and isFac\n // Otherwise (i.e. localhost) use the saved session values\n var account = finalOpts.account;\n var project = finalOpts.project;\n if (account && session.account !== account) {\n // This means that the token was not used to login to the same account\n return {};\n }\n if (session.groups && account && project) {\n var group = session.groups[project] || { groupId: '', groupName: '', isFac: false };\n $.extend(session, { project: project }, group);\n }\n return session;\n },\n removeSession: function (options) {\n var store = getStore(options);\n Object.keys(keyNames).forEach(function (cookieKey) {\n var cookieName = keyNames[cookieKey];\n store.remove(cookieName);\n });\n return true;\n },\n getStore: function (options) {\n return getStore(options);\n },\n\n getMergedOptions: function () {\n var args = Array.prototype.slice.call(arguments);\n var overrides = $.extend.apply($, [true, {}].concat(args));\n var baseOptions = getBaseOptions(overrides);\n var session = this.getSession(overrides);\n\n var token = session.auth_token;\n if (!token) {\n var factory = new StorageFactory();\n token = factory.get(EPI_MANAGER_KEY);\n }\n\n var sessionDefaults = {\n /**\n * For projects that require authentication, pass in the user access token (defaults to empty string). If the user is already logged in to Epicenter, the user access token is already set in a cookie and automatically loaded from there. (See [more background on access tokens](../../../project_access/)).\n * @see [Authentication API Service](../auth-api-service/) for getting tokens.\n * @type {String}\n */\n token: token,\n\n /**\n * The account. If left undefined, taken from the cookie session.\n * @type {String}\n */\n account: session.account,\n\n /**\n * The project. If left undefined, taken from the cookie session.\n * @type {String}\n */\n project: session.project,\n\n\n /**\n * The group name. If left undefined, taken from the cookie session.\n * @type {String}\n */\n group: session.groupName,\n /**\n * Alias for group. \n * @type {String}\n */\n groupName: session.groupName, //It's a little weird that it's called groupName in the cookie, but 'group' in all the service options, so normalize for both\n /**\n * The group id. If left undefined, taken from the cookie session.\n * @type {String}\n */\n groupId: session.groupId,\n userId: session.userId,\n userName: session.userName,\n };\n return $.extend(true, sessionDefaults, baseOptions);\n }\n };\n $.extend(this, publicAPI);\n};\n\nmodule.exports = SessionManager;","/**\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';\n\nvar qutils = require('../util/query-util');\n\nmodule.exports = function (config) {\n\n var defaults = {\n url: '',\n\n contentType: 'application/json',\n headers: {},\n statusCode: {\n 404: $.noop\n },\n\n /**\n * ONLY for strings in the url. All GET & DELETE params are run through this\n * @type {[type] }\n */\n parameterParser: qutils.toQueryFormat,\n\n // To allow epicenter.token and other session cookies to be passed\n // with the requests\n xhrFields: {\n withCredentials: true\n }\n };\n\n var transportOptions = $.extend({}, defaults, config);\n\n var result = function (d) {\n return ($.isFunction(d)) ? d() : d;\n };\n\n var connect = function (method, params, connectOptions) {\n params = result(params);\n params = ($.isPlainObject(params) || $.isArray(params)) ? JSON.stringify(params) : params;\n\n var options = $.extend(true, {}, transportOptions, connectOptions, {\n type: method,\n data: params\n });\n var ALLOWED_TO_BE_FUNCTIONS = ['data', 'url'];\n $.each(options, function (key, value) {\n if ($.isFunction(value) && $.inArray(key, ALLOWED_TO_BE_FUNCTIONS) !== -1) {\n options[key] = value();\n }\n });\n\n if (options.logLevel && options.logLevel === 'DEBUG') {\n console.log(options.url);\n var oldSuccessFn = options.success || $.noop;\n options.success = function (response, ajaxStatus, ajaxReq) {\n console.log(response);\n oldSuccessFn.apply(this, arguments);\n };\n }\n\n var beforeSend = options.beforeSend;\n options.beforeSend = function (xhr, settings) {\n xhr.requestUrl = (connectOptions || {}).url;\n if (beforeSend) {\n beforeSend.apply(this, arguments);\n }\n };\n\n return $.ajax(options);\n };\n\n var publicAPI = {\n get: function (params, ajaxOptions) {\n var options = $.extend({}, transportOptions, ajaxOptions);\n params = options.parameterParser(result(params));\n return connect.call(this, 'GET', params, options);\n },\n splitGet: function () {\n\n },\n post: function () {\n return connect.apply(this, ['post'].concat([].slice.call(arguments)));\n },\n patch: function () {\n return connect.apply(this, ['patch'].concat([].slice.call(arguments)));\n },\n put: function () {\n return connect.apply(this, ['put'].concat([].slice.call(arguments)));\n },\n delete: function (params, ajaxOptions) {\n //DELETE doesn't support body params, but jQuery thinks it does.\n var options = $.extend({}, transportOptions, ajaxOptions);\n params = options.parameterParser(result(params));\n if ($.trim(params)) {\n var delimiter = (result(options.url).indexOf('?') === -1) ? '?' : '&';\n options.url = result(options.url) + delimiter + params;\n }\n return connect.call(this, 'DELETE', null, options);\n },\n head: function () {\n return connect.apply(this, ['head'].concat([].slice.call(arguments)));\n },\n options: function () {\n return connect.apply(this, ['options'].concat([].slice.call(arguments)));\n }\n };\n\n return $.extend(this, publicAPI);\n};\n","'use strict';\n\n// var isNode = false; FIXME: Browserify/minifyify has issues with the next link\n// var transport = (isNode) ? require('./node-http-transport') : require('./ajax-http-transport');\nvar transport = require('./ajax-http-transport');\nmodule.exports = transport;\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* @param {Object} dest object to extend\n* @return {Object} extended 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 < obj.length; j++) {\n if (!(current = obj[j])) { //eslint-disable-line\n continue;\n }\n\n // do not wrap inner in dest.hasOwnProperty or bad things will happen\n for (var key in current) { //eslint-disable-line\n dest[key] = current[key];\n }\n }\n\n return dest;\n};\n\nmodule.exports = function (base, props, staticProps) {\n var parent = base;\n var child;\n\n child = props && props.hasOwnProperty('constructor') ? props.constructor : function () { return parent.apply(this, arguments); };\n\n // add static properties to the child constructor function\n extend(child, parent, staticProps);\n\n // associate prototype chain\n inherit(child, parent);\n\n // add instance properties\n if (props) {\n extend(child.prototype, props);\n }\n\n // done\n return child;\n};\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 isEmpty: function isEmpty(value) {\n return (!value || ($.isPlainObject(value) && Object.keys(value).length === 0));\n }\n};\n","'use strict';\n\nvar ConfigService = require('../service/configuration-service');\n\nvar urlConfig = new ConfigService().get('server');\nvar customDefaults = {};\nvar libDefaults = {\n /**\n * The account id. In the Epicenter UI, this is the **Team ID** (for team projects) or **User ID** (for personal projects). Defaults to empty string. If left undefined, taken from the URL.\n * @type {String}\n */\n account: urlConfig.accountPath || undefined,\n /**\n * The account id. In the Epicenter UI, this is the **Team ID** (for team projects) or **User ID** (for personal projects). Defaults to empty string. If left undefined, taken from the URL.\n * @type {String}\n */\n project: urlConfig.projectPath || undefined,\n isLocal: urlConfig.isLocalhost(),\n isCustomDomain: urlConfig.isCustomDomain,\n store: {}\n};\n\nvar optionUtils = {\n /**\n * Gets the final options by overriding the global options set with\n * optionUtils#setDefaults() and the lib defaults.\n * @param {object} options The final options object.\n * @return {object} Extended object\n */\n getOptions: function (options) {\n return $.extend(true, {}, libDefaults, customDefaults, options);\n },\n /**\n * Sets the global defaults for the optionUtils#getOptions() method.\n * @param {object} defaults The defaults object.\n */\n setDefaults: function (defaults) {\n customDefaults = defaults;\n }\n};\nmodule.exports = optionUtils;\n","/**\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 * 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 * normalizes different types of operation inputs\n * @param {Object|Array|String} operations operations to perform\n * @param {Array} args arguments for operation\n * @return {String} operations of the form `{ ops: [], args: [] }`\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; //eslint-disable-line\n var getValue = function (name) {\n var value = options[name] || httpOptions[name];\n if (typeof value === 'function') {\n value = value();\n }\n return value;\n };\n var getFinalUrl = function (params) {\n var url = getValue('url', options);\n var data = params;\n // There is easy (or known) way to get the final URL jquery is going to send so\n // we're replicating it. The process might change at some point but it probably will not.\n // 1. Remove hash\n url = url.replace(/#.*$/, '');\n // 1. Append query string\n var queryParams = qutil.toQueryFormat(data);\n var questionIdx = url.indexOf('?');\n if (queryParams && questionIdx > -1) {\n return url + '&' + queryParams;\n } else if (queryParams) {\n return url + '?' + queryParams;\n }\n return url;\n };\n var url = getFinalUrl(params);\n // We must split the GET in multiple short URL's\n // The only property allowed to be split is \"include\"\n if (params && params.include && encodeURI(url).length > MAX_URL_LENGTH) {\n var dtd = $.Deferred();\n var paramsCopy = $.extend(true, {}, params);\n delete paramsCopy.include;\n var urlNoIncludes = getFinalUrl(paramsCopy);\n var diff = MAX_URL_LENGTH - urlNoIncludes.length;\n var oldSuccess = options.success || httpOptions.success || $.noop;\n var oldError = options.error || httpOptions.error || $.noop;\n // remove the original success and error callbacks\n options.success = $.noop;\n options.error = $.noop;\n\n var include = params.include;\n var currIncludes = [];\n var includeOpts = [currIncludes];\n var currLength = encodeURIComponent('?include=').length;\n var variable = include.pop();\n while (variable) {\n var varLenght = encodeURIComponent(variable).length;\n // Use a greedy approach for now, can be optimized to be solved in a more\n // efficient way\n // + 1 is the comma\n if (currLength + varLenght + 1 < diff) {\n currIncludes.push(variable);\n currLength += varLenght + 1;\n } else {\n currIncludes = [variable];\n includeOpts.push(currIncludes);\n currLength = '?include='.length + varLenght;\n }\n variable = include.pop();\n }\n var reqs = $.map(includeOpts, function (include) {\n var reqParams = $.extend({}, params, { include: include });\n return http.get(reqParams, options);\n });\n $.when.apply($, reqs).then(function () {\n // Each argument are arrays of the arguments of each done request\n // So the first argument of the first array of arguments is the data\n var isValid = arguments[0] && arguments[0][0];\n if (!isValid) {\n // Should never happen...\n oldError();\n return dtd.reject();\n }\n var firstResponse = arguments[0][0];\n var isObject = $.isPlainObject(firstResponse);\n var isRunAPI = (isObject && $.isPlainObject(firstResponse.variables)) || !isObject;\n if (isRunAPI) {\n if (isObject) {\n // aggregate the variables property only\n var aggregateRun = arguments[0][0];\n $.each(arguments, function (idx, args) {\n var run = args[0];\n $.extend(true, aggregateRun.variables, run.variables);\n });\n oldSuccess(aggregateRun, arguments[0][1], arguments[0][2]);\n dtd.resolve(aggregateRun, arguments[0][1], arguments[0][2]);\n } else {\n // array of runs\n // Agregate variables in each run\n var aggregatedRuns = {};\n $.each(arguments, function (idx, args) {\n var runs = args[0];\n if (!$.isArray(runs)) {\n return;\n }\n $.each(runs, function (idxRun, run) {\n if (run.id && !aggregatedRuns[run.id]) {\n run.variables = run.variables || {};\n aggregatedRuns[run.id] = run;\n } else if (run.id) {\n $.extend(true, aggregatedRuns[run.id].variables, run.variables);\n }\n });\n });\n // turn it into an array\n aggregatedRuns = $.map(aggregatedRuns, function (run) { return run; });\n oldSuccess(aggregatedRuns, arguments[0][1], arguments[0][2]);\n dtd.resolve(aggregatedRuns, arguments[0][1], arguments[0][2]);\n }\n } else {\n // is variables API\n // aggregate the response\n var aggregatedVariables = {};\n $.each(arguments, function (idx, args) {\n var vars = args[0];\n $.extend(true, aggregatedVariables, vars);\n });\n oldSuccess(aggregatedVariables, arguments[0][1], arguments[0][2]);\n dtd.resolve(aggregatedVariables, arguments[0][1], arguments[0][2]);\n }\n }, function () {\n oldError.apply(http, arguments);\n dtd.reject.apply(dtd, arguments);\n });\n return dtd.promise();\n } else {\n return http.get(params, options);\n }\n };\n }\n };\n}());\n"]} \ No newline at end of file