diff --git a/.gitignore b/.gitignore index fa5e5267..fd562eac 100644 --- a/.gitignore +++ b/.gitignore @@ -49,3 +49,5 @@ dist/epicenter-edge-instrumented.js coverage/ .DS_Store **/.DS_Store + +*.orig diff --git a/dist/epicenter.js b/dist/epicenter.js index 4219538d..a8167a42 100644 --- a/dist/epicenter.js +++ b/dist/epicenter.js @@ -2007,7 +2007,7 @@ module.exports = shouldUseNative() ? Object.assign : function (target, source) { },{}],6:[function(require,module,exports){ module.exports={ - "version": "" + "version": "v2" } },{}],7:[function(require,module,exports){ @@ -2082,7 +2082,11 @@ module.exports = F; }).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) +<<<<<<< HEAD },{"./api-version.json":6,"./env-load":8,"./managers/auth-manager":9,"./managers/epicenter-channel-manager":11,"./managers/run-manager":13,"./managers/run-strategies/always-new-strategy":14,"./managers/run-strategies/conditional-creation-strategy":15,"./managers/run-strategies/identity-strategy":16,"./managers/run-strategies/new-if-initialized-strategy":18,"./managers/run-strategies/new-if-missing-strategy":19,"./managers/run-strategies/new-if-persisted-strategy":20,"./managers/scenario-manager":23,"./managers/world-manager":25,"./service/admin-file-service":26,"./service/asset-api-adapter":27,"./service/auth-api-service":28,"./service/channel-service":29,"./service/configuration-service":30,"./service/data-api-service":31,"./service/group-api-service":32,"./service/member-api-adapter":33,"./service/run-api-service":34,"./service/state-api-adapter":36,"./service/url-config-service":37,"./service/user-api-adapter":38,"./service/variables-api-service":39,"./service/world-api-adapter":40,"./store/cookie-store":41,"./store/store-factory":43,"./transport/ajax-http-transport":44,"./transport/http-transport-factory":45,"./util/inherit":46,"./util/make-sequence":47,"./util/query-util":50,"./util/run-util":51}],8:[function(require,module,exports){ +======= +},{"./api-version.json":5,"./env-load":7,"./managers/auth-manager":8,"./managers/epicenter-channel-manager":10,"./managers/run-manager":12,"./managers/run-strategies/always-new-strategy":13,"./managers/run-strategies/conditional-creation-strategy":14,"./managers/run-strategies/identity-strategy":15,"./managers/run-strategies/new-if-initialized-strategy":17,"./managers/run-strategies/new-if-missing-strategy":18,"./managers/run-strategies/new-if-persisted-strategy":19,"./managers/scenario-manager":22,"./managers/world-manager":24,"./service/admin-file-service":25,"./service/asset-api-adapter":26,"./service/auth-api-service":27,"./service/channel-service":28,"./service/configuration-service":29,"./service/data-api-service":30,"./service/member-api-adapter":32,"./service/run-api-service":33,"./service/state-api-adapter":34,"./service/url-config-service":35,"./service/user-api-adapter":36,"./service/variables-api-service":37,"./service/world-api-adapter":38,"./store/cookie-store":39,"./store/store-factory":41,"./transport/ajax-http-transport":42,"./transport/http-transport-factory":43,"./util/inherit":44,"./util/make-sequence":45,"./util/query-util":48,"./util/run-util":49}],7:[function(require,module,exports){ +>>>>>>> dms3-version 'use strict'; var urlConfigService = require('./service/url-config-service'); @@ -2112,7 +2116,11 @@ var envLoad = function (callback) { module.exports = envLoad; +<<<<<<< HEAD },{"./service/url-config-service":37}],9:[function(require,module,exports){ +======= +},{"./service/url-config-service":35}],8:[function(require,module,exports){ +>>>>>>> dms3-version /** * ## Authorization Manager * @@ -2501,7 +2509,11 @@ AuthManager.prototype = $.extend(AuthManager.prototype, { module.exports = AuthManager; +<<<<<<< HEAD },{"../service/auth-api-service":28,"../service/group-api-service":32,"../service/member-api-adapter":33,"../store/session-manager":42,"../util/object-util":48,"buffer":2,"object-assign":5}],10:[function(require,module,exports){ +======= +},{"../service/auth-api-service":27,"../service/member-api-adapter":32,"../store/session-manager":40,"../util/object-util":46,"buffer":2}],9:[function(require,module,exports){ +>>>>>>> dms3-version 'use strict'; var Channel = require('../service/channel-service'); @@ -2747,7 +2759,11 @@ ChannelManager.prototype = $.extend(ChannelManager.prototype, { module.exports = ChannelManager; +<<<<<<< HEAD },{"../service/channel-service":29,"../store/session-manager":42}],11:[function(require,module,exports){ +======= +},{"../service/channel-service":28,"../store/session-manager":40}],10:[function(require,module,exports){ +>>>>>>> dms3-version 'use strict'; /** @@ -3130,7 +3146,11 @@ var EpicenterChannelManager = classFrom(ChannelManager, { module.exports = EpicenterChannelManager; +<<<<<<< HEAD },{"../service/url-config-service":37,"../store/session-manager":42,"../util/inherit":46,"./auth-manager":9,"./channel-manager":10}],12:[function(require,module,exports){ +======= +},{"../service/url-config-service":35,"../store/session-manager":40,"../util/inherit":44,"./auth-manager":8,"./channel-manager":9}],11:[function(require,module,exports){ +>>>>>>> dms3-version 'use strict'; module.exports = { @@ -3294,7 +3314,11 @@ RunManager.prototype = { module.exports = RunManager; +<<<<<<< HEAD },{"../service/run-api-service":34,"./run-strategies/strategies-map":22,"./special-operations":24}],14:[function(require,module,exports){ +======= +},{"../service/run-api-service":33,"./run-strategies/strategies-map":21,"./special-operations":23}],13:[function(require,module,exports){ +>>>>>>> dms3-version 'use strict'; var classFrom = require('../../util/inherit'); @@ -3315,7 +3339,11 @@ var Strategy = classFrom(ConditionalStrategy, { module.exports = Strategy; +<<<<<<< HEAD },{"../../util/inherit":46,"./conditional-creation-strategy":15}],15:[function(require,module,exports){ +======= +},{"../../util/inherit":44,"./conditional-creation-strategy":14}],14:[function(require,module,exports){ +>>>>>>> dms3-version 'use strict'; var makeSeq = require('../../util/make-sequence'); @@ -3422,7 +3450,11 @@ var Strategy = classFrom(Base, { module.exports = Strategy; +<<<<<<< HEAD },{"../../store/session-manager":42,"../../util/inherit":46,"../../util/make-sequence":47,"../auth-manager":9,"../key-names":12,"./identity-strategy":16}],16:[function(require,module,exports){ +======= +},{"../../service/url-config-service":35,"../../store/store-factory":41,"../../util/inherit":44,"../../util/make-sequence":45,"../auth-manager":8,"../key-names":11,"./identity-strategy":15}],15:[function(require,module,exports){ +>>>>>>> dms3-version 'use strict'; var classFrom = require('../../util/inherit'); @@ -3445,7 +3477,11 @@ module.exports = classFrom(Base, { } }); +<<<<<<< HEAD },{"../../util/inherit":46}],17:[function(require,module,exports){ +======= +},{"../../util/inherit":44}],16:[function(require,module,exports){ +>>>>>>> dms3-version 'use strict'; var classFrom = require('../../util/inherit'); @@ -3526,7 +3562,11 @@ var Strategy = classFrom(IdentityStrategy, { module.exports = Strategy; +<<<<<<< HEAD },{"../../service/world-api-adapter":40,"../../util/inherit":46,"../auth-manager":9,"./identity-strategy":16}],18:[function(require,module,exports){ +======= +},{"../../service/world-api-adapter":38,"../../util/inherit":44,"../auth-manager":8,"./identity-strategy":15}],17:[function(require,module,exports){ +>>>>>>> dms3-version 'use strict'; var classFrom = require('../../util/inherit'); var ConditionalStrategy = require('./conditional-creation-strategy'); @@ -3545,7 +3585,11 @@ var Strategy = classFrom(ConditionalStrategy, { module.exports = Strategy; +<<<<<<< HEAD },{"../../util/inherit":46,"./conditional-creation-strategy":15}],19:[function(require,module,exports){ +======= +},{"../../util/inherit":44,"./conditional-creation-strategy":14}],18:[function(require,module,exports){ +>>>>>>> dms3-version 'use strict'; var classFrom = require('../../util/inherit'); @@ -3570,7 +3614,11 @@ var Strategy = classFrom(ConditionalStrategy, { module.exports = Strategy; +<<<<<<< HEAD },{"../../util/inherit":46,"./conditional-creation-strategy":15}],20:[function(require,module,exports){ +======= +},{"../../util/inherit":44,"./conditional-creation-strategy":14}],19:[function(require,module,exports){ +>>>>>>> dms3-version 'use strict'; var classFrom = require('../../util/inherit'); var ConditionalStrategy = require('./conditional-creation-strategy'); @@ -3589,7 +3637,11 @@ var Strategy = classFrom(ConditionalStrategy, { module.exports = Strategy; +<<<<<<< HEAD },{"../../util/inherit":46,"./conditional-creation-strategy":15}],21:[function(require,module,exports){ +======= +},{"../../util/inherit":44,"./conditional-creation-strategy":14}],20:[function(require,module,exports){ +>>>>>>> dms3-version 'use strict'; var classFrom = require('../../util/inherit'); @@ -3683,7 +3735,11 @@ var Strategy = classFrom(IdentityStrategy, { module.exports = Strategy; +<<<<<<< HEAD },{"../../service/state-api-adapter":36,"../../store/store-factory":43,"../../util/inherit":46,"../auth-manager":9,"../key-names":12,"./identity-strategy":16}],22:[function(require,module,exports){ +======= +},{"../../service/state-api-adapter":34,"../../store/store-factory":41,"../../util/inherit":44,"../auth-manager":8,"../key-names":11,"./identity-strategy":15}],21:[function(require,module,exports){ +>>>>>>> dms3-version module.exports = { 'new-if-initialized': require('./new-if-initialized-strategy'), 'new-if-persisted': require('./new-if-persisted-strategy'), @@ -3745,7 +3801,11 @@ ScenarioManager.prototype = { module.exports = ScenarioManager; +<<<<<<< HEAD },{"../service/run-api-service":34}],24:[function(require,module,exports){ +======= +},{"../service/run-api-service":33}],23:[function(require,module,exports){ +>>>>>>> dms3-version 'use strict'; @@ -3926,7 +3986,11 @@ module.exports = function (options) { $.extend(this, api); }; +<<<<<<< HEAD },{"../service/world-api-adapter":40,"./auth-manager":9,"./run-manager":13}],26:[function(require,module,exports){ +======= +},{"../service/world-api-adapter":38,"./auth-manager":8,"./run-manager":12}],25:[function(require,module,exports){ +>>>>>>> dms3-version /** * ## File API Service * @@ -4071,7 +4135,11 @@ module.exports = function (config) { $.extend(this, publicAsyncAPI); }; +<<<<<<< HEAD },{"../store/session-manager":42,"../transport/http-transport-factory":45,"./configuration-service":30}],27:[function(require,module,exports){ +======= +},{"../store/session-manager":40,"../transport/http-transport-factory":43,"./configuration-service":29}],26:[function(require,module,exports){ +>>>>>>> dms3-version /** * ## Asset API Adapter * @@ -4451,7 +4519,11 @@ module.exports = function (config) { $.extend(this, publicAPI); }; +<<<<<<< HEAD },{"../store/session-manager":42,"../transport/http-transport-factory":45,"../util/object-util":48,"./configuration-service":30}],28:[function(require,module,exports){ +======= +},{"../store/session-manager":40,"../transport/http-transport-factory":43,"../util/object-util":46,"./configuration-service":29}],27:[function(require,module,exports){ +>>>>>>> dms3-version /** * * ## Authentication API Service @@ -4572,7 +4644,11 @@ module.exports = function (config) { $.extend(this, publicAPI); }; +<<<<<<< HEAD },{"../transport/http-transport-factory":45,"./configuration-service":30}],29:[function(require,module,exports){ +======= +},{"../transport/http-transport-factory":43,"./configuration-service":29}],28:[function(require,module,exports){ +>>>>>>> dms3-version 'use strict'; /** @@ -4876,7 +4952,11 @@ module.exports = function (config) { }; +<<<<<<< HEAD },{"./url-config-service":37}],31:[function(require,module,exports){ +======= +},{"./url-config-service":35}],30:[function(require,module,exports){ +>>>>>>> dms3-version /** * ## Data API Service * @@ -5137,6 +5217,7 @@ module.exports = function (config) { $.extend(this, publicAPI); }; +<<<<<<< HEAD },{"../store/session-manager":42,"../transport/http-transport-factory":45,"../util/query-util":50,"./configuration-service":30}],32:[function(require,module,exports){ /** * @@ -5148,10 +5229,32 @@ module.exports = function (config) { * * var ma = new F.service.Group({ token: 'user-or-project-access-token' }); * ma.getGroupsForProject({ account: 'acme', project: 'sample' }); +======= +},{"../store/session-manager":40,"../transport/http-transport-factory":43,"../util/query-util":48,"./configuration-service":29}],31:[function(require,module,exports){ +/** + * + * ## Introspection API Service + * + * Used in conjunction with the [Run API Service](../run-api-service/) to access Native DMS 3 Introspection calls + * + * var rm = new F.manager.RunManager({ + * run: { + * account: 'acme-simulations', + * project: 'supply-chain-game', + * model: 'supply-chain-model.jl' + * } + * }); + * rm.getRun() + * .then(function() { + * var is = rm.run.introspection(); + * }); + * +>>>>>>> dms3-version */ 'use strict'; +<<<<<<< HEAD var serviceUtils = require('./service-utils'); var TransportFactory = require('../transport/http-transport-factory'); var objectAssign = require('object-assign'); @@ -5212,6 +5315,70 @@ var GroupService = function (config) { module.exports = GroupService; },{"../transport/http-transport-factory":45,"./service-utils":35,"object-assign":5}],33:[function(require,module,exports){ +======= +var ConfigService = require('./configuration-service'); +var TransportFactory = require('../transport/http-transport-factory'); + +module.exports = function (config) { + var defaults = { + server: { + versionPath: 'v3/' + } + }; + var serviceOptions = $.extend({}, defaults, config); + + var urlConfig = new ConfigService(serviceOptions).get('server'); + if (serviceOptions.account) { + urlConfig.accountPath = serviceOptions.account; + } + if (serviceOptions.project) { + urlConfig.projectPath = serviceOptions.project; + } + + urlConfig.filter = ';'; + + var httpOptions = { + url: urlConfig.getAPIPath('model') + 'publish' + }; + if (serviceOptions.token) { + httpOptions.headers = { + 'Authorization': 'Bearer ' + serviceOptions.token + }; + } + var http = new TransportFactory(httpOptions); + + var publicAPI = { + /** + * Get the available Functions and Variables + * + * **Example** + * + * vs.get() + * .then(function(data) { + * // data contains an object with available functions (used with operations API) and available variables (used with variables API) + * console.log(data.functions); + * console.log(data.variables); + * }); + * + * **Parameters** + * @param {String} `runId` (Optional) Overrides the run id used when the service was created + * @param {Object} `options` (Optional) Overrides for configuration options. + */ + get: function (runId, options) { + var httpOptions = $.extend(true, {}, serviceOptions, options); + var params = { + runId: runId || httpOptions.filter, + commandWrapper: { command: { introspect: {} } }, + reanimate: false + }; + return http.post(params, httpOptions); + } + }; + $.extend(this, publicAPI); +}; + +},{"../transport/http-transport-factory":43,"./configuration-service":29}],32:[function(require,module,exports){ +>>>>>>> dms3-version /** * * ## Member API Adapter @@ -5398,7 +5565,11 @@ module.exports = function (config) { $.extend(this, publicAPI); }; +<<<<<<< HEAD },{"../store/session-manager":42,"../transport/http-transport-factory":45,"../util/object-util":48,"./configuration-service":30}],34:[function(require,module,exports){ +======= +},{"../store/session-manager":40,"../transport/http-transport-factory":43,"../util/object-util":46,"./configuration-service":29}],33:[function(require,module,exports){ +>>>>>>> dms3-version /** * * ## Run API Service @@ -5455,6 +5626,7 @@ var rutil = require('../util/run-util'); var _pick = require('../util/object-util')._pick; var TransportFactory = require('../transport/http-transport-factory'); var VariablesService = require('./variables-api-service'); +var IntrospectionService = require('./introspection-api-service'); var SessionManager = require('../store/session-manager'); module.exports = function (config) { @@ -5895,6 +6067,11 @@ module.exports = function (config) { runService: this })); return vs; + }, + + introspection: function (config) { + var introspection = new IntrospectionService($.extend(true, {}, serviceOptions, config)); + return introspection; } }; @@ -5902,6 +6079,7 @@ module.exports = function (config) { $.extend(this, publicSyncAPI); }; +<<<<<<< HEAD },{"../store/session-manager":42,"../transport/http-transport-factory":45,"../util/object-util":48,"../util/query-util":50,"../util/run-util":51,"./configuration-service":30,"./variables-api-service":39}],35:[function(require,module,exports){ 'use strict'; @@ -5944,6 +6122,9 @@ var serviceUtils = { module.exports = serviceUtils; },{"../store/session-manager":42,"./configuration-service":30,"object-assign":5}],36:[function(require,module,exports){ +======= +},{"../store/session-manager":40,"../transport/http-transport-factory":43,"../util/object-util":46,"../util/query-util":48,"../util/run-util":49,"./configuration-service":29,"./introspection-api-service":31,"./variables-api-service":37}],34:[function(require,module,exports){ +>>>>>>> dms3-version 'use strict'; /** * ## State API Adapter @@ -6067,7 +6248,11 @@ module.exports = function (config) { $.extend(this, publicAPI); }; +<<<<<<< HEAD },{"../store/session-manager":42,"../transport/http-transport-factory":45,"../util/object-util":48,"./configuration-service":30}],37:[function(require,module,exports){ +======= +},{"../store/session-manager":40,"../transport/http-transport-factory":43,"../util/object-util":46,"./configuration-service":29}],35:[function(require,module,exports){ +>>>>>>> dms3-version 'use strict'; var epiVersion = require('../api-version.json'); @@ -6161,7 +6346,11 @@ var UrlConfigService = function (config) { module.exports = UrlConfigService; +<<<<<<< HEAD },{"../api-version.json":6}],38:[function(require,module,exports){ +======= +},{"../api-version.json":5}],36:[function(require,module,exports){ +>>>>>>> dms3-version 'use strict'; /** * ## User API Adapter @@ -6318,7 +6507,11 @@ module.exports = function (config) { +<<<<<<< HEAD },{"../store/session-manager":42,"../transport/http-transport-factory":45,"../util/query-util":50,"./configuration-service":30}],39:[function(require,module,exports){ +======= +},{"../store/session-manager":40,"../transport/http-transport-factory":43,"../util/query-util":48,"./configuration-service":29}],37:[function(require,module,exports){ +>>>>>>> dms3-version /** * * ## Variables API Service @@ -6483,7 +6676,11 @@ module.exports = function (config) { $.extend(this, publicAPI); }; +<<<<<<< HEAD },{"../transport/http-transport-factory":45,"../util/run-util":51}],40:[function(require,module,exports){ +======= +},{"../transport/http-transport-factory":43,"../util/run-util":49}],38:[function(require,module,exports){ +>>>>>>> dms3-version /** * ## World API Adapter * @@ -7232,7 +7429,11 @@ module.exports = function (config) { $.extend(this, publicAPI); }; +<<<<<<< HEAD },{"../store/session-manager":42,"../transport/http-transport-factory":45,"../util/object-util":48,"./configuration-service":30}],41:[function(require,module,exports){ +======= +},{"../store/session-manager":40,"../transport/http-transport-factory":43,"../util/object-util":46,"./configuration-service":29}],39:[function(require,module,exports){ +>>>>>>> dms3-version /** * @class Cookie Storage Service * @@ -7377,7 +7578,11 @@ module.exports = function (config) { $.extend(this, publicAPI); }; +<<<<<<< HEAD },{}],42:[function(require,module,exports){ +======= +},{}],40:[function(require,module,exports){ +>>>>>>> dms3-version 'use strict'; var keyNames = require('../managers/key-names'); @@ -7485,7 +7690,11 @@ var SessionManager = function (managerOptions) { }; module.exports = SessionManager; +<<<<<<< HEAD },{"../managers/key-names":12,"../util/option-utils":49,"./store-factory":43}],43:[function(require,module,exports){ +======= +},{"../managers/key-names":11,"../util/option-utils":47,"./store-factory":41}],41:[function(require,module,exports){ +>>>>>>> dms3-version /** Decides type of store to provide */ @@ -7497,7 +7706,11 @@ var store = require('./cookie-store'); module.exports = store; +<<<<<<< HEAD },{"./cookie-store":41}],44:[function(require,module,exports){ +======= +},{"./cookie-store":39}],42:[function(require,module,exports){ +>>>>>>> dms3-version 'use strict'; var qutils = require('../util/query-util'); @@ -7606,7 +7819,11 @@ module.exports = function (config) { return $.extend(this, publicAPI); }; +<<<<<<< HEAD },{"../util/query-util":50}],45:[function(require,module,exports){ +======= +},{"../util/query-util":48}],43:[function(require,module,exports){ +>>>>>>> dms3-version 'use strict'; // var isNode = false; FIXME: Browserify/minifyify has issues with the next link @@ -7614,7 +7831,11 @@ module.exports = function (config) { var transport = require('./ajax-http-transport'); module.exports = transport; +<<<<<<< HEAD },{"./ajax-http-transport":44}],46:[function(require,module,exports){ +======= +},{"./ajax-http-transport":42}],44:[function(require,module,exports){ +>>>>>>> dms3-version /** /* Inherit from a class (using prototype borrowing) */ @@ -7670,7 +7891,11 @@ module.exports = function (base, props, staticProps) { return child; }; +<<<<<<< HEAD },{}],47:[function(require,module,exports){ +======= +},{}],45:[function(require,module,exports){ +>>>>>>> dms3-version 'use strict'; /*jshint loopfunc:false */ @@ -7753,7 +7978,11 @@ function MakeSeq(obj) { module.exports = MakeSeq; +<<<<<<< HEAD },{}],48:[function(require,module,exports){ +======= +},{}],46:[function(require,module,exports){ +>>>>>>> dms3-version 'use strict'; module.exports = { @@ -7769,7 +7998,11 @@ module.exports = { } }; +<<<<<<< HEAD },{}],49:[function(require,module,exports){ +======= +},{}],47:[function(require,module,exports){ +>>>>>>> dms3-version 'use strict'; var ConfigService = require('../service/configuration-service'); @@ -7810,7 +8043,11 @@ var optionUtils = { }; module.exports = optionUtils; +<<<<<<< HEAD },{"../service/configuration-service":30}],50:[function(require,module,exports){ +======= +},{"../service/configuration-service":29}],48:[function(require,module,exports){ +>>>>>>> dms3-version /** * Utilities for working with query strings */ @@ -7924,7 +8161,11 @@ module.exports = (function () { +<<<<<<< HEAD },{}],51:[function(require,module,exports){ +======= +},{}],49:[function(require,module,exports){ +>>>>>>> dms3-version /** * Utilities for working with the run service */ @@ -8148,5 +8389,10 @@ module.exports = (function () { }; }()); +<<<<<<< HEAD },{"./query-util":50}]},{},[7]) //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIm5vZGVfbW9kdWxlcy9icm93c2VyLXBhY2svX3ByZWx1ZGUuanMiLCJub2RlX21vZHVsZXMvYmFzZTY0LWpzL2xpYi9iNjQuanMiLCJub2RlX21vZHVsZXMvYnVmZmVyL2luZGV4LmpzIiwibm9kZV9tb2R1bGVzL2llZWU3NTQvaW5kZXguanMiLCJub2RlX21vZHVsZXMvaXNhcnJheS9pbmRleC5qcyIsIm5vZGVfbW9kdWxlcy9vYmplY3QtYXNzaWduL2luZGV4LmpzIiwic3JjL2FwaS12ZXJzaW9uLmpzb24iLCJzcmMvYXBwLmpzIiwic3JjL2Vudi1sb2FkLmpzIiwic3JjL21hbmFnZXJzL2F1dGgtbWFuYWdlci5qcyIsInNyYy9tYW5hZ2Vycy9jaGFubmVsLW1hbmFnZXIuanMiLCJzcmMvbWFuYWdlcnMvZXBpY2VudGVyLWNoYW5uZWwtbWFuYWdlci5qcyIsInNyYy9tYW5hZ2Vycy9rZXktbmFtZXMuanMiLCJzcmMvbWFuYWdlcnMvcnVuLW1hbmFnZXIuanMiLCJzcmMvbWFuYWdlcnMvcnVuLXN0cmF0ZWdpZXMvYWx3YXlzLW5ldy1zdHJhdGVneS5qcyIsInNyYy9tYW5hZ2Vycy9ydW4tc3RyYXRlZ2llcy9jb25kaXRpb25hbC1jcmVhdGlvbi1zdHJhdGVneS5qcyIsInNyYy9tYW5hZ2Vycy9ydW4tc3RyYXRlZ2llcy9pZGVudGl0eS1zdHJhdGVneS5qcyIsInNyYy9tYW5hZ2Vycy9ydW4tc3RyYXRlZ2llcy9tdWx0aXBsYXllci1zdHJhdGVneS5qcyIsInNyYy9tYW5hZ2Vycy9ydW4tc3RyYXRlZ2llcy9uZXctaWYtaW5pdGlhbGl6ZWQtc3RyYXRlZ3kuanMiLCJzcmMvbWFuYWdlcnMvcnVuLXN0cmF0ZWdpZXMvbmV3LWlmLW1pc3Npbmctc3RyYXRlZ3kuanMiLCJzcmMvbWFuYWdlcnMvcnVuLXN0cmF0ZWdpZXMvbmV3LWlmLXBlcnNpc3RlZC1zdHJhdGVneS5qcyIsInNyYy9tYW5hZ2Vycy9ydW4tc3RyYXRlZ2llcy9wZXJzaXN0ZW50LXNpbmdsZS1wbGF5ZXItc3RyYXRlZ3kuanMiLCJzcmMvbWFuYWdlcnMvcnVuLXN0cmF0ZWdpZXMvc3RyYXRlZ2llcy1tYXAuanMiLCJzcmMvbWFuYWdlcnMvc2NlbmFyaW8tbWFuYWdlci5qcyIsInNyYy9tYW5hZ2Vycy9zcGVjaWFsLW9wZXJhdGlvbnMuanMiLCJzcmMvbWFuYWdlcnMvd29ybGQtbWFuYWdlci5qcyIsInNyYy9zZXJ2aWNlL2FkbWluLWZpbGUtc2VydmljZS5qcyIsInNyYy9zZXJ2aWNlL2Fzc2V0LWFwaS1hZGFwdGVyLmpzIiwic3JjL3NlcnZpY2UvYXV0aC1hcGktc2VydmljZS5qcyIsInNyYy9zZXJ2aWNlL2NoYW5uZWwtc2VydmljZS5qcyIsInNyYy9zZXJ2aWNlL2NvbmZpZ3VyYXRpb24tc2VydmljZS5qcyIsInNyYy9zZXJ2aWNlL2RhdGEtYXBpLXNlcnZpY2UuanMiLCJzcmMvc2VydmljZS9ncm91cC1hcGktc2VydmljZS5qcyIsInNyYy9zZXJ2aWNlL21lbWJlci1hcGktYWRhcHRlci5qcyIsInNyYy9zZXJ2aWNlL3J1bi1hcGktc2VydmljZS5qcyIsInNyYy9zZXJ2aWNlL3NlcnZpY2UtdXRpbHMuanMiLCJzcmMvc2VydmljZS9zdGF0ZS1hcGktYWRhcHRlci5qcyIsInNyYy9zZXJ2aWNlL3VybC1jb25maWctc2VydmljZS5qcyIsInNyYy9zZXJ2aWNlL3VzZXItYXBpLWFkYXB0ZXIuanMiLCJzcmMvc2VydmljZS92YXJpYWJsZXMtYXBpLXNlcnZpY2UuanMiLCJzcmMvc2VydmljZS93b3JsZC1hcGktYWRhcHRlci5qcyIsInNyYy9zdG9yZS9jb29raWUtc3RvcmUuanMiLCJzcmMvc3RvcmUvc2Vzc2lvbi1tYW5hZ2VyLmpzIiwic3JjL3N0b3JlL3N0b3JlLWZhY3RvcnkuanMiLCJzcmMvdHJhbnNwb3J0L2FqYXgtaHR0cC10cmFuc3BvcnQuanMiLCJzcmMvdHJhbnNwb3J0L2h0dHAtdHJhbnNwb3J0LWZhY3RvcnkuanMiLCJzcmMvdXRpbC9pbmhlcml0LmpzIiwic3JjL3V0aWwvbWFrZS1zZXF1ZW5jZS5qcyIsInNyYy91dGlsL29iamVjdC11dGlsLmpzIiwic3JjL3V0aWwvb3B0aW9uLXV0aWxzLmpzIiwic3JjL3V0aWwvcXVlcnktdXRpbC5qcyIsInNyYy91dGlsL3J1bi11dGlsLmpzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBO0FDQUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7O0FDN0dBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOzs7O0FDanJEQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNwRkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ0xBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNuRkE7QUFDQTtBQUNBO0FBQ0E7OztBQ0hBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7Ozs7QUNuRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUM1QkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDbllBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDcFBBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzdYQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDTEE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzNKQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ25CQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUN6R0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDckJBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDL0VBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNqQkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3ZCQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDakJBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUM1RkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDVEE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNqREE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ1JBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDektBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUMvSUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDMVhBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUN2SEE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDcE9BO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3hFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ25RQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUN4RUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3pMQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3RmQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUN2Q0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzFIQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDNUZBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUMzSkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNuS0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDM3VCQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDL0lBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDMUdBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDVkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzNHQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNOQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUN0REE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDakZBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNkQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUN2Q0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNoSEE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EiLCJmaWxlIjoiZ2VuZXJhdGVkLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXNDb250ZW50IjpbIihmdW5jdGlvbiBlKHQsbixyKXtmdW5jdGlvbiBzKG8sdSl7aWYoIW5bb10pe2lmKCF0W29dKXt2YXIgYT10eXBlb2YgcmVxdWlyZT09XCJmdW5jdGlvblwiJiZyZXF1aXJlO2lmKCF1JiZhKXJldHVybiBhKG8sITApO2lmKGkpcmV0dXJuIGkobywhMCk7dmFyIGY9bmV3IEVycm9yKFwiQ2Fubm90IGZpbmQgbW9kdWxlICdcIitvK1wiJ1wiKTt0aHJvdyBmLmNvZGU9XCJNT0RVTEVfTk9UX0ZPVU5EXCIsZn12YXIgbD1uW29dPXtleHBvcnRzOnt9fTt0W29dWzBdLmNhbGwobC5leHBvcnRzLGZ1bmN0aW9uKGUpe3ZhciBuPXRbb11bMV1bZV07cmV0dXJuIHMobj9uOmUpfSxsLGwuZXhwb3J0cyxlLHQsbixyKX1yZXR1cm4gbltvXS5leHBvcnRzfXZhciBpPXR5cGVvZiByZXF1aXJlPT1cImZ1bmN0aW9uXCImJnJlcXVpcmU7Zm9yKHZhciBvPTA7bzxyLmxlbmd0aDtvKyspcyhyW29dKTtyZXR1cm4gc30pIiwiJ3VzZSBzdHJpY3QnXG5cbmV4cG9ydHMudG9CeXRlQXJyYXkgPSB0b0J5dGVBcnJheVxuZXhwb3J0cy5mcm9tQnl0ZUFycmF5ID0gZnJvbUJ5dGVBcnJheVxuXG52YXIgbG9va3VwID0gW11cbnZhciByZXZMb29rdXAgPSBbXVxudmFyIEFyciA9IHR5cGVvZiBVaW50OEFycmF5ICE9PSAndW5kZWZpbmVkJyA/IFVpbnQ4QXJyYXkgOiBBcnJheVxuXG5mdW5jdGlvbiBpbml0ICgpIHtcbiAgdmFyIGNvZGUgPSAnQUJDREVGR0hJSktMTU5PUFFSU1RVVldYWVphYmNkZWZnaGlqa2xtbm9wcXJzdHV2d3h5ejAxMjM0NTY3ODkrLydcbiAgZm9yICh2YXIgaSA9IDAsIGxlbiA9IGNvZGUubGVuZ3RoOyBpIDwgbGVuOyArK2kpIHtcbiAgICBsb29rdXBbaV0gPSBjb2RlW2ldXG4gICAgcmV2TG9va3VwW2NvZGUuY2hhckNvZGVBdChpKV0gPSBpXG4gIH1cblxuICByZXZMb29rdXBbJy0nLmNoYXJDb2RlQXQoMCldID0gNjJcbiAgcmV2TG9va3VwWydfJy5jaGFyQ29kZUF0KDApXSA9IDYzXG59XG5cbmluaXQoKVxuXG5mdW5jdGlvbiB0b0J5dGVBcnJheSAoYjY0KSB7XG4gIHZhciBpLCBqLCBsLCB0bXAsIHBsYWNlSG9sZGVycywgYXJyXG4gIHZhciBsZW4gPSBiNjQubGVuZ3RoXG5cbiAgaWYgKGxlbiAlIDQgPiAwKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKCdJbnZhbGlkIHN0cmluZy4gTGVuZ3RoIG11c3QgYmUgYSBtdWx0aXBsZSBvZiA0JylcbiAgfVxuXG4gIC8vIHRoZSBudW1iZXIgb2YgZXF1YWwgc2lnbnMgKHBsYWNlIGhvbGRlcnMpXG4gIC8vIGlmIHRoZXJlIGFyZSB0d28gcGxhY2Vob2xkZXJzLCB0aGFuIHRoZSB0d28gY2hhcmFjdGVycyBiZWZvcmUgaXRcbiAgLy8gcmVwcmVzZW50IG9uZSBieXRlXG4gIC8vIGlmIHRoZXJlIGlzIG9ubHkgb25lLCB0aGVuIHRoZSB0aHJlZSBjaGFyYWN0ZXJzIGJlZm9yZSBpdCByZXByZXNlbnQgMiBieXRlc1xuICAvLyB0aGlzIGlzIGp1c3QgYSBjaGVhcCBoYWNrIHRvIG5vdCBkbyBpbmRleE9mIHR3aWNlXG4gIHBsYWNlSG9sZGVycyA9IGI2NFtsZW4gLSAyXSA9PT0gJz0nID8gMiA6IGI2NFtsZW4gLSAxXSA9PT0gJz0nID8gMSA6IDBcblxuICAvLyBiYXNlNjQgaXMgNC8zICsgdXAgdG8gdHdvIGNoYXJhY3RlcnMgb2YgdGhlIG9yaWdpbmFsIGRhdGFcbiAgYXJyID0gbmV3IEFycihsZW4gKiAzIC8gNCAtIHBsYWNlSG9sZGVycylcblxuICAvLyBpZiB0aGVyZSBhcmUgcGxhY2Vob2xkZXJzLCBvbmx5IGdldCB1cCB0byB0aGUgbGFzdCBjb21wbGV0ZSA0IGNoYXJzXG4gIGwgPSBwbGFjZUhvbGRlcnMgPiAwID8gbGVuIC0gNCA6IGxlblxuXG4gIHZhciBMID0gMFxuXG4gIGZvciAoaSA9IDAsIGogPSAwOyBpIDwgbDsgaSArPSA0LCBqICs9IDMpIHtcbiAgICB0bXAgPSAocmV2TG9va3VwW2I2NC5jaGFyQ29kZUF0KGkpXSA8PCAxOCkgfCAocmV2TG9va3VwW2I2NC5jaGFyQ29kZUF0KGkgKyAxKV0gPDwgMTIpIHwgKHJldkxvb2t1cFtiNjQuY2hhckNvZGVBdChpICsgMildIDw8IDYpIHwgcmV2TG9va3VwW2I2NC5jaGFyQ29kZUF0KGkgKyAzKV1cbiAgICBhcnJbTCsrXSA9ICh0bXAgPj4gMTYpICYgMHhGRlxuICAgIGFycltMKytdID0gKHRtcCA+PiA4KSAmIDB4RkZcbiAgICBhcnJbTCsrXSA9IHRtcCAmIDB4RkZcbiAgfVxuXG4gIGlmIChwbGFjZUhvbGRlcnMgPT09IDIpIHtcbiAgICB0bXAgPSAocmV2TG9va3VwW2I2NC5jaGFyQ29kZUF0KGkpXSA8PCAyKSB8IChyZXZMb29rdXBbYjY0LmNoYXJDb2RlQXQoaSArIDEpXSA+PiA0KVxuICAgIGFycltMKytdID0gdG1wICYgMHhGRlxuICB9IGVsc2UgaWYgKHBsYWNlSG9sZGVycyA9PT0gMSkge1xuICAgIHRtcCA9IChyZXZMb29rdXBbYjY0LmNoYXJDb2RlQXQoaSldIDw8IDEwKSB8IChyZXZMb29rdXBbYjY0LmNoYXJDb2RlQXQoaSArIDEpXSA8PCA0KSB8IChyZXZMb29rdXBbYjY0LmNoYXJDb2RlQXQoaSArIDIpXSA+PiAyKVxuICAgIGFycltMKytdID0gKHRtcCA+PiA4KSAmIDB4RkZcbiAgICBhcnJbTCsrXSA9IHRtcCAmIDB4RkZcbiAgfVxuXG4gIHJldHVybiBhcnJcbn1cblxuZnVuY3Rpb24gdHJpcGxldFRvQmFzZTY0IChudW0pIHtcbiAgcmV0dXJuIGxvb2t1cFtudW0gPj4gMTggJiAweDNGXSArIGxvb2t1cFtudW0gPj4gMTIgJiAweDNGXSArIGxvb2t1cFtudW0gPj4gNiAmIDB4M0ZdICsgbG9va3VwW251bSAmIDB4M0ZdXG59XG5cbmZ1bmN0aW9uIGVuY29kZUNodW5rICh1aW50OCwgc3RhcnQsIGVuZCkge1xuICB2YXIgdG1wXG4gIHZhciBvdXRwdXQgPSBbXVxuICBmb3IgKHZhciBpID0gc3RhcnQ7IGkgPCBlbmQ7IGkgKz0gMykge1xuICAgIHRtcCA9ICh1aW50OFtpXSA8PCAxNikgKyAodWludDhbaSArIDFdIDw8IDgpICsgKHVpbnQ4W2kgKyAyXSlcbiAgICBvdXRwdXQucHVzaCh0cmlwbGV0VG9CYXNlNjQodG1wKSlcbiAgfVxuICByZXR1cm4gb3V0cHV0LmpvaW4oJycpXG59XG5cbmZ1bmN0aW9uIGZyb21CeXRlQXJyYXkgKHVpbnQ4KSB7XG4gIHZhciB0bXBcbiAgdmFyIGxlbiA9IHVpbnQ4Lmxlbmd0aFxuICB2YXIgZXh0cmFCeXRlcyA9IGxlbiAlIDMgLy8gaWYgd2UgaGF2ZSAxIGJ5dGUgbGVmdCwgcGFkIDIgYnl0ZXNcbiAgdmFyIG91dHB1dCA9ICcnXG4gIHZhciBwYXJ0cyA9IFtdXG4gIHZhciBtYXhDaHVua0xlbmd0aCA9IDE2MzgzIC8vIG11c3QgYmUgbXVsdGlwbGUgb2YgM1xuXG4gIC8vIGdvIHRocm91Z2ggdGhlIGFycmF5IGV2ZXJ5IHRocmVlIGJ5dGVzLCB3ZSdsbCBkZWFsIHdpdGggdHJhaWxpbmcgc3R1ZmYgbGF0ZXJcbiAgZm9yICh2YXIgaSA9IDAsIGxlbjIgPSBsZW4gLSBleHRyYUJ5dGVzOyBpIDwgbGVuMjsgaSArPSBtYXhDaHVua0xlbmd0aCkge1xuICAgIHBhcnRzLnB1c2goZW5jb2RlQ2h1bmsodWludDgsIGksIChpICsgbWF4Q2h1bmtMZW5ndGgpID4gbGVuMiA/IGxlbjIgOiAoaSArIG1heENodW5rTGVuZ3RoKSkpXG4gIH1cblxuICAvLyBwYWQgdGhlIGVuZCB3aXRoIHplcm9zLCBidXQgbWFrZSBzdXJlIHRvIG5vdCBmb3JnZXQgdGhlIGV4dHJhIGJ5dGVzXG4gIGlmIChleHRyYUJ5dGVzID09PSAxKSB7XG4gICAgdG1wID0gdWludDhbbGVuIC0gMV1cbiAgICBvdXRwdXQgKz0gbG9va3VwW3RtcCA+PiAyXVxuICAgIG91dHB1dCArPSBsb29rdXBbKHRtcCA8PCA0KSAmIDB4M0ZdXG4gICAgb3V0cHV0ICs9ICc9PSdcbiAgfSBlbHNlIGlmIChleHRyYUJ5dGVzID09PSAyKSB7XG4gICAgdG1wID0gKHVpbnQ4W2xlbiAtIDJdIDw8IDgpICsgKHVpbnQ4W2xlbiAtIDFdKVxuICAgIG91dHB1dCArPSBsb29rdXBbdG1wID4+IDEwXVxuICAgIG91dHB1dCArPSBsb29rdXBbKHRtcCA+PiA0KSAmIDB4M0ZdXG4gICAgb3V0cHV0ICs9IGxvb2t1cFsodG1wIDw8IDIpICYgMHgzRl1cbiAgICBvdXRwdXQgKz0gJz0nXG4gIH1cblxuICBwYXJ0cy5wdXNoKG91dHB1dClcblxuICByZXR1cm4gcGFydHMuam9pbignJylcbn1cbiIsIi8qIVxuICogVGhlIGJ1ZmZlciBtb2R1bGUgZnJvbSBub2RlLmpzLCBmb3IgdGhlIGJyb3dzZXIuXG4gKlxuICogQGF1dGhvciAgIEZlcm9zcyBBYm91a2hhZGlqZWggPGZlcm9zc0BmZXJvc3Mub3JnPiA8aHR0cDovL2Zlcm9zcy5vcmc+XG4gKiBAbGljZW5zZSAgTUlUXG4gKi9cbi8qIGVzbGludC1kaXNhYmxlIG5vLXByb3RvICovXG5cbid1c2Ugc3RyaWN0J1xuXG52YXIgYmFzZTY0ID0gcmVxdWlyZSgnYmFzZTY0LWpzJylcbnZhciBpZWVlNzU0ID0gcmVxdWlyZSgnaWVlZTc1NCcpXG52YXIgaXNBcnJheSA9IHJlcXVpcmUoJ2lzYXJyYXknKVxuXG5leHBvcnRzLkJ1ZmZlciA9IEJ1ZmZlclxuZXhwb3J0cy5TbG93QnVmZmVyID0gU2xvd0J1ZmZlclxuZXhwb3J0cy5JTlNQRUNUX01BWF9CWVRFUyA9IDUwXG5cbi8qKlxuICogSWYgYEJ1ZmZlci5UWVBFRF9BUlJBWV9TVVBQT1JUYDpcbiAqICAgPT09IHRydWUgICAgVXNlIFVpbnQ4QXJyYXkgaW1wbGVtZW50YXRpb24gKGZhc3Rlc3QpXG4gKiAgID09PSBmYWxzZSAgIFVzZSBPYmplY3QgaW1wbGVtZW50YXRpb24gKG1vc3QgY29tcGF0aWJsZSwgZXZlbiBJRTYpXG4gKlxuICogQnJvd3NlcnMgdGhhdCBzdXBwb3J0IHR5cGVkIGFycmF5cyBhcmUgSUUgMTArLCBGaXJlZm94IDQrLCBDaHJvbWUgNyssIFNhZmFyaSA1LjErLFxuICogT3BlcmEgMTEuNissIGlPUyA0LjIrLlxuICpcbiAqIER1ZSB0byB2YXJpb3VzIGJyb3dzZXIgYnVncywgc29tZXRpbWVzIHRoZSBPYmplY3QgaW1wbGVtZW50YXRpb24gd2lsbCBiZSB1c2VkIGV2ZW5cbiAqIHdoZW4gdGhlIGJyb3dzZXIgc3VwcG9ydHMgdHlwZWQgYXJyYXlzLlxuICpcbiAqIE5vdGU6XG4gKlxuICogICAtIEZpcmVmb3ggNC0yOSBsYWNrcyBzdXBwb3J0IGZvciBhZGRpbmcgbmV3IHByb3BlcnRpZXMgdG8gYFVpbnQ4QXJyYXlgIGluc3RhbmNlcyxcbiAqICAgICBTZWU6IGh0dHBzOi8vYnVnemlsbGEubW96aWxsYS5vcmcvc2hvd19idWcuY2dpP2lkPTY5NTQzOC5cbiAqXG4gKiAgIC0gQ2hyb21lIDktMTAgaXMgbWlzc2luZyB0aGUgYFR5cGVkQXJyYXkucHJvdG90eXBlLnN1YmFycmF5YCBmdW5jdGlvbi5cbiAqXG4gKiAgIC0gSUUxMCBoYXMgYSBicm9rZW4gYFR5cGVkQXJyYXkucHJvdG90eXBlLnN1YmFycmF5YCBmdW5jdGlvbiB3aGljaCByZXR1cm5zIGFycmF5cyBvZlxuICogICAgIGluY29ycmVjdCBsZW5ndGggaW4gc29tZSBzaXR1YXRpb25zLlxuXG4gKiBXZSBkZXRlY3QgdGhlc2UgYnVnZ3kgYnJvd3NlcnMgYW5kIHNldCBgQnVmZmVyLlRZUEVEX0FSUkFZX1NVUFBPUlRgIHRvIGBmYWxzZWAgc28gdGhleVxuICogZ2V0IHRoZSBPYmplY3QgaW1wbGVtZW50YXRpb24sIHdoaWNoIGlzIHNsb3dlciBidXQgYmVoYXZlcyBjb3JyZWN0bHkuXG4gKi9cbkJ1ZmZlci5UWVBFRF9BUlJBWV9TVVBQT1JUID0gZ2xvYmFsLlRZUEVEX0FSUkFZX1NVUFBPUlQgIT09IHVuZGVmaW5lZFxuICA/IGdsb2JhbC5UWVBFRF9BUlJBWV9TVVBQT1JUXG4gIDogdHlwZWRBcnJheVN1cHBvcnQoKVxuXG4vKlxuICogRXhwb3J0IGtNYXhMZW5ndGggYWZ0ZXIgdHlwZWQgYXJyYXkgc3VwcG9ydCBpcyBkZXRlcm1pbmVkLlxuICovXG5leHBvcnRzLmtNYXhMZW5ndGggPSBrTWF4TGVuZ3RoKClcblxuZnVuY3Rpb24gdHlwZWRBcnJheVN1cHBvcnQgKCkge1xuICB0cnkge1xuICAgIHZhciBhcnIgPSBuZXcgVWludDhBcnJheSgxKVxuICAgIGFyci5fX3Byb3RvX18gPSB7X19wcm90b19fOiBVaW50OEFycmF5LnByb3RvdHlwZSwgZm9vOiBmdW5jdGlvbiAoKSB7IHJldHVybiA0MiB9fVxuICAgIHJldHVybiBhcnIuZm9vKCkgPT09IDQyICYmIC8vIHR5cGVkIGFycmF5IGluc3RhbmNlcyBjYW4gYmUgYXVnbWVudGVkXG4gICAgICAgIHR5cGVvZiBhcnIuc3ViYXJyYXkgPT09ICdmdW5jdGlvbicgJiYgLy8gY2hyb21lIDktMTAgbGFjayBgc3ViYXJyYXlgXG4gICAgICAgIGFyci5zdWJhcnJheSgxLCAxKS5ieXRlTGVuZ3RoID09PSAwIC8vIGllMTAgaGFzIGJyb2tlbiBgc3ViYXJyYXlgXG4gIH0gY2F0Y2ggKGUpIHtcbiAgICByZXR1cm4gZmFsc2VcbiAgfVxufVxuXG5mdW5jdGlvbiBrTWF4TGVuZ3RoICgpIHtcbiAgcmV0dXJuIEJ1ZmZlci5UWVBFRF9BUlJBWV9TVVBQT1JUXG4gICAgPyAweDdmZmZmZmZmXG4gICAgOiAweDNmZmZmZmZmXG59XG5cbmZ1bmN0aW9uIGNyZWF0ZUJ1ZmZlciAodGhhdCwgbGVuZ3RoKSB7XG4gIGlmIChrTWF4TGVuZ3RoKCkgPCBsZW5ndGgpIHtcbiAgICB0aHJvdyBuZXcgUmFuZ2VFcnJvcignSW52YWxpZCB0eXBlZCBhcnJheSBsZW5ndGgnKVxuICB9XG4gIGlmIChCdWZmZXIuVFlQRURfQVJSQVlfU1VQUE9SVCkge1xuICAgIC8vIFJldHVybiBhbiBhdWdtZW50ZWQgYFVpbnQ4QXJyYXlgIGluc3RhbmNlLCBmb3IgYmVzdCBwZXJmb3JtYW5jZVxuICAgIHRoYXQgPSBuZXcgVWludDhBcnJheShsZW5ndGgpXG4gICAgdGhhdC5fX3Byb3RvX18gPSBCdWZmZXIucHJvdG90eXBlXG4gIH0gZWxzZSB7XG4gICAgLy8gRmFsbGJhY2s6IFJldHVybiBhbiBvYmplY3QgaW5zdGFuY2Ugb2YgdGhlIEJ1ZmZlciBjbGFzc1xuICAgIGlmICh0aGF0ID09PSBudWxsKSB7XG4gICAgICB0aGF0ID0gbmV3IEJ1ZmZlcihsZW5ndGgpXG4gICAgfVxuICAgIHRoYXQubGVuZ3RoID0gbGVuZ3RoXG4gIH1cblxuICByZXR1cm4gdGhhdFxufVxuXG4vKipcbiAqIFRoZSBCdWZmZXIgY29uc3RydWN0b3IgcmV0dXJucyBpbnN0YW5jZXMgb2YgYFVpbnQ4QXJyYXlgIHRoYXQgaGF2ZSB0aGVpclxuICogcHJvdG90eXBlIGNoYW5nZWQgdG8gYEJ1ZmZlci5wcm90b3R5cGVgLiBGdXJ0aGVybW9yZSwgYEJ1ZmZlcmAgaXMgYSBzdWJjbGFzcyBvZlxuICogYFVpbnQ4QXJyYXlgLCBzbyB0aGUgcmV0dXJuZWQgaW5zdGFuY2VzIHdpbGwgaGF2ZSBhbGwgdGhlIG5vZGUgYEJ1ZmZlcmAgbWV0aG9kc1xuICogYW5kIHRoZSBgVWludDhBcnJheWAgbWV0aG9kcy4gU3F1YXJlIGJyYWNrZXQgbm90YXRpb24gd29ya3MgYXMgZXhwZWN0ZWQgLS0gaXRcbiAqIHJldHVybnMgYSBzaW5nbGUgb2N0ZXQuXG4gKlxuICogVGhlIGBVaW50OEFycmF5YCBwcm90b3R5cGUgcmVtYWlucyB1bm1vZGlmaWVkLlxuICovXG5cbmZ1bmN0aW9uIEJ1ZmZlciAoYXJnLCBlbmNvZGluZ09yT2Zmc2V0LCBsZW5ndGgpIHtcbiAgaWYgKCFCdWZmZXIuVFlQRURfQVJSQVlfU1VQUE9SVCAmJiAhKHRoaXMgaW5zdGFuY2VvZiBCdWZmZXIpKSB7XG4gICAgcmV0dXJuIG5ldyBCdWZmZXIoYXJnLCBlbmNvZGluZ09yT2Zmc2V0LCBsZW5ndGgpXG4gIH1cblxuICAvLyBDb21tb24gY2FzZS5cbiAgaWYgKHR5cGVvZiBhcmcgPT09ICdudW1iZXInKSB7XG4gICAgaWYgKHR5cGVvZiBlbmNvZGluZ09yT2Zmc2V0ID09PSAnc3RyaW5nJykge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKFxuICAgICAgICAnSWYgZW5jb2RpbmcgaXMgc3BlY2lmaWVkIHRoZW4gdGhlIGZpcnN0IGFyZ3VtZW50IG11c3QgYmUgYSBzdHJpbmcnXG4gICAgICApXG4gICAgfVxuICAgIHJldHVybiBhbGxvY1Vuc2FmZSh0aGlzLCBhcmcpXG4gIH1cbiAgcmV0dXJuIGZyb20odGhpcywgYXJnLCBlbmNvZGluZ09yT2Zmc2V0LCBsZW5ndGgpXG59XG5cbkJ1ZmZlci5wb29sU2l6ZSA9IDgxOTIgLy8gbm90IHVzZWQgYnkgdGhpcyBpbXBsZW1lbnRhdGlvblxuXG4vLyBUT0RPOiBMZWdhY3ksIG5vdCBuZWVkZWQgYW55bW9yZS4gUmVtb3ZlIGluIG5leHQgbWFqb3IgdmVyc2lvbi5cbkJ1ZmZlci5fYXVnbWVudCA9IGZ1bmN0aW9uIChhcnIpIHtcbiAgYXJyLl9fcHJvdG9fXyA9IEJ1ZmZlci5wcm90b3R5cGVcbiAgcmV0dXJuIGFyclxufVxuXG5mdW5jdGlvbiBmcm9tICh0aGF0LCB2YWx1ZSwgZW5jb2RpbmdPck9mZnNldCwgbGVuZ3RoKSB7XG4gIGlmICh0eXBlb2YgdmFsdWUgPT09ICdudW1iZXInKSB7XG4gICAgdGhyb3cgbmV3IFR5cGVFcnJvcignXCJ2YWx1ZVwiIGFyZ3VtZW50IG11c3Qgbm90IGJlIGEgbnVtYmVyJylcbiAgfVxuXG4gIGlmICh0eXBlb2YgQXJyYXlCdWZmZXIgIT09ICd1bmRlZmluZWQnICYmIHZhbHVlIGluc3RhbmNlb2YgQXJyYXlCdWZmZXIpIHtcbiAgICByZXR1cm4gZnJvbUFycmF5QnVmZmVyKHRoYXQsIHZhbHVlLCBlbmNvZGluZ09yT2Zmc2V0LCBsZW5ndGgpXG4gIH1cblxuICBpZiAodHlwZW9mIHZhbHVlID09PSAnc3RyaW5nJykge1xuICAgIHJldHVybiBmcm9tU3RyaW5nKHRoYXQsIHZhbHVlLCBlbmNvZGluZ09yT2Zmc2V0KVxuICB9XG5cbiAgcmV0dXJuIGZyb21PYmplY3QodGhhdCwgdmFsdWUpXG59XG5cbi8qKlxuICogRnVuY3Rpb25hbGx5IGVxdWl2YWxlbnQgdG8gQnVmZmVyKGFyZywgZW5jb2RpbmcpIGJ1dCB0aHJvd3MgYSBUeXBlRXJyb3JcbiAqIGlmIHZhbHVlIGlzIGEgbnVtYmVyLlxuICogQnVmZmVyLmZyb20oc3RyWywgZW5jb2RpbmddKVxuICogQnVmZmVyLmZyb20oYXJyYXkpXG4gKiBCdWZmZXIuZnJvbShidWZmZXIpXG4gKiBCdWZmZXIuZnJvbShhcnJheUJ1ZmZlclssIGJ5dGVPZmZzZXRbLCBsZW5ndGhdXSlcbiAqKi9cbkJ1ZmZlci5mcm9tID0gZnVuY3Rpb24gKHZhbHVlLCBlbmNvZGluZ09yT2Zmc2V0LCBsZW5ndGgpIHtcbiAgcmV0dXJuIGZyb20obnVsbCwgdmFsdWUsIGVuY29kaW5nT3JPZmZzZXQsIGxlbmd0aClcbn1cblxuaWYgKEJ1ZmZlci5UWVBFRF9BUlJBWV9TVVBQT1JUKSB7XG4gIEJ1ZmZlci5wcm90b3R5cGUuX19wcm90b19fID0gVWludDhBcnJheS5wcm90b3R5cGVcbiAgQnVmZmVyLl9fcHJvdG9fXyA9IFVpbnQ4QXJyYXlcbiAgaWYgKHR5cGVvZiBTeW1ib2wgIT09ICd1bmRlZmluZWQnICYmIFN5bWJvbC5zcGVjaWVzICYmXG4gICAgICBCdWZmZXJbU3ltYm9sLnNwZWNpZXNdID09PSBCdWZmZXIpIHtcbiAgICAvLyBGaXggc3ViYXJyYXkoKSBpbiBFUzIwMTYuIFNlZTogaHR0cHM6Ly9naXRodWIuY29tL2Zlcm9zcy9idWZmZXIvcHVsbC85N1xuICAgIE9iamVjdC5kZWZpbmVQcm9wZXJ0eShCdWZmZXIsIFN5bWJvbC5zcGVjaWVzLCB7XG4gICAgICB2YWx1ZTogbnVsbCxcbiAgICAgIGNvbmZpZ3VyYWJsZTogdHJ1ZVxuICAgIH0pXG4gIH1cbn1cblxuZnVuY3Rpb24gYXNzZXJ0U2l6ZSAoc2l6ZSkge1xuICBpZiAodHlwZW9mIHNpemUgIT09ICdudW1iZXInKSB7XG4gICAgdGhyb3cgbmV3IFR5cGVFcnJvcignXCJzaXplXCIgYXJndW1lbnQgbXVzdCBiZSBhIG51bWJlcicpXG4gIH1cbn1cblxuZnVuY3Rpb24gYWxsb2MgKHRoYXQsIHNpemUsIGZpbGwsIGVuY29kaW5nKSB7XG4gIGFzc2VydFNpemUoc2l6ZSlcbiAgaWYgKHNpemUgPD0gMCkge1xuICAgIHJldHVybiBjcmVhdGVCdWZmZXIodGhhdCwgc2l6ZSlcbiAgfVxuICBpZiAoZmlsbCAhPT0gdW5kZWZpbmVkKSB7XG4gICAgLy8gT25seSBwYXkgYXR0ZW50aW9uIHRvIGVuY29kaW5nIGlmIGl0J3MgYSBzdHJpbmcuIFRoaXNcbiAgICAvLyBwcmV2ZW50cyBhY2NpZGVudGFsbHkgc2VuZGluZyBpbiBhIG51bWJlciB0aGF0IHdvdWxkXG4gICAgLy8gYmUgaW50ZXJwcmV0dGVkIGFzIGEgc3RhcnQgb2Zmc2V0LlxuICAgIHJldHVybiB0eXBlb2YgZW5jb2RpbmcgPT09ICdzdHJpbmcnXG4gICAgICA/IGNyZWF0ZUJ1ZmZlcih0aGF0LCBzaXplKS5maWxsKGZpbGwsIGVuY29kaW5nKVxuICAgICAgOiBjcmVhdGVCdWZmZXIodGhhdCwgc2l6ZSkuZmlsbChmaWxsKVxuICB9XG4gIHJldHVybiBjcmVhdGVCdWZmZXIodGhhdCwgc2l6ZSlcbn1cblxuLyoqXG4gKiBDcmVhdGVzIGEgbmV3IGZpbGxlZCBCdWZmZXIgaW5zdGFuY2UuXG4gKiBhbGxvYyhzaXplWywgZmlsbFssIGVuY29kaW5nXV0pXG4gKiovXG5CdWZmZXIuYWxsb2MgPSBmdW5jdGlvbiAoc2l6ZSwgZmlsbCwgZW5jb2RpbmcpIHtcbiAgcmV0dXJuIGFsbG9jKG51bGwsIHNpemUsIGZpbGwsIGVuY29kaW5nKVxufVxuXG5mdW5jdGlvbiBhbGxvY1Vuc2FmZSAodGhhdCwgc2l6ZSkge1xuICBhc3NlcnRTaXplKHNpemUpXG4gIHRoYXQgPSBjcmVhdGVCdWZmZXIodGhhdCwgc2l6ZSA8IDAgPyAwIDogY2hlY2tlZChzaXplKSB8IDApXG4gIGlmICghQnVmZmVyLlRZUEVEX0FSUkFZX1NVUFBPUlQpIHtcbiAgICBmb3IgKHZhciBpID0gMDsgaSA8IHNpemU7ICsraSkge1xuICAgICAgdGhhdFtpXSA9IDBcbiAgICB9XG4gIH1cbiAgcmV0dXJuIHRoYXRcbn1cblxuLyoqXG4gKiBFcXVpdmFsZW50IHRvIEJ1ZmZlcihudW0pLCBieSBkZWZhdWx0IGNyZWF0ZXMgYSBub24temVyby1maWxsZWQgQnVmZmVyIGluc3RhbmNlLlxuICogKi9cbkJ1ZmZlci5hbGxvY1Vuc2FmZSA9IGZ1bmN0aW9uIChzaXplKSB7XG4gIHJldHVybiBhbGxvY1Vuc2FmZShudWxsLCBzaXplKVxufVxuLyoqXG4gKiBFcXVpdmFsZW50IHRvIFNsb3dCdWZmZXIobnVtKSwgYnkgZGVmYXVsdCBjcmVhdGVzIGEgbm9uLXplcm8tZmlsbGVkIEJ1ZmZlciBpbnN0YW5jZS5cbiAqL1xuQnVmZmVyLmFsbG9jVW5zYWZlU2xvdyA9IGZ1bmN0aW9uIChzaXplKSB7XG4gIHJldHVybiBhbGxvY1Vuc2FmZShudWxsLCBzaXplKVxufVxuXG5mdW5jdGlvbiBmcm9tU3RyaW5nICh0aGF0LCBzdHJpbmcsIGVuY29kaW5nKSB7XG4gIGlmICh0eXBlb2YgZW5jb2RpbmcgIT09ICdzdHJpbmcnIHx8IGVuY29kaW5nID09PSAnJykge1xuICAgIGVuY29kaW5nID0gJ3V0ZjgnXG4gIH1cblxuICBpZiAoIUJ1ZmZlci5pc0VuY29kaW5nKGVuY29kaW5nKSkge1xuICAgIHRocm93IG5ldyBUeXBlRXJyb3IoJ1wiZW5jb2RpbmdcIiBtdXN0IGJlIGEgdmFsaWQgc3RyaW5nIGVuY29kaW5nJylcbiAgfVxuXG4gIHZhciBsZW5ndGggPSBieXRlTGVuZ3RoKHN0cmluZywgZW5jb2RpbmcpIHwgMFxuICB0aGF0ID0gY3JlYXRlQnVmZmVyKHRoYXQsIGxlbmd0aClcblxuICB0aGF0LndyaXRlKHN0cmluZywgZW5jb2RpbmcpXG4gIHJldHVybiB0aGF0XG59XG5cbmZ1bmN0aW9uIGZyb21BcnJheUxpa2UgKHRoYXQsIGFycmF5KSB7XG4gIHZhciBsZW5ndGggPSBjaGVja2VkKGFycmF5Lmxlbmd0aCkgfCAwXG4gIHRoYXQgPSBjcmVhdGVCdWZmZXIodGhhdCwgbGVuZ3RoKVxuICBmb3IgKHZhciBpID0gMDsgaSA8IGxlbmd0aDsgaSArPSAxKSB7XG4gICAgdGhhdFtpXSA9IGFycmF5W2ldICYgMjU1XG4gIH1cbiAgcmV0dXJuIHRoYXRcbn1cblxuZnVuY3Rpb24gZnJvbUFycmF5QnVmZmVyICh0aGF0LCBhcnJheSwgYnl0ZU9mZnNldCwgbGVuZ3RoKSB7XG4gIGFycmF5LmJ5dGVMZW5ndGggLy8gdGhpcyB0aHJvd3MgaWYgYGFycmF5YCBpcyBub3QgYSB2YWxpZCBBcnJheUJ1ZmZlclxuXG4gIGlmIChieXRlT2Zmc2V0IDwgMCB8fCBhcnJheS5ieXRlTGVuZ3RoIDwgYnl0ZU9mZnNldCkge1xuICAgIHRocm93IG5ldyBSYW5nZUVycm9yKCdcXCdvZmZzZXRcXCcgaXMgb3V0IG9mIGJvdW5kcycpXG4gIH1cblxuICBpZiAoYXJyYXkuYnl0ZUxlbmd0aCA8IGJ5dGVPZmZzZXQgKyAobGVuZ3RoIHx8IDApKSB7XG4gICAgdGhyb3cgbmV3IFJhbmdlRXJyb3IoJ1xcJ2xlbmd0aFxcJyBpcyBvdXQgb2YgYm91bmRzJylcbiAgfVxuXG4gIGlmIChieXRlT2Zmc2V0ID09PSB1bmRlZmluZWQgJiYgbGVuZ3RoID09PSB1bmRlZmluZWQpIHtcbiAgICBhcnJheSA9IG5ldyBVaW50OEFycmF5KGFycmF5KVxuICB9IGVsc2UgaWYgKGxlbmd0aCA9PT0gdW5kZWZpbmVkKSB7XG4gICAgYXJyYXkgPSBuZXcgVWludDhBcnJheShhcnJheSwgYnl0ZU9mZnNldClcbiAgfSBlbHNlIHtcbiAgICBhcnJheSA9IG5ldyBVaW50OEFycmF5KGFycmF5LCBieXRlT2Zmc2V0LCBsZW5ndGgpXG4gIH1cblxuICBpZiAoQnVmZmVyLlRZUEVEX0FSUkFZX1NVUFBPUlQpIHtcbiAgICAvLyBSZXR1cm4gYW4gYXVnbWVudGVkIGBVaW50OEFycmF5YCBpbnN0YW5jZSwgZm9yIGJlc3QgcGVyZm9ybWFuY2VcbiAgICB0aGF0ID0gYXJyYXlcbiAgICB0aGF0Ll9fcHJvdG9fXyA9IEJ1ZmZlci5wcm90b3R5cGVcbiAgfSBlbHNlIHtcbiAgICAvLyBGYWxsYmFjazogUmV0dXJuIGFuIG9iamVjdCBpbnN0YW5jZSBvZiB0aGUgQnVmZmVyIGNsYXNzXG4gICAgdGhhdCA9IGZyb21BcnJheUxpa2UodGhhdCwgYXJyYXkpXG4gIH1cbiAgcmV0dXJuIHRoYXRcbn1cblxuZnVuY3Rpb24gZnJvbU9iamVjdCAodGhhdCwgb2JqKSB7XG4gIGlmIChCdWZmZXIuaXNCdWZmZXIob2JqKSkge1xuICAgIHZhciBsZW4gPSBjaGVja2VkKG9iai5sZW5ndGgpIHwgMFxuICAgIHRoYXQgPSBjcmVhdGVCdWZmZXIodGhhdCwgbGVuKVxuXG4gICAgaWYgKHRoYXQubGVuZ3RoID09PSAwKSB7XG4gICAgICByZXR1cm4gdGhhdFxuICAgIH1cblxuICAgIG9iai5jb3B5KHRoYXQsIDAsIDAsIGxlbilcbiAgICByZXR1cm4gdGhhdFxuICB9XG5cbiAgaWYgKG9iaikge1xuICAgIGlmICgodHlwZW9mIEFycmF5QnVmZmVyICE9PSAndW5kZWZpbmVkJyAmJlxuICAgICAgICBvYmouYnVmZmVyIGluc3RhbmNlb2YgQXJyYXlCdWZmZXIpIHx8ICdsZW5ndGgnIGluIG9iaikge1xuICAgICAgaWYgKHR5cGVvZiBvYmoubGVuZ3RoICE9PSAnbnVtYmVyJyB8fCBpc25hbihvYmoubGVuZ3RoKSkge1xuICAgICAgICByZXR1cm4gY3JlYXRlQnVmZmVyKHRoYXQsIDApXG4gICAgICB9XG4gICAgICByZXR1cm4gZnJvbUFycmF5TGlrZSh0aGF0LCBvYmopXG4gICAgfVxuXG4gICAgaWYgKG9iai50eXBlID09PSAnQnVmZmVyJyAmJiBpc0FycmF5KG9iai5kYXRhKSkge1xuICAgICAgcmV0dXJuIGZyb21BcnJheUxpa2UodGhhdCwgb2JqLmRhdGEpXG4gICAgfVxuICB9XG5cbiAgdGhyb3cgbmV3IFR5cGVFcnJvcignRmlyc3QgYXJndW1lbnQgbXVzdCBiZSBhIHN0cmluZywgQnVmZmVyLCBBcnJheUJ1ZmZlciwgQXJyYXksIG9yIGFycmF5LWxpa2Ugb2JqZWN0LicpXG59XG5cbmZ1bmN0aW9uIGNoZWNrZWQgKGxlbmd0aCkge1xuICAvLyBOb3RlOiBjYW5ub3QgdXNlIGBsZW5ndGggPCBrTWF4TGVuZ3RoYCBoZXJlIGJlY2F1c2UgdGhhdCBmYWlscyB3aGVuXG4gIC8vIGxlbmd0aCBpcyBOYU4gKHdoaWNoIGlzIG90aGVyd2lzZSBjb2VyY2VkIHRvIHplcm8uKVxuICBpZiAobGVuZ3RoID49IGtNYXhMZW5ndGgoKSkge1xuICAgIHRocm93IG5ldyBSYW5nZUVycm9yKCdBdHRlbXB0IHRvIGFsbG9jYXRlIEJ1ZmZlciBsYXJnZXIgdGhhbiBtYXhpbXVtICcgK1xuICAgICAgICAgICAgICAgICAgICAgICAgICdzaXplOiAweCcgKyBrTWF4TGVuZ3RoKCkudG9TdHJpbmcoMTYpICsgJyBieXRlcycpXG4gIH1cbiAgcmV0dXJuIGxlbmd0aCB8IDBcbn1cblxuZnVuY3Rpb24gU2xvd0J1ZmZlciAobGVuZ3RoKSB7XG4gIGlmICgrbGVuZ3RoICE9IGxlbmd0aCkgeyAvLyBlc2xpbnQtZGlzYWJsZS1saW5lIGVxZXFlcVxuICAgIGxlbmd0aCA9IDBcbiAgfVxuICByZXR1cm4gQnVmZmVyLmFsbG9jKCtsZW5ndGgpXG59XG5cbkJ1ZmZlci5pc0J1ZmZlciA9IGZ1bmN0aW9uIGlzQnVmZmVyIChiKSB7XG4gIHJldHVybiAhIShiICE9IG51bGwgJiYgYi5faXNCdWZmZXIpXG59XG5cbkJ1ZmZlci5jb21wYXJlID0gZnVuY3Rpb24gY29tcGFyZSAoYSwgYikge1xuICBpZiAoIUJ1ZmZlci5pc0J1ZmZlcihhKSB8fCAhQnVmZmVyLmlzQnVmZmVyKGIpKSB7XG4gICAgdGhyb3cgbmV3IFR5cGVFcnJvcignQXJndW1lbnRzIG11c3QgYmUgQnVmZmVycycpXG4gIH1cblxuICBpZiAoYSA9PT0gYikgcmV0dXJuIDBcblxuICB2YXIgeCA9IGEubGVuZ3RoXG4gIHZhciB5ID0gYi5sZW5ndGhcblxuICBmb3IgKHZhciBpID0gMCwgbGVuID0gTWF0aC5taW4oeCwgeSk7IGkgPCBsZW47ICsraSkge1xuICAgIGlmIChhW2ldICE9PSBiW2ldKSB7XG4gICAgICB4ID0gYVtpXVxuICAgICAgeSA9IGJbaV1cbiAgICAgIGJyZWFrXG4gICAgfVxuICB9XG5cbiAgaWYgKHggPCB5KSByZXR1cm4gLTFcbiAgaWYgKHkgPCB4KSByZXR1cm4gMVxuICByZXR1cm4gMFxufVxuXG5CdWZmZXIuaXNFbmNvZGluZyA9IGZ1bmN0aW9uIGlzRW5jb2RpbmcgKGVuY29kaW5nKSB7XG4gIHN3aXRjaCAoU3RyaW5nKGVuY29kaW5nKS50b0xvd2VyQ2FzZSgpKSB7XG4gICAgY2FzZSAnaGV4JzpcbiAgICBjYXNlICd1dGY4JzpcbiAgICBjYXNlICd1dGYtOCc6XG4gICAgY2FzZSAnYXNjaWknOlxuICAgIGNhc2UgJ2JpbmFyeSc6XG4gICAgY2FzZSAnYmFzZTY0JzpcbiAgICBjYXNlICdyYXcnOlxuICAgIGNhc2UgJ3VjczInOlxuICAgIGNhc2UgJ3Vjcy0yJzpcbiAgICBjYXNlICd1dGYxNmxlJzpcbiAgICBjYXNlICd1dGYtMTZsZSc6XG4gICAgICByZXR1cm4gdHJ1ZVxuICAgIGRlZmF1bHQ6XG4gICAgICByZXR1cm4gZmFsc2VcbiAgfVxufVxuXG5CdWZmZXIuY29uY2F0ID0gZnVuY3Rpb24gY29uY2F0IChsaXN0LCBsZW5ndGgpIHtcbiAgaWYgKCFpc0FycmF5KGxpc3QpKSB7XG4gICAgdGhyb3cgbmV3IFR5cGVFcnJvcignXCJsaXN0XCIgYXJndW1lbnQgbXVzdCBiZSBhbiBBcnJheSBvZiBCdWZmZXJzJylcbiAgfVxuXG4gIGlmIChsaXN0Lmxlbmd0aCA9PT0gMCkge1xuICAgIHJldHVybiBCdWZmZXIuYWxsb2MoMClcbiAgfVxuXG4gIHZhciBpXG4gIGlmIChsZW5ndGggPT09IHVuZGVmaW5lZCkge1xuICAgIGxlbmd0aCA9IDBcbiAgICBmb3IgKGkgPSAwOyBpIDwgbGlzdC5sZW5ndGg7ICsraSkge1xuICAgICAgbGVuZ3RoICs9IGxpc3RbaV0ubGVuZ3RoXG4gICAgfVxuICB9XG5cbiAgdmFyIGJ1ZmZlciA9IEJ1ZmZlci5hbGxvY1Vuc2FmZShsZW5ndGgpXG4gIHZhciBwb3MgPSAwXG4gIGZvciAoaSA9IDA7IGkgPCBsaXN0Lmxlbmd0aDsgKytpKSB7XG4gICAgdmFyIGJ1ZiA9IGxpc3RbaV1cbiAgICBpZiAoIUJ1ZmZlci5pc0J1ZmZlcihidWYpKSB7XG4gICAgICB0aHJvdyBuZXcgVHlwZUVycm9yKCdcImxpc3RcIiBhcmd1bWVudCBtdXN0IGJlIGFuIEFycmF5IG9mIEJ1ZmZlcnMnKVxuICAgIH1cbiAgICBidWYuY29weShidWZmZXIsIHBvcylcbiAgICBwb3MgKz0gYnVmLmxlbmd0aFxuICB9XG4gIHJldHVybiBidWZmZXJcbn1cblxuZnVuY3Rpb24gYnl0ZUxlbmd0aCAoc3RyaW5nLCBlbmNvZGluZykge1xuICBpZiAoQnVmZmVyLmlzQnVmZmVyKHN0cmluZykpIHtcbiAgICByZXR1cm4gc3RyaW5nLmxlbmd0aFxuICB9XG4gIGlmICh0eXBlb2YgQXJyYXlCdWZmZXIgIT09ICd1bmRlZmluZWQnICYmIHR5cGVvZiBBcnJheUJ1ZmZlci5pc1ZpZXcgPT09ICdmdW5jdGlvbicgJiZcbiAgICAgIChBcnJheUJ1ZmZlci5pc1ZpZXcoc3RyaW5nKSB8fCBzdHJpbmcgaW5zdGFuY2VvZiBBcnJheUJ1ZmZlcikpIHtcbiAgICByZXR1cm4gc3RyaW5nLmJ5dGVMZW5ndGhcbiAgfVxuICBpZiAodHlwZW9mIHN0cmluZyAhPT0gJ3N0cmluZycpIHtcbiAgICBzdHJpbmcgPSAnJyArIHN0cmluZ1xuICB9XG5cbiAgdmFyIGxlbiA9IHN0cmluZy5sZW5ndGhcbiAgaWYgKGxlbiA9PT0gMCkgcmV0dXJuIDBcblxuICAvLyBVc2UgYSBmb3IgbG9vcCB0byBhdm9pZCByZWN1cnNpb25cbiAgdmFyIGxvd2VyZWRDYXNlID0gZmFsc2VcbiAgZm9yICg7Oykge1xuICAgIHN3aXRjaCAoZW5jb2RpbmcpIHtcbiAgICAgIGNhc2UgJ2FzY2lpJzpcbiAgICAgIGNhc2UgJ2JpbmFyeSc6XG4gICAgICBjYXNlICdyYXcnOlxuICAgICAgY2FzZSAncmF3cyc6XG4gICAgICAgIHJldHVybiBsZW5cbiAgICAgIGNhc2UgJ3V0ZjgnOlxuICAgICAgY2FzZSAndXRmLTgnOlxuICAgICAgY2FzZSB1bmRlZmluZWQ6XG4gICAgICAgIHJldHVybiB1dGY4VG9CeXRlcyhzdHJpbmcpLmxlbmd0aFxuICAgICAgY2FzZSAndWNzMic6XG4gICAgICBjYXNlICd1Y3MtMic6XG4gICAgICBjYXNlICd1dGYxNmxlJzpcbiAgICAgIGNhc2UgJ3V0Zi0xNmxlJzpcbiAgICAgICAgcmV0dXJuIGxlbiAqIDJcbiAgICAgIGNhc2UgJ2hleCc6XG4gICAgICAgIHJldHVybiBsZW4gPj4+IDFcbiAgICAgIGNhc2UgJ2Jhc2U2NCc6XG4gICAgICAgIHJldHVybiBiYXNlNjRUb0J5dGVzKHN0cmluZykubGVuZ3RoXG4gICAgICBkZWZhdWx0OlxuICAgICAgICBpZiAobG93ZXJlZENhc2UpIHJldHVybiB1dGY4VG9CeXRlcyhzdHJpbmcpLmxlbmd0aCAvLyBhc3N1bWUgdXRmOFxuICAgICAgICBlbmNvZGluZyA9ICgnJyArIGVuY29kaW5nKS50b0xvd2VyQ2FzZSgpXG4gICAgICAgIGxvd2VyZWRDYXNlID0gdHJ1ZVxuICAgIH1cbiAgfVxufVxuQnVmZmVyLmJ5dGVMZW5ndGggPSBieXRlTGVuZ3RoXG5cbmZ1bmN0aW9uIHNsb3dUb1N0cmluZyAoZW5jb2RpbmcsIHN0YXJ0LCBlbmQpIHtcbiAgdmFyIGxvd2VyZWRDYXNlID0gZmFsc2VcblxuICAvLyBObyBuZWVkIHRvIHZlcmlmeSB0aGF0IFwidGhpcy5sZW5ndGggPD0gTUFYX1VJTlQzMlwiIHNpbmNlIGl0J3MgYSByZWFkLW9ubHlcbiAgLy8gcHJvcGVydHkgb2YgYSB0eXBlZCBhcnJheS5cblxuICAvLyBUaGlzIGJlaGF2ZXMgbmVpdGhlciBsaWtlIFN0cmluZyBub3IgVWludDhBcnJheSBpbiB0aGF0IHdlIHNldCBzdGFydC9lbmRcbiAgLy8gdG8gdGhlaXIgdXBwZXIvbG93ZXIgYm91bmRzIGlmIHRoZSB2YWx1ZSBwYXNzZWQgaXMgb3V0IG9mIHJhbmdlLlxuICAvLyB1bmRlZmluZWQgaXMgaGFuZGxlZCBzcGVjaWFsbHkgYXMgcGVyIEVDTUEtMjYyIDZ0aCBFZGl0aW9uLFxuICAvLyBTZWN0aW9uIDEzLjMuMy43IFJ1bnRpbWUgU2VtYW50aWNzOiBLZXllZEJpbmRpbmdJbml0aWFsaXphdGlvbi5cbiAgaWYgKHN0YXJ0ID09PSB1bmRlZmluZWQgfHwgc3RhcnQgPCAwKSB7XG4gICAgc3RhcnQgPSAwXG4gIH1cbiAgLy8gUmV0dXJuIGVhcmx5IGlmIHN0YXJ0ID4gdGhpcy5sZW5ndGguIERvbmUgaGVyZSB0byBwcmV2ZW50IHBvdGVudGlhbCB1aW50MzJcbiAgLy8gY29lcmNpb24gZmFpbCBiZWxvdy5cbiAgaWYgKHN0YXJ0ID4gdGhpcy5sZW5ndGgpIHtcbiAgICByZXR1cm4gJydcbiAgfVxuXG4gIGlmIChlbmQgPT09IHVuZGVmaW5lZCB8fCBlbmQgPiB0aGlzLmxlbmd0aCkge1xuICAgIGVuZCA9IHRoaXMubGVuZ3RoXG4gIH1cblxuICBpZiAoZW5kIDw9IDApIHtcbiAgICByZXR1cm4gJydcbiAgfVxuXG4gIC8vIEZvcmNlIGNvZXJzaW9uIHRvIHVpbnQzMi4gVGhpcyB3aWxsIGFsc28gY29lcmNlIGZhbHNleS9OYU4gdmFsdWVzIHRvIDAuXG4gIGVuZCA+Pj49IDBcbiAgc3RhcnQgPj4+PSAwXG5cbiAgaWYgKGVuZCA8PSBzdGFydCkge1xuICAgIHJldHVybiAnJ1xuICB9XG5cbiAgaWYgKCFlbmNvZGluZykgZW5jb2RpbmcgPSAndXRmOCdcblxuICB3aGlsZSAodHJ1ZSkge1xuICAgIHN3aXRjaCAoZW5jb2RpbmcpIHtcbiAgICAgIGNhc2UgJ2hleCc6XG4gICAgICAgIHJldHVybiBoZXhTbGljZSh0aGlzLCBzdGFydCwgZW5kKVxuXG4gICAgICBjYXNlICd1dGY4JzpcbiAgICAgIGNhc2UgJ3V0Zi04JzpcbiAgICAgICAgcmV0dXJuIHV0ZjhTbGljZSh0aGlzLCBzdGFydCwgZW5kKVxuXG4gICAgICBjYXNlICdhc2NpaSc6XG4gICAgICAgIHJldHVybiBhc2NpaVNsaWNlKHRoaXMsIHN0YXJ0LCBlbmQpXG5cbiAgICAgIGNhc2UgJ2JpbmFyeSc6XG4gICAgICAgIHJldHVybiBiaW5hcnlTbGljZSh0aGlzLCBzdGFydCwgZW5kKVxuXG4gICAgICBjYXNlICdiYXNlNjQnOlxuICAgICAgICByZXR1cm4gYmFzZTY0U2xpY2UodGhpcywgc3RhcnQsIGVuZClcblxuICAgICAgY2FzZSAndWNzMic6XG4gICAgICBjYXNlICd1Y3MtMic6XG4gICAgICBjYXNlICd1dGYxNmxlJzpcbiAgICAgIGNhc2UgJ3V0Zi0xNmxlJzpcbiAgICAgICAgcmV0dXJuIHV0ZjE2bGVTbGljZSh0aGlzLCBzdGFydCwgZW5kKVxuXG4gICAgICBkZWZhdWx0OlxuICAgICAgICBpZiAobG93ZXJlZENhc2UpIHRocm93IG5ldyBUeXBlRXJyb3IoJ1Vua25vd24gZW5jb2Rpbmc6ICcgKyBlbmNvZGluZylcbiAgICAgICAgZW5jb2RpbmcgPSAoZW5jb2RpbmcgKyAnJykudG9Mb3dlckNhc2UoKVxuICAgICAgICBsb3dlcmVkQ2FzZSA9IHRydWVcbiAgICB9XG4gIH1cbn1cblxuLy8gVGhlIHByb3BlcnR5IGlzIHVzZWQgYnkgYEJ1ZmZlci5pc0J1ZmZlcmAgYW5kIGBpcy1idWZmZXJgIChpbiBTYWZhcmkgNS03KSB0byBkZXRlY3Rcbi8vIEJ1ZmZlciBpbnN0YW5jZXMuXG5CdWZmZXIucHJvdG90eXBlLl9pc0J1ZmZlciA9IHRydWVcblxuZnVuY3Rpb24gc3dhcCAoYiwgbiwgbSkge1xuICB2YXIgaSA9IGJbbl1cbiAgYltuXSA9IGJbbV1cbiAgYlttXSA9IGlcbn1cblxuQnVmZmVyLnByb3RvdHlwZS5zd2FwMTYgPSBmdW5jdGlvbiBzd2FwMTYgKCkge1xuICB2YXIgbGVuID0gdGhpcy5sZW5ndGhcbiAgaWYgKGxlbiAlIDIgIT09IDApIHtcbiAgICB0aHJvdyBuZXcgUmFuZ2VFcnJvcignQnVmZmVyIHNpemUgbXVzdCBiZSBhIG11bHRpcGxlIG9mIDE2LWJpdHMnKVxuICB9XG4gIGZvciAodmFyIGkgPSAwOyBpIDwgbGVuOyBpICs9IDIpIHtcbiAgICBzd2FwKHRoaXMsIGksIGkgKyAxKVxuICB9XG4gIHJldHVybiB0aGlzXG59XG5cbkJ1ZmZlci5wcm90b3R5cGUuc3dhcDMyID0gZnVuY3Rpb24gc3dhcDMyICgpIHtcbiAgdmFyIGxlbiA9IHRoaXMubGVuZ3RoXG4gIGlmIChsZW4gJSA0ICE9PSAwKSB7XG4gICAgdGhyb3cgbmV3IFJhbmdlRXJyb3IoJ0J1ZmZlciBzaXplIG11c3QgYmUgYSBtdWx0aXBsZSBvZiAzMi1iaXRzJylcbiAgfVxuICBmb3IgKHZhciBpID0gMDsgaSA8IGxlbjsgaSArPSA0KSB7XG4gICAgc3dhcCh0aGlzLCBpLCBpICsgMylcbiAgICBzd2FwKHRoaXMsIGkgKyAxLCBpICsgMilcbiAgfVxuICByZXR1cm4gdGhpc1xufVxuXG5CdWZmZXIucHJvdG90eXBlLnRvU3RyaW5nID0gZnVuY3Rpb24gdG9TdHJpbmcgKCkge1xuICB2YXIgbGVuZ3RoID0gdGhpcy5sZW5ndGggfCAwXG4gIGlmIChsZW5ndGggPT09IDApIHJldHVybiAnJ1xuICBpZiAoYXJndW1lbnRzLmxlbmd0aCA9PT0gMCkgcmV0dXJuIHV0ZjhTbGljZSh0aGlzLCAwLCBsZW5ndGgpXG4gIHJldHVybiBzbG93VG9TdHJpbmcuYXBwbHkodGhpcywgYXJndW1lbnRzKVxufVxuXG5CdWZmZXIucHJvdG90eXBlLmVxdWFscyA9IGZ1bmN0aW9uIGVxdWFscyAoYikge1xuICBpZiAoIUJ1ZmZlci5pc0J1ZmZlcihiKSkgdGhyb3cgbmV3IFR5cGVFcnJvcignQXJndW1lbnQgbXVzdCBiZSBhIEJ1ZmZlcicpXG4gIGlmICh0aGlzID09PSBiKSByZXR1cm4gdHJ1ZVxuICByZXR1cm4gQnVmZmVyLmNvbXBhcmUodGhpcywgYikgPT09IDBcbn1cblxuQnVmZmVyLnByb3RvdHlwZS5pbnNwZWN0ID0gZnVuY3Rpb24gaW5zcGVjdCAoKSB7XG4gIHZhciBzdHIgPSAnJ1xuICB2YXIgbWF4ID0gZXhwb3J0cy5JTlNQRUNUX01BWF9CWVRFU1xuICBpZiAodGhpcy5sZW5ndGggPiAwKSB7XG4gICAgc3RyID0gdGhpcy50b1N0cmluZygnaGV4JywgMCwgbWF4KS5tYXRjaCgvLnsyfS9nKS5qb2luKCcgJylcbiAgICBpZiAodGhpcy5sZW5ndGggPiBtYXgpIHN0ciArPSAnIC4uLiAnXG4gIH1cbiAgcmV0dXJuICc8QnVmZmVyICcgKyBzdHIgKyAnPidcbn1cblxuQnVmZmVyLnByb3RvdHlwZS5jb21wYXJlID0gZnVuY3Rpb24gY29tcGFyZSAodGFyZ2V0LCBzdGFydCwgZW5kLCB0aGlzU3RhcnQsIHRoaXNFbmQpIHtcbiAgaWYgKCFCdWZmZXIuaXNCdWZmZXIodGFyZ2V0KSkge1xuICAgIHRocm93IG5ldyBUeXBlRXJyb3IoJ0FyZ3VtZW50IG11c3QgYmUgYSBCdWZmZXInKVxuICB9XG5cbiAgaWYgKHN0YXJ0ID09PSB1bmRlZmluZWQpIHtcbiAgICBzdGFydCA9IDBcbiAgfVxuICBpZiAoZW5kID09PSB1bmRlZmluZWQpIHtcbiAgICBlbmQgPSB0YXJnZXQgPyB0YXJnZXQubGVuZ3RoIDogMFxuICB9XG4gIGlmICh0aGlzU3RhcnQgPT09IHVuZGVmaW5lZCkge1xuICAgIHRoaXNTdGFydCA9IDBcbiAgfVxuICBpZiAodGhpc0VuZCA9PT0gdW5kZWZpbmVkKSB7XG4gICAgdGhpc0VuZCA9IHRoaXMubGVuZ3RoXG4gIH1cblxuICBpZiAoc3RhcnQgPCAwIHx8IGVuZCA+IHRhcmdldC5sZW5ndGggfHwgdGhpc1N0YXJ0IDwgMCB8fCB0aGlzRW5kID4gdGhpcy5sZW5ndGgpIHtcbiAgICB0aHJvdyBuZXcgUmFuZ2VFcnJvcignb3V0IG9mIHJhbmdlIGluZGV4JylcbiAgfVxuXG4gIGlmICh0aGlzU3RhcnQgPj0gdGhpc0VuZCAmJiBzdGFydCA+PSBlbmQpIHtcbiAgICByZXR1cm4gMFxuICB9XG4gIGlmICh0aGlzU3RhcnQgPj0gdGhpc0VuZCkge1xuICAgIHJldHVybiAtMVxuICB9XG4gIGlmIChzdGFydCA+PSBlbmQpIHtcbiAgICByZXR1cm4gMVxuICB9XG5cbiAgc3RhcnQgPj4+PSAwXG4gIGVuZCA+Pj49IDBcbiAgdGhpc1N0YXJ0ID4+Pj0gMFxuICB0aGlzRW5kID4+Pj0gMFxuXG4gIGlmICh0aGlzID09PSB0YXJnZXQpIHJldHVybiAwXG5cbiAgdmFyIHggPSB0aGlzRW5kIC0gdGhpc1N0YXJ0XG4gIHZhciB5ID0gZW5kIC0gc3RhcnRcbiAgdmFyIGxlbiA9IE1hdGgubWluKHgsIHkpXG5cbiAgdmFyIHRoaXNDb3B5ID0gdGhpcy5zbGljZSh0aGlzU3RhcnQsIHRoaXNFbmQpXG4gIHZhciB0YXJnZXRDb3B5ID0gdGFyZ2V0LnNsaWNlKHN0YXJ0LCBlbmQpXG5cbiAgZm9yICh2YXIgaSA9IDA7IGkgPCBsZW47ICsraSkge1xuICAgIGlmICh0aGlzQ29weVtpXSAhPT0gdGFyZ2V0Q29weVtpXSkge1xuICAgICAgeCA9IHRoaXNDb3B5W2ldXG4gICAgICB5ID0gdGFyZ2V0Q29weVtpXVxuICAgICAgYnJlYWtcbiAgICB9XG4gIH1cblxuICBpZiAoeCA8IHkpIHJldHVybiAtMVxuICBpZiAoeSA8IHgpIHJldHVybiAxXG4gIHJldHVybiAwXG59XG5cbmZ1bmN0aW9uIGFycmF5SW5kZXhPZiAoYXJyLCB2YWwsIGJ5dGVPZmZzZXQsIGVuY29kaW5nKSB7XG4gIHZhciBpbmRleFNpemUgPSAxXG4gIHZhciBhcnJMZW5ndGggPSBhcnIubGVuZ3RoXG4gIHZhciB2YWxMZW5ndGggPSB2YWwubGVuZ3RoXG5cbiAgaWYgKGVuY29kaW5nICE9PSB1bmRlZmluZWQpIHtcbiAgICBlbmNvZGluZyA9IFN0cmluZyhlbmNvZGluZykudG9Mb3dlckNhc2UoKVxuICAgIGlmIChlbmNvZGluZyA9PT0gJ3VjczInIHx8IGVuY29kaW5nID09PSAndWNzLTInIHx8XG4gICAgICAgIGVuY29kaW5nID09PSAndXRmMTZsZScgfHwgZW5jb2RpbmcgPT09ICd1dGYtMTZsZScpIHtcbiAgICAgIGlmIChhcnIubGVuZ3RoIDwgMiB8fCB2YWwubGVuZ3RoIDwgMikge1xuICAgICAgICByZXR1cm4gLTFcbiAgICAgIH1cbiAgICAgIGluZGV4U2l6ZSA9IDJcbiAgICAgIGFyckxlbmd0aCAvPSAyXG4gICAgICB2YWxMZW5ndGggLz0gMlxuICAgICAgYnl0ZU9mZnNldCAvPSAyXG4gICAgfVxuICB9XG5cbiAgZnVuY3Rpb24gcmVhZCAoYnVmLCBpKSB7XG4gICAgaWYgKGluZGV4U2l6ZSA9PT0gMSkge1xuICAgICAgcmV0dXJuIGJ1ZltpXVxuICAgIH0gZWxzZSB7XG4gICAgICByZXR1cm4gYnVmLnJlYWRVSW50MTZCRShpICogaW5kZXhTaXplKVxuICAgIH1cbiAgfVxuXG4gIHZhciBmb3VuZEluZGV4ID0gLTFcbiAgZm9yICh2YXIgaSA9IGJ5dGVPZmZzZXQ7IGkgPCBhcnJMZW5ndGg7ICsraSkge1xuICAgIGlmIChyZWFkKGFyciwgaSkgPT09IHJlYWQodmFsLCBmb3VuZEluZGV4ID09PSAtMSA/IDAgOiBpIC0gZm91bmRJbmRleCkpIHtcbiAgICAgIGlmIChmb3VuZEluZGV4ID09PSAtMSkgZm91bmRJbmRleCA9IGlcbiAgICAgIGlmIChpIC0gZm91bmRJbmRleCArIDEgPT09IHZhbExlbmd0aCkgcmV0dXJuIGZvdW5kSW5kZXggKiBpbmRleFNpemVcbiAgICB9IGVsc2Uge1xuICAgICAgaWYgKGZvdW5kSW5kZXggIT09IC0xKSBpIC09IGkgLSBmb3VuZEluZGV4XG4gICAgICBmb3VuZEluZGV4ID0gLTFcbiAgICB9XG4gIH1cblxuICByZXR1cm4gLTFcbn1cblxuQnVmZmVyLnByb3RvdHlwZS5pbmRleE9mID0gZnVuY3Rpb24gaW5kZXhPZiAodmFsLCBieXRlT2Zmc2V0LCBlbmNvZGluZykge1xuICBpZiAodHlwZW9mIGJ5dGVPZmZzZXQgPT09ICdzdHJpbmcnKSB7XG4gICAgZW5jb2RpbmcgPSBieXRlT2Zmc2V0XG4gICAgYnl0ZU9mZnNldCA9IDBcbiAgfSBlbHNlIGlmIChieXRlT2Zmc2V0ID4gMHg3ZmZmZmZmZikge1xuICAgIGJ5dGVPZmZzZXQgPSAweDdmZmZmZmZmXG4gIH0gZWxzZSBpZiAoYnl0ZU9mZnNldCA8IC0weDgwMDAwMDAwKSB7XG4gICAgYnl0ZU9mZnNldCA9IC0weDgwMDAwMDAwXG4gIH1cbiAgYnl0ZU9mZnNldCA+Pj0gMFxuXG4gIGlmICh0aGlzLmxlbmd0aCA9PT0gMCkgcmV0dXJuIC0xXG4gIGlmIChieXRlT2Zmc2V0ID49IHRoaXMubGVuZ3RoKSByZXR1cm4gLTFcblxuICAvLyBOZWdhdGl2ZSBvZmZzZXRzIHN0YXJ0IGZyb20gdGhlIGVuZCBvZiB0aGUgYnVmZmVyXG4gIGlmIChieXRlT2Zmc2V0IDwgMCkgYnl0ZU9mZnNldCA9IE1hdGgubWF4KHRoaXMubGVuZ3RoICsgYnl0ZU9mZnNldCwgMClcblxuICBpZiAodHlwZW9mIHZhbCA9PT0gJ3N0cmluZycpIHtcbiAgICB2YWwgPSBCdWZmZXIuZnJvbSh2YWwsIGVuY29kaW5nKVxuICB9XG5cbiAgaWYgKEJ1ZmZlci5pc0J1ZmZlcih2YWwpKSB7XG4gICAgLy8gc3BlY2lhbCBjYXNlOiBsb29raW5nIGZvciBlbXB0eSBzdHJpbmcvYnVmZmVyIGFsd2F5cyBmYWlsc1xuICAgIGlmICh2YWwubGVuZ3RoID09PSAwKSB7XG4gICAgICByZXR1cm4gLTFcbiAgICB9XG4gICAgcmV0dXJuIGFycmF5SW5kZXhPZih0aGlzLCB2YWwsIGJ5dGVPZmZzZXQsIGVuY29kaW5nKVxuICB9XG4gIGlmICh0eXBlb2YgdmFsID09PSAnbnVtYmVyJykge1xuICAgIGlmIChCdWZmZXIuVFlQRURfQVJSQVlfU1VQUE9SVCAmJiBVaW50OEFycmF5LnByb3RvdHlwZS5pbmRleE9mID09PSAnZnVuY3Rpb24nKSB7XG4gICAgICByZXR1cm4gVWludDhBcnJheS5wcm90b3R5cGUuaW5kZXhPZi5jYWxsKHRoaXMsIHZhbCwgYnl0ZU9mZnNldClcbiAgICB9XG4gICAgcmV0dXJuIGFycmF5SW5kZXhPZih0aGlzLCBbIHZhbCBdLCBieXRlT2Zmc2V0LCBlbmNvZGluZylcbiAgfVxuXG4gIHRocm93IG5ldyBUeXBlRXJyb3IoJ3ZhbCBtdXN0IGJlIHN0cmluZywgbnVtYmVyIG9yIEJ1ZmZlcicpXG59XG5cbkJ1ZmZlci5wcm90b3R5cGUuaW5jbHVkZXMgPSBmdW5jdGlvbiBpbmNsdWRlcyAodmFsLCBieXRlT2Zmc2V0LCBlbmNvZGluZykge1xuICByZXR1cm4gdGhpcy5pbmRleE9mKHZhbCwgYnl0ZU9mZnNldCwgZW5jb2RpbmcpICE9PSAtMVxufVxuXG5mdW5jdGlvbiBoZXhXcml0ZSAoYnVmLCBzdHJpbmcsIG9mZnNldCwgbGVuZ3RoKSB7XG4gIG9mZnNldCA9IE51bWJlcihvZmZzZXQpIHx8IDBcbiAgdmFyIHJlbWFpbmluZyA9IGJ1Zi5sZW5ndGggLSBvZmZzZXRcbiAgaWYgKCFsZW5ndGgpIHtcbiAgICBsZW5ndGggPSByZW1haW5pbmdcbiAgfSBlbHNlIHtcbiAgICBsZW5ndGggPSBOdW1iZXIobGVuZ3RoKVxuICAgIGlmIChsZW5ndGggPiByZW1haW5pbmcpIHtcbiAgICAgIGxlbmd0aCA9IHJlbWFpbmluZ1xuICAgIH1cbiAgfVxuXG4gIC8vIG11c3QgYmUgYW4gZXZlbiBudW1iZXIgb2YgZGlnaXRzXG4gIHZhciBzdHJMZW4gPSBzdHJpbmcubGVuZ3RoXG4gIGlmIChzdHJMZW4gJSAyICE9PSAwKSB0aHJvdyBuZXcgRXJyb3IoJ0ludmFsaWQgaGV4IHN0cmluZycpXG5cbiAgaWYgKGxlbmd0aCA+IHN0ckxlbiAvIDIpIHtcbiAgICBsZW5ndGggPSBzdHJMZW4gLyAyXG4gIH1cbiAgZm9yICh2YXIgaSA9IDA7IGkgPCBsZW5ndGg7ICsraSkge1xuICAgIHZhciBwYXJzZWQgPSBwYXJzZUludChzdHJpbmcuc3Vic3RyKGkgKiAyLCAyKSwgMTYpXG4gICAgaWYgKGlzTmFOKHBhcnNlZCkpIHJldHVybiBpXG4gICAgYnVmW29mZnNldCArIGldID0gcGFyc2VkXG4gIH1cbiAgcmV0dXJuIGlcbn1cblxuZnVuY3Rpb24gdXRmOFdyaXRlIChidWYsIHN0cmluZywgb2Zmc2V0LCBsZW5ndGgpIHtcbiAgcmV0dXJuIGJsaXRCdWZmZXIodXRmOFRvQnl0ZXMoc3RyaW5nLCBidWYubGVuZ3RoIC0gb2Zmc2V0KSwgYnVmLCBvZmZzZXQsIGxlbmd0aClcbn1cblxuZnVuY3Rpb24gYXNjaWlXcml0ZSAoYnVmLCBzdHJpbmcsIG9mZnNldCwgbGVuZ3RoKSB7XG4gIHJldHVybiBibGl0QnVmZmVyKGFzY2lpVG9CeXRlcyhzdHJpbmcpLCBidWYsIG9mZnNldCwgbGVuZ3RoKVxufVxuXG5mdW5jdGlvbiBiaW5hcnlXcml0ZSAoYnVmLCBzdHJpbmcsIG9mZnNldCwgbGVuZ3RoKSB7XG4gIHJldHVybiBhc2NpaVdyaXRlKGJ1Ziwgc3RyaW5nLCBvZmZzZXQsIGxlbmd0aClcbn1cblxuZnVuY3Rpb24gYmFzZTY0V3JpdGUgKGJ1Ziwgc3RyaW5nLCBvZmZzZXQsIGxlbmd0aCkge1xuICByZXR1cm4gYmxpdEJ1ZmZlcihiYXNlNjRUb0J5dGVzKHN0cmluZyksIGJ1Ziwgb2Zmc2V0LCBsZW5ndGgpXG59XG5cbmZ1bmN0aW9uIHVjczJXcml0ZSAoYnVmLCBzdHJpbmcsIG9mZnNldCwgbGVuZ3RoKSB7XG4gIHJldHVybiBibGl0QnVmZmVyKHV0ZjE2bGVUb0J5dGVzKHN0cmluZywgYnVmLmxlbmd0aCAtIG9mZnNldCksIGJ1Ziwgb2Zmc2V0LCBsZW5ndGgpXG59XG5cbkJ1ZmZlci5wcm90b3R5cGUud3JpdGUgPSBmdW5jdGlvbiB3cml0ZSAoc3RyaW5nLCBvZmZzZXQsIGxlbmd0aCwgZW5jb2RpbmcpIHtcbiAgLy8gQnVmZmVyI3dyaXRlKHN0cmluZylcbiAgaWYgKG9mZnNldCA9PT0gdW5kZWZpbmVkKSB7XG4gICAgZW5jb2RpbmcgPSAndXRmOCdcbiAgICBsZW5ndGggPSB0aGlzLmxlbmd0aFxuICAgIG9mZnNldCA9IDBcbiAgLy8gQnVmZmVyI3dyaXRlKHN0cmluZywgZW5jb2RpbmcpXG4gIH0gZWxzZSBpZiAobGVuZ3RoID09PSB1bmRlZmluZWQgJiYgdHlwZW9mIG9mZnNldCA9PT0gJ3N0cmluZycpIHtcbiAgICBlbmNvZGluZyA9IG9mZnNldFxuICAgIGxlbmd0aCA9IHRoaXMubGVuZ3RoXG4gICAgb2Zmc2V0ID0gMFxuICAvLyBCdWZmZXIjd3JpdGUoc3RyaW5nLCBvZmZzZXRbLCBsZW5ndGhdWywgZW5jb2RpbmddKVxuICB9IGVsc2UgaWYgKGlzRmluaXRlKG9mZnNldCkpIHtcbiAgICBvZmZzZXQgPSBvZmZzZXQgfCAwXG4gICAgaWYgKGlzRmluaXRlKGxlbmd0aCkpIHtcbiAgICAgIGxlbmd0aCA9IGxlbmd0aCB8IDBcbiAgICAgIGlmIChlbmNvZGluZyA9PT0gdW5kZWZpbmVkKSBlbmNvZGluZyA9ICd1dGY4J1xuICAgIH0gZWxzZSB7XG4gICAgICBlbmNvZGluZyA9IGxlbmd0aFxuICAgICAgbGVuZ3RoID0gdW5kZWZpbmVkXG4gICAgfVxuICAvLyBsZWdhY3kgd3JpdGUoc3RyaW5nLCBlbmNvZGluZywgb2Zmc2V0LCBsZW5ndGgpIC0gcmVtb3ZlIGluIHYwLjEzXG4gIH0gZWxzZSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKFxuICAgICAgJ0J1ZmZlci53cml0ZShzdHJpbmcsIGVuY29kaW5nLCBvZmZzZXRbLCBsZW5ndGhdKSBpcyBubyBsb25nZXIgc3VwcG9ydGVkJ1xuICAgIClcbiAgfVxuXG4gIHZhciByZW1haW5pbmcgPSB0aGlzLmxlbmd0aCAtIG9mZnNldFxuICBpZiAobGVuZ3RoID09PSB1bmRlZmluZWQgfHwgbGVuZ3RoID4gcmVtYWluaW5nKSBsZW5ndGggPSByZW1haW5pbmdcblxuICBpZiAoKHN0cmluZy5sZW5ndGggPiAwICYmIChsZW5ndGggPCAwIHx8IG9mZnNldCA8IDApKSB8fCBvZmZzZXQgPiB0aGlzLmxlbmd0aCkge1xuICAgIHRocm93IG5ldyBSYW5nZUVycm9yKCdBdHRlbXB0IHRvIHdyaXRlIG91dHNpZGUgYnVmZmVyIGJvdW5kcycpXG4gIH1cblxuICBpZiAoIWVuY29kaW5nKSBlbmNvZGluZyA9ICd1dGY4J1xuXG4gIHZhciBsb3dlcmVkQ2FzZSA9IGZhbHNlXG4gIGZvciAoOzspIHtcbiAgICBzd2l0Y2ggKGVuY29kaW5nKSB7XG4gICAgICBjYXNlICdoZXgnOlxuICAgICAgICByZXR1cm4gaGV4V3JpdGUodGhpcywgc3RyaW5nLCBvZmZzZXQsIGxlbmd0aClcblxuICAgICAgY2FzZSAndXRmOCc6XG4gICAgICBjYXNlICd1dGYtOCc6XG4gICAgICAgIHJldHVybiB1dGY4V3JpdGUodGhpcywgc3RyaW5nLCBvZmZzZXQsIGxlbmd0aClcblxuICAgICAgY2FzZSAnYXNjaWknOlxuICAgICAgICByZXR1cm4gYXNjaWlXcml0ZSh0aGlzLCBzdHJpbmcsIG9mZnNldCwgbGVuZ3RoKVxuXG4gICAgICBjYXNlICdiaW5hcnknOlxuICAgICAgICByZXR1cm4gYmluYXJ5V3JpdGUodGhpcywgc3RyaW5nLCBvZmZzZXQsIGxlbmd0aClcblxuICAgICAgY2FzZSAnYmFzZTY0JzpcbiAgICAgICAgLy8gV2FybmluZzogbWF4TGVuZ3RoIG5vdCB0YWtlbiBpbnRvIGFjY291bnQgaW4gYmFzZTY0V3JpdGVcbiAgICAgICAgcmV0dXJuIGJhc2U2NFdyaXRlKHRoaXMsIHN0cmluZywgb2Zmc2V0LCBsZW5ndGgpXG5cbiAgICAgIGNhc2UgJ3VjczInOlxuICAgICAgY2FzZSAndWNzLTInOlxuICAgICAgY2FzZSAndXRmMTZsZSc6XG4gICAgICBjYXNlICd1dGYtMTZsZSc6XG4gICAgICAgIHJldHVybiB1Y3MyV3JpdGUodGhpcywgc3RyaW5nLCBvZmZzZXQsIGxlbmd0aClcblxuICAgICAgZGVmYXVsdDpcbiAgICAgICAgaWYgKGxvd2VyZWRDYXNlKSB0aHJvdyBuZXcgVHlwZUVycm9yKCdVbmtub3duIGVuY29kaW5nOiAnICsgZW5jb2RpbmcpXG4gICAgICAgIGVuY29kaW5nID0gKCcnICsgZW5jb2RpbmcpLnRvTG93ZXJDYXNlKClcbiAgICAgICAgbG93ZXJlZENhc2UgPSB0cnVlXG4gICAgfVxuICB9XG59XG5cbkJ1ZmZlci5wcm90b3R5cGUudG9KU09OID0gZnVuY3Rpb24gdG9KU09OICgpIHtcbiAgcmV0dXJuIHtcbiAgICB0eXBlOiAnQnVmZmVyJyxcbiAgICBkYXRhOiBBcnJheS5wcm90b3R5cGUuc2xpY2UuY2FsbCh0aGlzLl9hcnIgfHwgdGhpcywgMClcbiAgfVxufVxuXG5mdW5jdGlvbiBiYXNlNjRTbGljZSAoYnVmLCBzdGFydCwgZW5kKSB7XG4gIGlmIChzdGFydCA9PT0gMCAmJiBlbmQgPT09IGJ1Zi5sZW5ndGgpIHtcbiAgICByZXR1cm4gYmFzZTY0LmZyb21CeXRlQXJyYXkoYnVmKVxuICB9IGVsc2Uge1xuICAgIHJldHVybiBiYXNlNjQuZnJvbUJ5dGVBcnJheShidWYuc2xpY2Uoc3RhcnQsIGVuZCkpXG4gIH1cbn1cblxuZnVuY3Rpb24gdXRmOFNsaWNlIChidWYsIHN0YXJ0LCBlbmQpIHtcbiAgZW5kID0gTWF0aC5taW4oYnVmLmxlbmd0aCwgZW5kKVxuICB2YXIgcmVzID0gW11cblxuICB2YXIgaSA9IHN0YXJ0XG4gIHdoaWxlIChpIDwgZW5kKSB7XG4gICAgdmFyIGZpcnN0Qnl0ZSA9IGJ1ZltpXVxuICAgIHZhciBjb2RlUG9pbnQgPSBudWxsXG4gICAgdmFyIGJ5dGVzUGVyU2VxdWVuY2UgPSAoZmlyc3RCeXRlID4gMHhFRikgPyA0XG4gICAgICA6IChmaXJzdEJ5dGUgPiAweERGKSA/IDNcbiAgICAgIDogKGZpcnN0Qnl0ZSA+IDB4QkYpID8gMlxuICAgICAgOiAxXG5cbiAgICBpZiAoaSArIGJ5dGVzUGVyU2VxdWVuY2UgPD0gZW5kKSB7XG4gICAgICB2YXIgc2Vjb25kQnl0ZSwgdGhpcmRCeXRlLCBmb3VydGhCeXRlLCB0ZW1wQ29kZVBvaW50XG5cbiAgICAgIHN3aXRjaCAoYnl0ZXNQZXJTZXF1ZW5jZSkge1xuICAgICAgICBjYXNlIDE6XG4gICAgICAgICAgaWYgKGZpcnN0Qnl0ZSA8IDB4ODApIHtcbiAgICAgICAgICAgIGNvZGVQb2ludCA9IGZpcnN0Qnl0ZVxuICAgICAgICAgIH1cbiAgICAgICAgICBicmVha1xuICAgICAgICBjYXNlIDI6XG4gICAgICAgICAgc2Vjb25kQnl0ZSA9IGJ1ZltpICsgMV1cbiAgICAgICAgICBpZiAoKHNlY29uZEJ5dGUgJiAweEMwKSA9PT0gMHg4MCkge1xuICAgICAgICAgICAgdGVtcENvZGVQb2ludCA9IChmaXJzdEJ5dGUgJiAweDFGKSA8PCAweDYgfCAoc2Vjb25kQnl0ZSAmIDB4M0YpXG4gICAgICAgICAgICBpZiAodGVtcENvZGVQb2ludCA+IDB4N0YpIHtcbiAgICAgICAgICAgICAgY29kZVBvaW50ID0gdGVtcENvZGVQb2ludFxuICAgICAgICAgICAgfVxuICAgICAgICAgIH1cbiAgICAgICAgICBicmVha1xuICAgICAgICBjYXNlIDM6XG4gICAgICAgICAgc2Vjb25kQnl0ZSA9IGJ1ZltpICsgMV1cbiAgICAgICAgICB0aGlyZEJ5dGUgPSBidWZbaSArIDJdXG4gICAgICAgICAgaWYgKChzZWNvbmRCeXRlICYgMHhDMCkgPT09IDB4ODAgJiYgKHRoaXJkQnl0ZSAmIDB4QzApID09PSAweDgwKSB7XG4gICAgICAgICAgICB0ZW1wQ29kZVBvaW50ID0gKGZpcnN0Qnl0ZSAmIDB4RikgPDwgMHhDIHwgKHNlY29uZEJ5dGUgJiAweDNGKSA8PCAweDYgfCAodGhpcmRCeXRlICYgMHgzRilcbiAgICAgICAgICAgIGlmICh0ZW1wQ29kZVBvaW50ID4gMHg3RkYgJiYgKHRlbXBDb2RlUG9pbnQgPCAweEQ4MDAgfHwgdGVtcENvZGVQb2ludCA+IDB4REZGRikpIHtcbiAgICAgICAgICAgICAgY29kZVBvaW50ID0gdGVtcENvZGVQb2ludFxuICAgICAgICAgICAgfVxuICAgICAgICAgIH1cbiAgICAgICAgICBicmVha1xuICAgICAgICBjYXNlIDQ6XG4gICAgICAgICAgc2Vjb25kQnl0ZSA9IGJ1ZltpICsgMV1cbiAgICAgICAgICB0aGlyZEJ5dGUgPSBidWZbaSArIDJdXG4gICAgICAgICAgZm91cnRoQnl0ZSA9IGJ1ZltpICsgM11cbiAgICAgICAgICBpZiAoKHNlY29uZEJ5dGUgJiAweEMwKSA9PT0gMHg4MCAmJiAodGhpcmRCeXRlICYgMHhDMCkgPT09IDB4ODAgJiYgKGZvdXJ0aEJ5dGUgJiAweEMwKSA9PT0gMHg4MCkge1xuICAgICAgICAgICAgdGVtcENvZGVQb2ludCA9IChmaXJzdEJ5dGUgJiAweEYpIDw8IDB4MTIgfCAoc2Vjb25kQnl0ZSAmIDB4M0YpIDw8IDB4QyB8ICh0aGlyZEJ5dGUgJiAweDNGKSA8PCAweDYgfCAoZm91cnRoQnl0ZSAmIDB4M0YpXG4gICAgICAgICAgICBpZiAodGVtcENvZGVQb2ludCA+IDB4RkZGRiAmJiB0ZW1wQ29kZVBvaW50IDwgMHgxMTAwMDApIHtcbiAgICAgICAgICAgICAgY29kZVBvaW50ID0gdGVtcENvZGVQb2ludFxuICAgICAgICAgICAgfVxuICAgICAgICAgIH1cbiAgICAgIH1cbiAgICB9XG5cbiAgICBpZiAoY29kZVBvaW50ID09PSBudWxsKSB7XG4gICAgICAvLyB3ZSBkaWQgbm90IGdlbmVyYXRlIGEgdmFsaWQgY29kZVBvaW50IHNvIGluc2VydCBhXG4gICAgICAvLyByZXBsYWNlbWVudCBjaGFyIChVK0ZGRkQpIGFuZCBhZHZhbmNlIG9ubHkgMSBieXRlXG4gICAgICBjb2RlUG9pbnQgPSAweEZGRkRcbiAgICAgIGJ5dGVzUGVyU2VxdWVuY2UgPSAxXG4gICAgfSBlbHNlIGlmIChjb2RlUG9pbnQgPiAweEZGRkYpIHtcbiAgICAgIC8vIGVuY29kZSB0byB1dGYxNiAoc3Vycm9nYXRlIHBhaXIgZGFuY2UpXG4gICAgICBjb2RlUG9pbnQgLT0gMHgxMDAwMFxuICAgICAgcmVzLnB1c2goY29kZVBvaW50ID4+PiAxMCAmIDB4M0ZGIHwgMHhEODAwKVxuICAgICAgY29kZVBvaW50ID0gMHhEQzAwIHwgY29kZVBvaW50ICYgMHgzRkZcbiAgICB9XG5cbiAgICByZXMucHVzaChjb2RlUG9pbnQpXG4gICAgaSArPSBieXRlc1BlclNlcXVlbmNlXG4gIH1cblxuICByZXR1cm4gZGVjb2RlQ29kZVBvaW50c0FycmF5KHJlcylcbn1cblxuLy8gQmFzZWQgb24gaHR0cDovL3N0YWNrb3ZlcmZsb3cuY29tL2EvMjI3NDcyNzIvNjgwNzQyLCB0aGUgYnJvd3NlciB3aXRoXG4vLyB0aGUgbG93ZXN0IGxpbWl0IGlzIENocm9tZSwgd2l0aCAweDEwMDAwIGFyZ3MuXG4vLyBXZSBnbyAxIG1hZ25pdHVkZSBsZXNzLCBmb3Igc2FmZXR5XG52YXIgTUFYX0FSR1VNRU5UU19MRU5HVEggPSAweDEwMDBcblxuZnVuY3Rpb24gZGVjb2RlQ29kZVBvaW50c0FycmF5IChjb2RlUG9pbnRzKSB7XG4gIHZhciBsZW4gPSBjb2RlUG9pbnRzLmxlbmd0aFxuICBpZiAobGVuIDw9IE1BWF9BUkdVTUVOVFNfTEVOR1RIKSB7XG4gICAgcmV0dXJuIFN0cmluZy5mcm9tQ2hhckNvZGUuYXBwbHkoU3RyaW5nLCBjb2RlUG9pbnRzKSAvLyBhdm9pZCBleHRyYSBzbGljZSgpXG4gIH1cblxuICAvLyBEZWNvZGUgaW4gY2h1bmtzIHRvIGF2b2lkIFwiY2FsbCBzdGFjayBzaXplIGV4Y2VlZGVkXCIuXG4gIHZhciByZXMgPSAnJ1xuICB2YXIgaSA9IDBcbiAgd2hpbGUgKGkgPCBsZW4pIHtcbiAgICByZXMgKz0gU3RyaW5nLmZyb21DaGFyQ29kZS5hcHBseShcbiAgICAgIFN0cmluZyxcbiAgICAgIGNvZGVQb2ludHMuc2xpY2UoaSwgaSArPSBNQVhfQVJHVU1FTlRTX0xFTkdUSClcbiAgICApXG4gIH1cbiAgcmV0dXJuIHJlc1xufVxuXG5mdW5jdGlvbiBhc2NpaVNsaWNlIChidWYsIHN0YXJ0LCBlbmQpIHtcbiAgdmFyIHJldCA9ICcnXG4gIGVuZCA9IE1hdGgubWluKGJ1Zi5sZW5ndGgsIGVuZClcblxuICBmb3IgKHZhciBpID0gc3RhcnQ7IGkgPCBlbmQ7ICsraSkge1xuICAgIHJldCArPSBTdHJpbmcuZnJvbUNoYXJDb2RlKGJ1ZltpXSAmIDB4N0YpXG4gIH1cbiAgcmV0dXJuIHJldFxufVxuXG5mdW5jdGlvbiBiaW5hcnlTbGljZSAoYnVmLCBzdGFydCwgZW5kKSB7XG4gIHZhciByZXQgPSAnJ1xuICBlbmQgPSBNYXRoLm1pbihidWYubGVuZ3RoLCBlbmQpXG5cbiAgZm9yICh2YXIgaSA9IHN0YXJ0OyBpIDwgZW5kOyArK2kpIHtcbiAgICByZXQgKz0gU3RyaW5nLmZyb21DaGFyQ29kZShidWZbaV0pXG4gIH1cbiAgcmV0dXJuIHJldFxufVxuXG5mdW5jdGlvbiBoZXhTbGljZSAoYnVmLCBzdGFydCwgZW5kKSB7XG4gIHZhciBsZW4gPSBidWYubGVuZ3RoXG5cbiAgaWYgKCFzdGFydCB8fCBzdGFydCA8IDApIHN0YXJ0ID0gMFxuICBpZiAoIWVuZCB8fCBlbmQgPCAwIHx8IGVuZCA+IGxlbikgZW5kID0gbGVuXG5cbiAgdmFyIG91dCA9ICcnXG4gIGZvciAodmFyIGkgPSBzdGFydDsgaSA8IGVuZDsgKytpKSB7XG4gICAgb3V0ICs9IHRvSGV4KGJ1ZltpXSlcbiAgfVxuICByZXR1cm4gb3V0XG59XG5cbmZ1bmN0aW9uIHV0ZjE2bGVTbGljZSAoYnVmLCBzdGFydCwgZW5kKSB7XG4gIHZhciBieXRlcyA9IGJ1Zi5zbGljZShzdGFydCwgZW5kKVxuICB2YXIgcmVzID0gJydcbiAgZm9yICh2YXIgaSA9IDA7IGkgPCBieXRlcy5sZW5ndGg7IGkgKz0gMikge1xuICAgIHJlcyArPSBTdHJpbmcuZnJvbUNoYXJDb2RlKGJ5dGVzW2ldICsgYnl0ZXNbaSArIDFdICogMjU2KVxuICB9XG4gIHJldHVybiByZXNcbn1cblxuQnVmZmVyLnByb3RvdHlwZS5zbGljZSA9IGZ1bmN0aW9uIHNsaWNlIChzdGFydCwgZW5kKSB7XG4gIHZhciBsZW4gPSB0aGlzLmxlbmd0aFxuICBzdGFydCA9IH5+c3RhcnRcbiAgZW5kID0gZW5kID09PSB1bmRlZmluZWQgPyBsZW4gOiB+fmVuZFxuXG4gIGlmIChzdGFydCA8IDApIHtcbiAgICBzdGFydCArPSBsZW5cbiAgICBpZiAoc3RhcnQgPCAwKSBzdGFydCA9IDBcbiAgfSBlbHNlIGlmIChzdGFydCA+IGxlbikge1xuICAgIHN0YXJ0ID0gbGVuXG4gIH1cblxuICBpZiAoZW5kIDwgMCkge1xuICAgIGVuZCArPSBsZW5cbiAgICBpZiAoZW5kIDwgMCkgZW5kID0gMFxuICB9IGVsc2UgaWYgKGVuZCA+IGxlbikge1xuICAgIGVuZCA9IGxlblxuICB9XG5cbiAgaWYgKGVuZCA8IHN0YXJ0KSBlbmQgPSBzdGFydFxuXG4gIHZhciBuZXdCdWZcbiAgaWYgKEJ1ZmZlci5UWVBFRF9BUlJBWV9TVVBQT1JUKSB7XG4gICAgbmV3QnVmID0gdGhpcy5zdWJhcnJheShzdGFydCwgZW5kKVxuICAgIG5ld0J1Zi5fX3Byb3RvX18gPSBCdWZmZXIucHJvdG90eXBlXG4gIH0gZWxzZSB7XG4gICAgdmFyIHNsaWNlTGVuID0gZW5kIC0gc3RhcnRcbiAgICBuZXdCdWYgPSBuZXcgQnVmZmVyKHNsaWNlTGVuLCB1bmRlZmluZWQpXG4gICAgZm9yICh2YXIgaSA9IDA7IGkgPCBzbGljZUxlbjsgKytpKSB7XG4gICAgICBuZXdCdWZbaV0gPSB0aGlzW2kgKyBzdGFydF1cbiAgICB9XG4gIH1cblxuICByZXR1cm4gbmV3QnVmXG59XG5cbi8qXG4gKiBOZWVkIHRvIG1ha2Ugc3VyZSB0aGF0IGJ1ZmZlciBpc24ndCB0cnlpbmcgdG8gd3JpdGUgb3V0IG9mIGJvdW5kcy5cbiAqL1xuZnVuY3Rpb24gY2hlY2tPZmZzZXQgKG9mZnNldCwgZXh0LCBsZW5ndGgpIHtcbiAgaWYgKChvZmZzZXQgJSAxKSAhPT0gMCB8fCBvZmZzZXQgPCAwKSB0aHJvdyBuZXcgUmFuZ2VFcnJvcignb2Zmc2V0IGlzIG5vdCB1aW50JylcbiAgaWYgKG9mZnNldCArIGV4dCA+IGxlbmd0aCkgdGhyb3cgbmV3IFJhbmdlRXJyb3IoJ1RyeWluZyB0byBhY2Nlc3MgYmV5b25kIGJ1ZmZlciBsZW5ndGgnKVxufVxuXG5CdWZmZXIucHJvdG90eXBlLnJlYWRVSW50TEUgPSBmdW5jdGlvbiByZWFkVUludExFIChvZmZzZXQsIGJ5dGVMZW5ndGgsIG5vQXNzZXJ0KSB7XG4gIG9mZnNldCA9IG9mZnNldCB8IDBcbiAgYnl0ZUxlbmd0aCA9IGJ5dGVMZW5ndGggfCAwXG4gIGlmICghbm9Bc3NlcnQpIGNoZWNrT2Zmc2V0KG9mZnNldCwgYnl0ZUxlbmd0aCwgdGhpcy5sZW5ndGgpXG5cbiAgdmFyIHZhbCA9IHRoaXNbb2Zmc2V0XVxuICB2YXIgbXVsID0gMVxuICB2YXIgaSA9IDBcbiAgd2hpbGUgKCsraSA8IGJ5dGVMZW5ndGggJiYgKG11bCAqPSAweDEwMCkpIHtcbiAgICB2YWwgKz0gdGhpc1tvZmZzZXQgKyBpXSAqIG11bFxuICB9XG5cbiAgcmV0dXJuIHZhbFxufVxuXG5CdWZmZXIucHJvdG90eXBlLnJlYWRVSW50QkUgPSBmdW5jdGlvbiByZWFkVUludEJFIChvZmZzZXQsIGJ5dGVMZW5ndGgsIG5vQXNzZXJ0KSB7XG4gIG9mZnNldCA9IG9mZnNldCB8IDBcbiAgYnl0ZUxlbmd0aCA9IGJ5dGVMZW5ndGggfCAwXG4gIGlmICghbm9Bc3NlcnQpIHtcbiAgICBjaGVja09mZnNldChvZmZzZXQsIGJ5dGVMZW5ndGgsIHRoaXMubGVuZ3RoKVxuICB9XG5cbiAgdmFyIHZhbCA9IHRoaXNbb2Zmc2V0ICsgLS1ieXRlTGVuZ3RoXVxuICB2YXIgbXVsID0gMVxuICB3aGlsZSAoYnl0ZUxlbmd0aCA+IDAgJiYgKG11bCAqPSAweDEwMCkpIHtcbiAgICB2YWwgKz0gdGhpc1tvZmZzZXQgKyAtLWJ5dGVMZW5ndGhdICogbXVsXG4gIH1cblxuICByZXR1cm4gdmFsXG59XG5cbkJ1ZmZlci5wcm90b3R5cGUucmVhZFVJbnQ4ID0gZnVuY3Rpb24gcmVhZFVJbnQ4IChvZmZzZXQsIG5vQXNzZXJ0KSB7XG4gIGlmICghbm9Bc3NlcnQpIGNoZWNrT2Zmc2V0KG9mZnNldCwgMSwgdGhpcy5sZW5ndGgpXG4gIHJldHVybiB0aGlzW29mZnNldF1cbn1cblxuQnVmZmVyLnByb3RvdHlwZS5yZWFkVUludDE2TEUgPSBmdW5jdGlvbiByZWFkVUludDE2TEUgKG9mZnNldCwgbm9Bc3NlcnQpIHtcbiAgaWYgKCFub0Fzc2VydCkgY2hlY2tPZmZzZXQob2Zmc2V0LCAyLCB0aGlzLmxlbmd0aClcbiAgcmV0dXJuIHRoaXNbb2Zmc2V0XSB8ICh0aGlzW29mZnNldCArIDFdIDw8IDgpXG59XG5cbkJ1ZmZlci5wcm90b3R5cGUucmVhZFVJbnQxNkJFID0gZnVuY3Rpb24gcmVhZFVJbnQxNkJFIChvZmZzZXQsIG5vQXNzZXJ0KSB7XG4gIGlmICghbm9Bc3NlcnQpIGNoZWNrT2Zmc2V0KG9mZnNldCwgMiwgdGhpcy5sZW5ndGgpXG4gIHJldHVybiAodGhpc1tvZmZzZXRdIDw8IDgpIHwgdGhpc1tvZmZzZXQgKyAxXVxufVxuXG5CdWZmZXIucHJvdG90eXBlLnJlYWRVSW50MzJMRSA9IGZ1bmN0aW9uIHJlYWRVSW50MzJMRSAob2Zmc2V0LCBub0Fzc2VydCkge1xuICBpZiAoIW5vQXNzZXJ0KSBjaGVja09mZnNldChvZmZzZXQsIDQsIHRoaXMubGVuZ3RoKVxuXG4gIHJldHVybiAoKHRoaXNbb2Zmc2V0XSkgfFxuICAgICAgKHRoaXNbb2Zmc2V0ICsgMV0gPDwgOCkgfFxuICAgICAgKHRoaXNbb2Zmc2V0ICsgMl0gPDwgMTYpKSArXG4gICAgICAodGhpc1tvZmZzZXQgKyAzXSAqIDB4MTAwMDAwMClcbn1cblxuQnVmZmVyLnByb3RvdHlwZS5yZWFkVUludDMyQkUgPSBmdW5jdGlvbiByZWFkVUludDMyQkUgKG9mZnNldCwgbm9Bc3NlcnQpIHtcbiAgaWYgKCFub0Fzc2VydCkgY2hlY2tPZmZzZXQob2Zmc2V0LCA0LCB0aGlzLmxlbmd0aClcblxuICByZXR1cm4gKHRoaXNbb2Zmc2V0XSAqIDB4MTAwMDAwMCkgK1xuICAgICgodGhpc1tvZmZzZXQgKyAxXSA8PCAxNikgfFxuICAgICh0aGlzW29mZnNldCArIDJdIDw8IDgpIHxcbiAgICB0aGlzW29mZnNldCArIDNdKVxufVxuXG5CdWZmZXIucHJvdG90eXBlLnJlYWRJbnRMRSA9IGZ1bmN0aW9uIHJlYWRJbnRMRSAob2Zmc2V0LCBieXRlTGVuZ3RoLCBub0Fzc2VydCkge1xuICBvZmZzZXQgPSBvZmZzZXQgfCAwXG4gIGJ5dGVMZW5ndGggPSBieXRlTGVuZ3RoIHwgMFxuICBpZiAoIW5vQXNzZXJ0KSBjaGVja09mZnNldChvZmZzZXQsIGJ5dGVMZW5ndGgsIHRoaXMubGVuZ3RoKVxuXG4gIHZhciB2YWwgPSB0aGlzW29mZnNldF1cbiAgdmFyIG11bCA9IDFcbiAgdmFyIGkgPSAwXG4gIHdoaWxlICgrK2kgPCBieXRlTGVuZ3RoICYmIChtdWwgKj0gMHgxMDApKSB7XG4gICAgdmFsICs9IHRoaXNbb2Zmc2V0ICsgaV0gKiBtdWxcbiAgfVxuICBtdWwgKj0gMHg4MFxuXG4gIGlmICh2YWwgPj0gbXVsKSB2YWwgLT0gTWF0aC5wb3coMiwgOCAqIGJ5dGVMZW5ndGgpXG5cbiAgcmV0dXJuIHZhbFxufVxuXG5CdWZmZXIucHJvdG90eXBlLnJlYWRJbnRCRSA9IGZ1bmN0aW9uIHJlYWRJbnRCRSAob2Zmc2V0LCBieXRlTGVuZ3RoLCBub0Fzc2VydCkge1xuICBvZmZzZXQgPSBvZmZzZXQgfCAwXG4gIGJ5dGVMZW5ndGggPSBieXRlTGVuZ3RoIHwgMFxuICBpZiAoIW5vQXNzZXJ0KSBjaGVja09mZnNldChvZmZzZXQsIGJ5dGVMZW5ndGgsIHRoaXMubGVuZ3RoKVxuXG4gIHZhciBpID0gYnl0ZUxlbmd0aFxuICB2YXIgbXVsID0gMVxuICB2YXIgdmFsID0gdGhpc1tvZmZzZXQgKyAtLWldXG4gIHdoaWxlIChpID4gMCAmJiAobXVsICo9IDB4MTAwKSkge1xuICAgIHZhbCArPSB0aGlzW29mZnNldCArIC0taV0gKiBtdWxcbiAgfVxuICBtdWwgKj0gMHg4MFxuXG4gIGlmICh2YWwgPj0gbXVsKSB2YWwgLT0gTWF0aC5wb3coMiwgOCAqIGJ5dGVMZW5ndGgpXG5cbiAgcmV0dXJuIHZhbFxufVxuXG5CdWZmZXIucHJvdG90eXBlLnJlYWRJbnQ4ID0gZnVuY3Rpb24gcmVhZEludDggKG9mZnNldCwgbm9Bc3NlcnQpIHtcbiAgaWYgKCFub0Fzc2VydCkgY2hlY2tPZmZzZXQob2Zmc2V0LCAxLCB0aGlzLmxlbmd0aClcbiAgaWYgKCEodGhpc1tvZmZzZXRdICYgMHg4MCkpIHJldHVybiAodGhpc1tvZmZzZXRdKVxuICByZXR1cm4gKCgweGZmIC0gdGhpc1tvZmZzZXRdICsgMSkgKiAtMSlcbn1cblxuQnVmZmVyLnByb3RvdHlwZS5yZWFkSW50MTZMRSA9IGZ1bmN0aW9uIHJlYWRJbnQxNkxFIChvZmZzZXQsIG5vQXNzZXJ0KSB7XG4gIGlmICghbm9Bc3NlcnQpIGNoZWNrT2Zmc2V0KG9mZnNldCwgMiwgdGhpcy5sZW5ndGgpXG4gIHZhciB2YWwgPSB0aGlzW29mZnNldF0gfCAodGhpc1tvZmZzZXQgKyAxXSA8PCA4KVxuICByZXR1cm4gKHZhbCAmIDB4ODAwMCkgPyB2YWwgfCAweEZGRkYwMDAwIDogdmFsXG59XG5cbkJ1ZmZlci5wcm90b3R5cGUucmVhZEludDE2QkUgPSBmdW5jdGlvbiByZWFkSW50MTZCRSAob2Zmc2V0LCBub0Fzc2VydCkge1xuICBpZiAoIW5vQXNzZXJ0KSBjaGVja09mZnNldChvZmZzZXQsIDIsIHRoaXMubGVuZ3RoKVxuICB2YXIgdmFsID0gdGhpc1tvZmZzZXQgKyAxXSB8ICh0aGlzW29mZnNldF0gPDwgOClcbiAgcmV0dXJuICh2YWwgJiAweDgwMDApID8gdmFsIHwgMHhGRkZGMDAwMCA6IHZhbFxufVxuXG5CdWZmZXIucHJvdG90eXBlLnJlYWRJbnQzMkxFID0gZnVuY3Rpb24gcmVhZEludDMyTEUgKG9mZnNldCwgbm9Bc3NlcnQpIHtcbiAgaWYgKCFub0Fzc2VydCkgY2hlY2tPZmZzZXQob2Zmc2V0LCA0LCB0aGlzLmxlbmd0aClcblxuICByZXR1cm4gKHRoaXNbb2Zmc2V0XSkgfFxuICAgICh0aGlzW29mZnNldCArIDFdIDw8IDgpIHxcbiAgICAodGhpc1tvZmZzZXQgKyAyXSA8PCAxNikgfFxuICAgICh0aGlzW29mZnNldCArIDNdIDw8IDI0KVxufVxuXG5CdWZmZXIucHJvdG90eXBlLnJlYWRJbnQzMkJFID0gZnVuY3Rpb24gcmVhZEludDMyQkUgKG9mZnNldCwgbm9Bc3NlcnQpIHtcbiAgaWYgKCFub0Fzc2VydCkgY2hlY2tPZmZzZXQob2Zmc2V0LCA0LCB0aGlzLmxlbmd0aClcblxuICByZXR1cm4gKHRoaXNbb2Zmc2V0XSA8PCAyNCkgfFxuICAgICh0aGlzW29mZnNldCArIDFdIDw8IDE2KSB8XG4gICAgKHRoaXNbb2Zmc2V0ICsgMl0gPDwgOCkgfFxuICAgICh0aGlzW29mZnNldCArIDNdKVxufVxuXG5CdWZmZXIucHJvdG90eXBlLnJlYWRGbG9hdExFID0gZnVuY3Rpb24gcmVhZEZsb2F0TEUgKG9mZnNldCwgbm9Bc3NlcnQpIHtcbiAgaWYgKCFub0Fzc2VydCkgY2hlY2tPZmZzZXQob2Zmc2V0LCA0LCB0aGlzLmxlbmd0aClcbiAgcmV0dXJuIGllZWU3NTQucmVhZCh0aGlzLCBvZmZzZXQsIHRydWUsIDIzLCA0KVxufVxuXG5CdWZmZXIucHJvdG90eXBlLnJlYWRGbG9hdEJFID0gZnVuY3Rpb24gcmVhZEZsb2F0QkUgKG9mZnNldCwgbm9Bc3NlcnQpIHtcbiAgaWYgKCFub0Fzc2VydCkgY2hlY2tPZmZzZXQob2Zmc2V0LCA0LCB0aGlzLmxlbmd0aClcbiAgcmV0dXJuIGllZWU3NTQucmVhZCh0aGlzLCBvZmZzZXQsIGZhbHNlLCAyMywgNClcbn1cblxuQnVmZmVyLnByb3RvdHlwZS5yZWFkRG91YmxlTEUgPSBmdW5jdGlvbiByZWFkRG91YmxlTEUgKG9mZnNldCwgbm9Bc3NlcnQpIHtcbiAgaWYgKCFub0Fzc2VydCkgY2hlY2tPZmZzZXQob2Zmc2V0LCA4LCB0aGlzLmxlbmd0aClcbiAgcmV0dXJuIGllZWU3NTQucmVhZCh0aGlzLCBvZmZzZXQsIHRydWUsIDUyLCA4KVxufVxuXG5CdWZmZXIucHJvdG90eXBlLnJlYWREb3VibGVCRSA9IGZ1bmN0aW9uIHJlYWREb3VibGVCRSAob2Zmc2V0LCBub0Fzc2VydCkge1xuICBpZiAoIW5vQXNzZXJ0KSBjaGVja09mZnNldChvZmZzZXQsIDgsIHRoaXMubGVuZ3RoKVxuICByZXR1cm4gaWVlZTc1NC5yZWFkKHRoaXMsIG9mZnNldCwgZmFsc2UsIDUyLCA4KVxufVxuXG5mdW5jdGlvbiBjaGVja0ludCAoYnVmLCB2YWx1ZSwgb2Zmc2V0LCBleHQsIG1heCwgbWluKSB7XG4gIGlmICghQnVmZmVyLmlzQnVmZmVyKGJ1ZikpIHRocm93IG5ldyBUeXBlRXJyb3IoJ1wiYnVmZmVyXCIgYXJndW1lbnQgbXVzdCBiZSBhIEJ1ZmZlciBpbnN0YW5jZScpXG4gIGlmICh2YWx1ZSA+IG1heCB8fCB2YWx1ZSA8IG1pbikgdGhyb3cgbmV3IFJhbmdlRXJyb3IoJ1widmFsdWVcIiBhcmd1bWVudCBpcyBvdXQgb2YgYm91bmRzJylcbiAgaWYgKG9mZnNldCArIGV4dCA+IGJ1Zi5sZW5ndGgpIHRocm93IG5ldyBSYW5nZUVycm9yKCdJbmRleCBvdXQgb2YgcmFuZ2UnKVxufVxuXG5CdWZmZXIucHJvdG90eXBlLndyaXRlVUludExFID0gZnVuY3Rpb24gd3JpdGVVSW50TEUgKHZhbHVlLCBvZmZzZXQsIGJ5dGVMZW5ndGgsIG5vQXNzZXJ0KSB7XG4gIHZhbHVlID0gK3ZhbHVlXG4gIG9mZnNldCA9IG9mZnNldCB8IDBcbiAgYnl0ZUxlbmd0aCA9IGJ5dGVMZW5ndGggfCAwXG4gIGlmICghbm9Bc3NlcnQpIHtcbiAgICB2YXIgbWF4Qnl0ZXMgPSBNYXRoLnBvdygyLCA4ICogYnl0ZUxlbmd0aCkgLSAxXG4gICAgY2hlY2tJbnQodGhpcywgdmFsdWUsIG9mZnNldCwgYnl0ZUxlbmd0aCwgbWF4Qnl0ZXMsIDApXG4gIH1cblxuICB2YXIgbXVsID0gMVxuICB2YXIgaSA9IDBcbiAgdGhpc1tvZmZzZXRdID0gdmFsdWUgJiAweEZGXG4gIHdoaWxlICgrK2kgPCBieXRlTGVuZ3RoICYmIChtdWwgKj0gMHgxMDApKSB7XG4gICAgdGhpc1tvZmZzZXQgKyBpXSA9ICh2YWx1ZSAvIG11bCkgJiAweEZGXG4gIH1cblxuICByZXR1cm4gb2Zmc2V0ICsgYnl0ZUxlbmd0aFxufVxuXG5CdWZmZXIucHJvdG90eXBlLndyaXRlVUludEJFID0gZnVuY3Rpb24gd3JpdGVVSW50QkUgKHZhbHVlLCBvZmZzZXQsIGJ5dGVMZW5ndGgsIG5vQXNzZXJ0KSB7XG4gIHZhbHVlID0gK3ZhbHVlXG4gIG9mZnNldCA9IG9mZnNldCB8IDBcbiAgYnl0ZUxlbmd0aCA9IGJ5dGVMZW5ndGggfCAwXG4gIGlmICghbm9Bc3NlcnQpIHtcbiAgICB2YXIgbWF4Qnl0ZXMgPSBNYXRoLnBvdygyLCA4ICogYnl0ZUxlbmd0aCkgLSAxXG4gICAgY2hlY2tJbnQodGhpcywgdmFsdWUsIG9mZnNldCwgYnl0ZUxlbmd0aCwgbWF4Qnl0ZXMsIDApXG4gIH1cblxuICB2YXIgaSA9IGJ5dGVMZW5ndGggLSAxXG4gIHZhciBtdWwgPSAxXG4gIHRoaXNbb2Zmc2V0ICsgaV0gPSB2YWx1ZSAmIDB4RkZcbiAgd2hpbGUgKC0taSA+PSAwICYmIChtdWwgKj0gMHgxMDApKSB7XG4gICAgdGhpc1tvZmZzZXQgKyBpXSA9ICh2YWx1ZSAvIG11bCkgJiAweEZGXG4gIH1cblxuICByZXR1cm4gb2Zmc2V0ICsgYnl0ZUxlbmd0aFxufVxuXG5CdWZmZXIucHJvdG90eXBlLndyaXRlVUludDggPSBmdW5jdGlvbiB3cml0ZVVJbnQ4ICh2YWx1ZSwgb2Zmc2V0LCBub0Fzc2VydCkge1xuICB2YWx1ZSA9ICt2YWx1ZVxuICBvZmZzZXQgPSBvZmZzZXQgfCAwXG4gIGlmICghbm9Bc3NlcnQpIGNoZWNrSW50KHRoaXMsIHZhbHVlLCBvZmZzZXQsIDEsIDB4ZmYsIDApXG4gIGlmICghQnVmZmVyLlRZUEVEX0FSUkFZX1NVUFBPUlQpIHZhbHVlID0gTWF0aC5mbG9vcih2YWx1ZSlcbiAgdGhpc1tvZmZzZXRdID0gKHZhbHVlICYgMHhmZilcbiAgcmV0dXJuIG9mZnNldCArIDFcbn1cblxuZnVuY3Rpb24gb2JqZWN0V3JpdGVVSW50MTYgKGJ1ZiwgdmFsdWUsIG9mZnNldCwgbGl0dGxlRW5kaWFuKSB7XG4gIGlmICh2YWx1ZSA8IDApIHZhbHVlID0gMHhmZmZmICsgdmFsdWUgKyAxXG4gIGZvciAodmFyIGkgPSAwLCBqID0gTWF0aC5taW4oYnVmLmxlbmd0aCAtIG9mZnNldCwgMik7IGkgPCBqOyArK2kpIHtcbiAgICBidWZbb2Zmc2V0ICsgaV0gPSAodmFsdWUgJiAoMHhmZiA8PCAoOCAqIChsaXR0bGVFbmRpYW4gPyBpIDogMSAtIGkpKSkpID4+PlxuICAgICAgKGxpdHRsZUVuZGlhbiA/IGkgOiAxIC0gaSkgKiA4XG4gIH1cbn1cblxuQnVmZmVyLnByb3RvdHlwZS53cml0ZVVJbnQxNkxFID0gZnVuY3Rpb24gd3JpdGVVSW50MTZMRSAodmFsdWUsIG9mZnNldCwgbm9Bc3NlcnQpIHtcbiAgdmFsdWUgPSArdmFsdWVcbiAgb2Zmc2V0ID0gb2Zmc2V0IHwgMFxuICBpZiAoIW5vQXNzZXJ0KSBjaGVja0ludCh0aGlzLCB2YWx1ZSwgb2Zmc2V0LCAyLCAweGZmZmYsIDApXG4gIGlmIChCdWZmZXIuVFlQRURfQVJSQVlfU1VQUE9SVCkge1xuICAgIHRoaXNbb2Zmc2V0XSA9ICh2YWx1ZSAmIDB4ZmYpXG4gICAgdGhpc1tvZmZzZXQgKyAxXSA9ICh2YWx1ZSA+Pj4gOClcbiAgfSBlbHNlIHtcbiAgICBvYmplY3RXcml0ZVVJbnQxNih0aGlzLCB2YWx1ZSwgb2Zmc2V0LCB0cnVlKVxuICB9XG4gIHJldHVybiBvZmZzZXQgKyAyXG59XG5cbkJ1ZmZlci5wcm90b3R5cGUud3JpdGVVSW50MTZCRSA9IGZ1bmN0aW9uIHdyaXRlVUludDE2QkUgKHZhbHVlLCBvZmZzZXQsIG5vQXNzZXJ0KSB7XG4gIHZhbHVlID0gK3ZhbHVlXG4gIG9mZnNldCA9IG9mZnNldCB8IDBcbiAgaWYgKCFub0Fzc2VydCkgY2hlY2tJbnQodGhpcywgdmFsdWUsIG9mZnNldCwgMiwgMHhmZmZmLCAwKVxuICBpZiAoQnVmZmVyLlRZUEVEX0FSUkFZX1NVUFBPUlQpIHtcbiAgICB0aGlzW29mZnNldF0gPSAodmFsdWUgPj4+IDgpXG4gICAgdGhpc1tvZmZzZXQgKyAxXSA9ICh2YWx1ZSAmIDB4ZmYpXG4gIH0gZWxzZSB7XG4gICAgb2JqZWN0V3JpdGVVSW50MTYodGhpcywgdmFsdWUsIG9mZnNldCwgZmFsc2UpXG4gIH1cbiAgcmV0dXJuIG9mZnNldCArIDJcbn1cblxuZnVuY3Rpb24gb2JqZWN0V3JpdGVVSW50MzIgKGJ1ZiwgdmFsdWUsIG9mZnNldCwgbGl0dGxlRW5kaWFuKSB7XG4gIGlmICh2YWx1ZSA8IDApIHZhbHVlID0gMHhmZmZmZmZmZiArIHZhbHVlICsgMVxuICBmb3IgKHZhciBpID0gMCwgaiA9IE1hdGgubWluKGJ1Zi5sZW5ndGggLSBvZmZzZXQsIDQpOyBpIDwgajsgKytpKSB7XG4gICAgYnVmW29mZnNldCArIGldID0gKHZhbHVlID4+PiAobGl0dGxlRW5kaWFuID8gaSA6IDMgLSBpKSAqIDgpICYgMHhmZlxuICB9XG59XG5cbkJ1ZmZlci5wcm90b3R5cGUud3JpdGVVSW50MzJMRSA9IGZ1bmN0aW9uIHdyaXRlVUludDMyTEUgKHZhbHVlLCBvZmZzZXQsIG5vQXNzZXJ0KSB7XG4gIHZhbHVlID0gK3ZhbHVlXG4gIG9mZnNldCA9IG9mZnNldCB8IDBcbiAgaWYgKCFub0Fzc2VydCkgY2hlY2tJbnQodGhpcywgdmFsdWUsIG9mZnNldCwgNCwgMHhmZmZmZmZmZiwgMClcbiAgaWYgKEJ1ZmZlci5UWVBFRF9BUlJBWV9TVVBQT1JUKSB7XG4gICAgdGhpc1tvZmZzZXQgKyAzXSA9ICh2YWx1ZSA+Pj4gMjQpXG4gICAgdGhpc1tvZmZzZXQgKyAyXSA9ICh2YWx1ZSA+Pj4gMTYpXG4gICAgdGhpc1tvZmZzZXQgKyAxXSA9ICh2YWx1ZSA+Pj4gOClcbiAgICB0aGlzW29mZnNldF0gPSAodmFsdWUgJiAweGZmKVxuICB9IGVsc2Uge1xuICAgIG9iamVjdFdyaXRlVUludDMyKHRoaXMsIHZhbHVlLCBvZmZzZXQsIHRydWUpXG4gIH1cbiAgcmV0dXJuIG9mZnNldCArIDRcbn1cblxuQnVmZmVyLnByb3RvdHlwZS53cml0ZVVJbnQzMkJFID0gZnVuY3Rpb24gd3JpdGVVSW50MzJCRSAodmFsdWUsIG9mZnNldCwgbm9Bc3NlcnQpIHtcbiAgdmFsdWUgPSArdmFsdWVcbiAgb2Zmc2V0ID0gb2Zmc2V0IHwgMFxuICBpZiAoIW5vQXNzZXJ0KSBjaGVja0ludCh0aGlzLCB2YWx1ZSwgb2Zmc2V0LCA0LCAweGZmZmZmZmZmLCAwKVxuICBpZiAoQnVmZmVyLlRZUEVEX0FSUkFZX1NVUFBPUlQpIHtcbiAgICB0aGlzW29mZnNldF0gPSAodmFsdWUgPj4+IDI0KVxuICAgIHRoaXNbb2Zmc2V0ICsgMV0gPSAodmFsdWUgPj4+IDE2KVxuICAgIHRoaXNbb2Zmc2V0ICsgMl0gPSAodmFsdWUgPj4+IDgpXG4gICAgdGhpc1tvZmZzZXQgKyAzXSA9ICh2YWx1ZSAmIDB4ZmYpXG4gIH0gZWxzZSB7XG4gICAgb2JqZWN0V3JpdGVVSW50MzIodGhpcywgdmFsdWUsIG9mZnNldCwgZmFsc2UpXG4gIH1cbiAgcmV0dXJuIG9mZnNldCArIDRcbn1cblxuQnVmZmVyLnByb3RvdHlwZS53cml0ZUludExFID0gZnVuY3Rpb24gd3JpdGVJbnRMRSAodmFsdWUsIG9mZnNldCwgYnl0ZUxlbmd0aCwgbm9Bc3NlcnQpIHtcbiAgdmFsdWUgPSArdmFsdWVcbiAgb2Zmc2V0ID0gb2Zmc2V0IHwgMFxuICBpZiAoIW5vQXNzZXJ0KSB7XG4gICAgdmFyIGxpbWl0ID0gTWF0aC5wb3coMiwgOCAqIGJ5dGVMZW5ndGggLSAxKVxuXG4gICAgY2hlY2tJbnQodGhpcywgdmFsdWUsIG9mZnNldCwgYnl0ZUxlbmd0aCwgbGltaXQgLSAxLCAtbGltaXQpXG4gIH1cblxuICB2YXIgaSA9IDBcbiAgdmFyIG11bCA9IDFcbiAgdmFyIHN1YiA9IDBcbiAgdGhpc1tvZmZzZXRdID0gdmFsdWUgJiAweEZGXG4gIHdoaWxlICgrK2kgPCBieXRlTGVuZ3RoICYmIChtdWwgKj0gMHgxMDApKSB7XG4gICAgaWYgKHZhbHVlIDwgMCAmJiBzdWIgPT09IDAgJiYgdGhpc1tvZmZzZXQgKyBpIC0gMV0gIT09IDApIHtcbiAgICAgIHN1YiA9IDFcbiAgICB9XG4gICAgdGhpc1tvZmZzZXQgKyBpXSA9ICgodmFsdWUgLyBtdWwpID4+IDApIC0gc3ViICYgMHhGRlxuICB9XG5cbiAgcmV0dXJuIG9mZnNldCArIGJ5dGVMZW5ndGhcbn1cblxuQnVmZmVyLnByb3RvdHlwZS53cml0ZUludEJFID0gZnVuY3Rpb24gd3JpdGVJbnRCRSAodmFsdWUsIG9mZnNldCwgYnl0ZUxlbmd0aCwgbm9Bc3NlcnQpIHtcbiAgdmFsdWUgPSArdmFsdWVcbiAgb2Zmc2V0ID0gb2Zmc2V0IHwgMFxuICBpZiAoIW5vQXNzZXJ0KSB7XG4gICAgdmFyIGxpbWl0ID0gTWF0aC5wb3coMiwgOCAqIGJ5dGVMZW5ndGggLSAxKVxuXG4gICAgY2hlY2tJbnQodGhpcywgdmFsdWUsIG9mZnNldCwgYnl0ZUxlbmd0aCwgbGltaXQgLSAxLCAtbGltaXQpXG4gIH1cblxuICB2YXIgaSA9IGJ5dGVMZW5ndGggLSAxXG4gIHZhciBtdWwgPSAxXG4gIHZhciBzdWIgPSAwXG4gIHRoaXNbb2Zmc2V0ICsgaV0gPSB2YWx1ZSAmIDB4RkZcbiAgd2hpbGUgKC0taSA+PSAwICYmIChtdWwgKj0gMHgxMDApKSB7XG4gICAgaWYgKHZhbHVlIDwgMCAmJiBzdWIgPT09IDAgJiYgdGhpc1tvZmZzZXQgKyBpICsgMV0gIT09IDApIHtcbiAgICAgIHN1YiA9IDFcbiAgICB9XG4gICAgdGhpc1tvZmZzZXQgKyBpXSA9ICgodmFsdWUgLyBtdWwpID4+IDApIC0gc3ViICYgMHhGRlxuICB9XG5cbiAgcmV0dXJuIG9mZnNldCArIGJ5dGVMZW5ndGhcbn1cblxuQnVmZmVyLnByb3RvdHlwZS53cml0ZUludDggPSBmdW5jdGlvbiB3cml0ZUludDggKHZhbHVlLCBvZmZzZXQsIG5vQXNzZXJ0KSB7XG4gIHZhbHVlID0gK3ZhbHVlXG4gIG9mZnNldCA9IG9mZnNldCB8IDBcbiAgaWYgKCFub0Fzc2VydCkgY2hlY2tJbnQodGhpcywgdmFsdWUsIG9mZnNldCwgMSwgMHg3ZiwgLTB4ODApXG4gIGlmICghQnVmZmVyLlRZUEVEX0FSUkFZX1NVUFBPUlQpIHZhbHVlID0gTWF0aC5mbG9vcih2YWx1ZSlcbiAgaWYgKHZhbHVlIDwgMCkgdmFsdWUgPSAweGZmICsgdmFsdWUgKyAxXG4gIHRoaXNbb2Zmc2V0XSA9ICh2YWx1ZSAmIDB4ZmYpXG4gIHJldHVybiBvZmZzZXQgKyAxXG59XG5cbkJ1ZmZlci5wcm90b3R5cGUud3JpdGVJbnQxNkxFID0gZnVuY3Rpb24gd3JpdGVJbnQxNkxFICh2YWx1ZSwgb2Zmc2V0LCBub0Fzc2VydCkge1xuICB2YWx1ZSA9ICt2YWx1ZVxuICBvZmZzZXQgPSBvZmZzZXQgfCAwXG4gIGlmICghbm9Bc3NlcnQpIGNoZWNrSW50KHRoaXMsIHZhbHVlLCBvZmZzZXQsIDIsIDB4N2ZmZiwgLTB4ODAwMClcbiAgaWYgKEJ1ZmZlci5UWVBFRF9BUlJBWV9TVVBQT1JUKSB7XG4gICAgdGhpc1tvZmZzZXRdID0gKHZhbHVlICYgMHhmZilcbiAgICB0aGlzW29mZnNldCArIDFdID0gKHZhbHVlID4+PiA4KVxuICB9IGVsc2Uge1xuICAgIG9iamVjdFdyaXRlVUludDE2KHRoaXMsIHZhbHVlLCBvZmZzZXQsIHRydWUpXG4gIH1cbiAgcmV0dXJuIG9mZnNldCArIDJcbn1cblxuQnVmZmVyLnByb3RvdHlwZS53cml0ZUludDE2QkUgPSBmdW5jdGlvbiB3cml0ZUludDE2QkUgKHZhbHVlLCBvZmZzZXQsIG5vQXNzZXJ0KSB7XG4gIHZhbHVlID0gK3ZhbHVlXG4gIG9mZnNldCA9IG9mZnNldCB8IDBcbiAgaWYgKCFub0Fzc2VydCkgY2hlY2tJbnQodGhpcywgdmFsdWUsIG9mZnNldCwgMiwgMHg3ZmZmLCAtMHg4MDAwKVxuICBpZiAoQnVmZmVyLlRZUEVEX0FSUkFZX1NVUFBPUlQpIHtcbiAgICB0aGlzW29mZnNldF0gPSAodmFsdWUgPj4+IDgpXG4gICAgdGhpc1tvZmZzZXQgKyAxXSA9ICh2YWx1ZSAmIDB4ZmYpXG4gIH0gZWxzZSB7XG4gICAgb2JqZWN0V3JpdGVVSW50MTYodGhpcywgdmFsdWUsIG9mZnNldCwgZmFsc2UpXG4gIH1cbiAgcmV0dXJuIG9mZnNldCArIDJcbn1cblxuQnVmZmVyLnByb3RvdHlwZS53cml0ZUludDMyTEUgPSBmdW5jdGlvbiB3cml0ZUludDMyTEUgKHZhbHVlLCBvZmZzZXQsIG5vQXNzZXJ0KSB7XG4gIHZhbHVlID0gK3ZhbHVlXG4gIG9mZnNldCA9IG9mZnNldCB8IDBcbiAgaWYgKCFub0Fzc2VydCkgY2hlY2tJbnQodGhpcywgdmFsdWUsIG9mZnNldCwgNCwgMHg3ZmZmZmZmZiwgLTB4ODAwMDAwMDApXG4gIGlmIChCdWZmZXIuVFlQRURfQVJSQVlfU1VQUE9SVCkge1xuICAgIHRoaXNbb2Zmc2V0XSA9ICh2YWx1ZSAmIDB4ZmYpXG4gICAgdGhpc1tvZmZzZXQgKyAxXSA9ICh2YWx1ZSA+Pj4gOClcbiAgICB0aGlzW29mZnNldCArIDJdID0gKHZhbHVlID4+PiAxNilcbiAgICB0aGlzW29mZnNldCArIDNdID0gKHZhbHVlID4+PiAyNClcbiAgfSBlbHNlIHtcbiAgICBvYmplY3RXcml0ZVVJbnQzMih0aGlzLCB2YWx1ZSwgb2Zmc2V0LCB0cnVlKVxuICB9XG4gIHJldHVybiBvZmZzZXQgKyA0XG59XG5cbkJ1ZmZlci5wcm90b3R5cGUud3JpdGVJbnQzMkJFID0gZnVuY3Rpb24gd3JpdGVJbnQzMkJFICh2YWx1ZSwgb2Zmc2V0LCBub0Fzc2VydCkge1xuICB2YWx1ZSA9ICt2YWx1ZVxuICBvZmZzZXQgPSBvZmZzZXQgfCAwXG4gIGlmICghbm9Bc3NlcnQpIGNoZWNrSW50KHRoaXMsIHZhbHVlLCBvZmZzZXQsIDQsIDB4N2ZmZmZmZmYsIC0weDgwMDAwMDAwKVxuICBpZiAodmFsdWUgPCAwKSB2YWx1ZSA9IDB4ZmZmZmZmZmYgKyB2YWx1ZSArIDFcbiAgaWYgKEJ1ZmZlci5UWVBFRF9BUlJBWV9TVVBQT1JUKSB7XG4gICAgdGhpc1tvZmZzZXRdID0gKHZhbHVlID4+PiAyNClcbiAgICB0aGlzW29mZnNldCArIDFdID0gKHZhbHVlID4+PiAxNilcbiAgICB0aGlzW29mZnNldCArIDJdID0gKHZhbHVlID4+PiA4KVxuICAgIHRoaXNbb2Zmc2V0ICsgM10gPSAodmFsdWUgJiAweGZmKVxuICB9IGVsc2Uge1xuICAgIG9iamVjdFdyaXRlVUludDMyKHRoaXMsIHZhbHVlLCBvZmZzZXQsIGZhbHNlKVxuICB9XG4gIHJldHVybiBvZmZzZXQgKyA0XG59XG5cbmZ1bmN0aW9uIGNoZWNrSUVFRTc1NCAoYnVmLCB2YWx1ZSwgb2Zmc2V0LCBleHQsIG1heCwgbWluKSB7XG4gIGlmIChvZmZzZXQgKyBleHQgPiBidWYubGVuZ3RoKSB0aHJvdyBuZXcgUmFuZ2VFcnJvcignSW5kZXggb3V0IG9mIHJhbmdlJylcbiAgaWYgKG9mZnNldCA8IDApIHRocm93IG5ldyBSYW5nZUVycm9yKCdJbmRleCBvdXQgb2YgcmFuZ2UnKVxufVxuXG5mdW5jdGlvbiB3cml0ZUZsb2F0IChidWYsIHZhbHVlLCBvZmZzZXQsIGxpdHRsZUVuZGlhbiwgbm9Bc3NlcnQpIHtcbiAgaWYgKCFub0Fzc2VydCkge1xuICAgIGNoZWNrSUVFRTc1NChidWYsIHZhbHVlLCBvZmZzZXQsIDQsIDMuNDAyODIzNDY2Mzg1Mjg4NmUrMzgsIC0zLjQwMjgyMzQ2NjM4NTI4ODZlKzM4KVxuICB9XG4gIGllZWU3NTQud3JpdGUoYnVmLCB2YWx1ZSwgb2Zmc2V0LCBsaXR0bGVFbmRpYW4sIDIzLCA0KVxuICByZXR1cm4gb2Zmc2V0ICsgNFxufVxuXG5CdWZmZXIucHJvdG90eXBlLndyaXRlRmxvYXRMRSA9IGZ1bmN0aW9uIHdyaXRlRmxvYXRMRSAodmFsdWUsIG9mZnNldCwgbm9Bc3NlcnQpIHtcbiAgcmV0dXJuIHdyaXRlRmxvYXQodGhpcywgdmFsdWUsIG9mZnNldCwgdHJ1ZSwgbm9Bc3NlcnQpXG59XG5cbkJ1ZmZlci5wcm90b3R5cGUud3JpdGVGbG9hdEJFID0gZnVuY3Rpb24gd3JpdGVGbG9hdEJFICh2YWx1ZSwgb2Zmc2V0LCBub0Fzc2VydCkge1xuICByZXR1cm4gd3JpdGVGbG9hdCh0aGlzLCB2YWx1ZSwgb2Zmc2V0LCBmYWxzZSwgbm9Bc3NlcnQpXG59XG5cbmZ1bmN0aW9uIHdyaXRlRG91YmxlIChidWYsIHZhbHVlLCBvZmZzZXQsIGxpdHRsZUVuZGlhbiwgbm9Bc3NlcnQpIHtcbiAgaWYgKCFub0Fzc2VydCkge1xuICAgIGNoZWNrSUVFRTc1NChidWYsIHZhbHVlLCBvZmZzZXQsIDgsIDEuNzk3NjkzMTM0ODYyMzE1N0UrMzA4LCAtMS43OTc2OTMxMzQ4NjIzMTU3RSszMDgpXG4gIH1cbiAgaWVlZTc1NC53cml0ZShidWYsIHZhbHVlLCBvZmZzZXQsIGxpdHRsZUVuZGlhbiwgNTIsIDgpXG4gIHJldHVybiBvZmZzZXQgKyA4XG59XG5cbkJ1ZmZlci5wcm90b3R5cGUud3JpdGVEb3VibGVMRSA9IGZ1bmN0aW9uIHdyaXRlRG91YmxlTEUgKHZhbHVlLCBvZmZzZXQsIG5vQXNzZXJ0KSB7XG4gIHJldHVybiB3cml0ZURvdWJsZSh0aGlzLCB2YWx1ZSwgb2Zmc2V0LCB0cnVlLCBub0Fzc2VydClcbn1cblxuQnVmZmVyLnByb3RvdHlwZS53cml0ZURvdWJsZUJFID0gZnVuY3Rpb24gd3JpdGVEb3VibGVCRSAodmFsdWUsIG9mZnNldCwgbm9Bc3NlcnQpIHtcbiAgcmV0dXJuIHdyaXRlRG91YmxlKHRoaXMsIHZhbHVlLCBvZmZzZXQsIGZhbHNlLCBub0Fzc2VydClcbn1cblxuLy8gY29weSh0YXJnZXRCdWZmZXIsIHRhcmdldFN0YXJ0PTAsIHNvdXJjZVN0YXJ0PTAsIHNvdXJjZUVuZD1idWZmZXIubGVuZ3RoKVxuQnVmZmVyLnByb3RvdHlwZS5jb3B5ID0gZnVuY3Rpb24gY29weSAodGFyZ2V0LCB0YXJnZXRTdGFydCwgc3RhcnQsIGVuZCkge1xuICBpZiAoIXN0YXJ0KSBzdGFydCA9IDBcbiAgaWYgKCFlbmQgJiYgZW5kICE9PSAwKSBlbmQgPSB0aGlzLmxlbmd0aFxuICBpZiAodGFyZ2V0U3RhcnQgPj0gdGFyZ2V0Lmxlbmd0aCkgdGFyZ2V0U3RhcnQgPSB0YXJnZXQubGVuZ3RoXG4gIGlmICghdGFyZ2V0U3RhcnQpIHRhcmdldFN0YXJ0ID0gMFxuICBpZiAoZW5kID4gMCAmJiBlbmQgPCBzdGFydCkgZW5kID0gc3RhcnRcblxuICAvLyBDb3B5IDAgYnl0ZXM7IHdlJ3JlIGRvbmVcbiAgaWYgKGVuZCA9PT0gc3RhcnQpIHJldHVybiAwXG4gIGlmICh0YXJnZXQubGVuZ3RoID09PSAwIHx8IHRoaXMubGVuZ3RoID09PSAwKSByZXR1cm4gMFxuXG4gIC8vIEZhdGFsIGVycm9yIGNvbmRpdGlvbnNcbiAgaWYgKHRhcmdldFN0YXJ0IDwgMCkge1xuICAgIHRocm93IG5ldyBSYW5nZUVycm9yKCd0YXJnZXRTdGFydCBvdXQgb2YgYm91bmRzJylcbiAgfVxuICBpZiAoc3RhcnQgPCAwIHx8IHN0YXJ0ID49IHRoaXMubGVuZ3RoKSB0aHJvdyBuZXcgUmFuZ2VFcnJvcignc291cmNlU3RhcnQgb3V0IG9mIGJvdW5kcycpXG4gIGlmIChlbmQgPCAwKSB0aHJvdyBuZXcgUmFuZ2VFcnJvcignc291cmNlRW5kIG91dCBvZiBib3VuZHMnKVxuXG4gIC8vIEFyZSB3ZSBvb2I/XG4gIGlmIChlbmQgPiB0aGlzLmxlbmd0aCkgZW5kID0gdGhpcy5sZW5ndGhcbiAgaWYgKHRhcmdldC5sZW5ndGggLSB0YXJnZXRTdGFydCA8IGVuZCAtIHN0YXJ0KSB7XG4gICAgZW5kID0gdGFyZ2V0Lmxlbmd0aCAtIHRhcmdldFN0YXJ0ICsgc3RhcnRcbiAgfVxuXG4gIHZhciBsZW4gPSBlbmQgLSBzdGFydFxuICB2YXIgaVxuXG4gIGlmICh0aGlzID09PSB0YXJnZXQgJiYgc3RhcnQgPCB0YXJnZXRTdGFydCAmJiB0YXJnZXRTdGFydCA8IGVuZCkge1xuICAgIC8vIGRlc2NlbmRpbmcgY29weSBmcm9tIGVuZFxuICAgIGZvciAoaSA9IGxlbiAtIDE7IGkgPj0gMDsgLS1pKSB7XG4gICAgICB0YXJnZXRbaSArIHRhcmdldFN0YXJ0XSA9IHRoaXNbaSArIHN0YXJ0XVxuICAgIH1cbiAgfSBlbHNlIGlmIChsZW4gPCAxMDAwIHx8ICFCdWZmZXIuVFlQRURfQVJSQVlfU1VQUE9SVCkge1xuICAgIC8vIGFzY2VuZGluZyBjb3B5IGZyb20gc3RhcnRcbiAgICBmb3IgKGkgPSAwOyBpIDwgbGVuOyArK2kpIHtcbiAgICAgIHRhcmdldFtpICsgdGFyZ2V0U3RhcnRdID0gdGhpc1tpICsgc3RhcnRdXG4gICAgfVxuICB9IGVsc2Uge1xuICAgIFVpbnQ4QXJyYXkucHJvdG90eXBlLnNldC5jYWxsKFxuICAgICAgdGFyZ2V0LFxuICAgICAgdGhpcy5zdWJhcnJheShzdGFydCwgc3RhcnQgKyBsZW4pLFxuICAgICAgdGFyZ2V0U3RhcnRcbiAgICApXG4gIH1cblxuICByZXR1cm4gbGVuXG59XG5cbi8vIFVzYWdlOlxuLy8gICAgYnVmZmVyLmZpbGwobnVtYmVyWywgb2Zmc2V0WywgZW5kXV0pXG4vLyAgICBidWZmZXIuZmlsbChidWZmZXJbLCBvZmZzZXRbLCBlbmRdXSlcbi8vICAgIGJ1ZmZlci5maWxsKHN0cmluZ1ssIG9mZnNldFssIGVuZF1dWywgZW5jb2RpbmddKVxuQnVmZmVyLnByb3RvdHlwZS5maWxsID0gZnVuY3Rpb24gZmlsbCAodmFsLCBzdGFydCwgZW5kLCBlbmNvZGluZykge1xuICAvLyBIYW5kbGUgc3RyaW5nIGNhc2VzOlxuICBpZiAodHlwZW9mIHZhbCA9PT0gJ3N0cmluZycpIHtcbiAgICBpZiAodHlwZW9mIHN0YXJ0ID09PSAnc3RyaW5nJykge1xuICAgICAgZW5jb2RpbmcgPSBzdGFydFxuICAgICAgc3RhcnQgPSAwXG4gICAgICBlbmQgPSB0aGlzLmxlbmd0aFxuICAgIH0gZWxzZSBpZiAodHlwZW9mIGVuZCA9PT0gJ3N0cmluZycpIHtcbiAgICAgIGVuY29kaW5nID0gZW5kXG4gICAgICBlbmQgPSB0aGlzLmxlbmd0aFxuICAgIH1cbiAgICBpZiAodmFsLmxlbmd0aCA9PT0gMSkge1xuICAgICAgdmFyIGNvZGUgPSB2YWwuY2hhckNvZGVBdCgwKVxuICAgICAgaWYgKGNvZGUgPCAyNTYpIHtcbiAgICAgICAgdmFsID0gY29kZVxuICAgICAgfVxuICAgIH1cbiAgICBpZiAoZW5jb2RpbmcgIT09IHVuZGVmaW5lZCAmJiB0eXBlb2YgZW5jb2RpbmcgIT09ICdzdHJpbmcnKSB7XG4gICAgICB0aHJvdyBuZXcgVHlwZUVycm9yKCdlbmNvZGluZyBtdXN0IGJlIGEgc3RyaW5nJylcbiAgICB9XG4gICAgaWYgKHR5cGVvZiBlbmNvZGluZyA9PT0gJ3N0cmluZycgJiYgIUJ1ZmZlci5pc0VuY29kaW5nKGVuY29kaW5nKSkge1xuICAgICAgdGhyb3cgbmV3IFR5cGVFcnJvcignVW5rbm93biBlbmNvZGluZzogJyArIGVuY29kaW5nKVxuICAgIH1cbiAgfSBlbHNlIGlmICh0eXBlb2YgdmFsID09PSAnbnVtYmVyJykge1xuICAgIHZhbCA9IHZhbCAmIDI1NVxuICB9XG5cbiAgLy8gSW52YWxpZCByYW5nZXMgYXJlIG5vdCBzZXQgdG8gYSBkZWZhdWx0LCBzbyBjYW4gcmFuZ2UgY2hlY2sgZWFybHkuXG4gIGlmIChzdGFydCA8IDAgfHwgdGhpcy5sZW5ndGggPCBzdGFydCB8fCB0aGlzLmxlbmd0aCA8IGVuZCkge1xuICAgIHRocm93IG5ldyBSYW5nZUVycm9yKCdPdXQgb2YgcmFuZ2UgaW5kZXgnKVxuICB9XG5cbiAgaWYgKGVuZCA8PSBzdGFydCkge1xuICAgIHJldHVybiB0aGlzXG4gIH1cblxuICBzdGFydCA9IHN0YXJ0ID4+PiAwXG4gIGVuZCA9IGVuZCA9PT0gdW5kZWZpbmVkID8gdGhpcy5sZW5ndGggOiBlbmQgPj4+IDBcblxuICBpZiAoIXZhbCkgdmFsID0gMFxuXG4gIHZhciBpXG4gIGlmICh0eXBlb2YgdmFsID09PSAnbnVtYmVyJykge1xuICAgIGZvciAoaSA9IHN0YXJ0OyBpIDwgZW5kOyArK2kpIHtcbiAgICAgIHRoaXNbaV0gPSB2YWxcbiAgICB9XG4gIH0gZWxzZSB7XG4gICAgdmFyIGJ5dGVzID0gQnVmZmVyLmlzQnVmZmVyKHZhbClcbiAgICAgID8gdmFsXG4gICAgICA6IHV0ZjhUb0J5dGVzKG5ldyBCdWZmZXIodmFsLCBlbmNvZGluZykudG9TdHJpbmcoKSlcbiAgICB2YXIgbGVuID0gYnl0ZXMubGVuZ3RoXG4gICAgZm9yIChpID0gMDsgaSA8IGVuZCAtIHN0YXJ0OyArK2kpIHtcbiAgICAgIHRoaXNbaSArIHN0YXJ0XSA9IGJ5dGVzW2kgJSBsZW5dXG4gICAgfVxuICB9XG5cbiAgcmV0dXJuIHRoaXNcbn1cblxuLy8gSEVMUEVSIEZVTkNUSU9OU1xuLy8gPT09PT09PT09PT09PT09PVxuXG52YXIgSU5WQUxJRF9CQVNFNjRfUkUgPSAvW14rXFwvMC05QS1aYS16LV9dL2dcblxuZnVuY3Rpb24gYmFzZTY0Y2xlYW4gKHN0cikge1xuICAvLyBOb2RlIHN0cmlwcyBvdXQgaW52YWxpZCBjaGFyYWN0ZXJzIGxpa2UgXFxuIGFuZCBcXHQgZnJvbSB0aGUgc3RyaW5nLCBiYXNlNjQtanMgZG9lcyBub3RcbiAgc3RyID0gc3RyaW5ndHJpbShzdHIpLnJlcGxhY2UoSU5WQUxJRF9CQVNFNjRfUkUsICcnKVxuICAvLyBOb2RlIGNvbnZlcnRzIHN0cmluZ3Mgd2l0aCBsZW5ndGggPCAyIHRvICcnXG4gIGlmIChzdHIubGVuZ3RoIDwgMikgcmV0dXJuICcnXG4gIC8vIE5vZGUgYWxsb3dzIGZvciBub24tcGFkZGVkIGJhc2U2NCBzdHJpbmdzIChtaXNzaW5nIHRyYWlsaW5nID09PSksIGJhc2U2NC1qcyBkb2VzIG5vdFxuICB3aGlsZSAoc3RyLmxlbmd0aCAlIDQgIT09IDApIHtcbiAgICBzdHIgPSBzdHIgKyAnPSdcbiAgfVxuICByZXR1cm4gc3RyXG59XG5cbmZ1bmN0aW9uIHN0cmluZ3RyaW0gKHN0cikge1xuICBpZiAoc3RyLnRyaW0pIHJldHVybiBzdHIudHJpbSgpXG4gIHJldHVybiBzdHIucmVwbGFjZSgvXlxccyt8XFxzKyQvZywgJycpXG59XG5cbmZ1bmN0aW9uIHRvSGV4IChuKSB7XG4gIGlmIChuIDwgMTYpIHJldHVybiAnMCcgKyBuLnRvU3RyaW5nKDE2KVxuICByZXR1cm4gbi50b1N0cmluZygxNilcbn1cblxuZnVuY3Rpb24gdXRmOFRvQnl0ZXMgKHN0cmluZywgdW5pdHMpIHtcbiAgdW5pdHMgPSB1bml0cyB8fCBJbmZpbml0eVxuICB2YXIgY29kZVBvaW50XG4gIHZhciBsZW5ndGggPSBzdHJpbmcubGVuZ3RoXG4gIHZhciBsZWFkU3Vycm9nYXRlID0gbnVsbFxuICB2YXIgYnl0ZXMgPSBbXVxuXG4gIGZvciAodmFyIGkgPSAwOyBpIDwgbGVuZ3RoOyArK2kpIHtcbiAgICBjb2RlUG9pbnQgPSBzdHJpbmcuY2hhckNvZGVBdChpKVxuXG4gICAgLy8gaXMgc3Vycm9nYXRlIGNvbXBvbmVudFxuICAgIGlmIChjb2RlUG9pbnQgPiAweEQ3RkYgJiYgY29kZVBvaW50IDwgMHhFMDAwKSB7XG4gICAgICAvLyBsYXN0IGNoYXIgd2FzIGEgbGVhZFxuICAgICAgaWYgKCFsZWFkU3Vycm9nYXRlKSB7XG4gICAgICAgIC8vIG5vIGxlYWQgeWV0XG4gICAgICAgIGlmIChjb2RlUG9pbnQgPiAweERCRkYpIHtcbiAgICAgICAgICAvLyB1bmV4cGVjdGVkIHRyYWlsXG4gICAgICAgICAgaWYgKCh1bml0cyAtPSAzKSA+IC0xKSBieXRlcy5wdXNoKDB4RUYsIDB4QkYsIDB4QkQpXG4gICAgICAgICAgY29udGludWVcbiAgICAgICAgfSBlbHNlIGlmIChpICsgMSA9PT0gbGVuZ3RoKSB7XG4gICAgICAgICAgLy8gdW5wYWlyZWQgbGVhZFxuICAgICAgICAgIGlmICgodW5pdHMgLT0gMykgPiAtMSkgYnl0ZXMucHVzaCgweEVGLCAweEJGLCAweEJEKVxuICAgICAgICAgIGNvbnRpbnVlXG4gICAgICAgIH1cblxuICAgICAgICAvLyB2YWxpZCBsZWFkXG4gICAgICAgIGxlYWRTdXJyb2dhdGUgPSBjb2RlUG9pbnRcblxuICAgICAgICBjb250aW51ZVxuICAgICAgfVxuXG4gICAgICAvLyAyIGxlYWRzIGluIGEgcm93XG4gICAgICBpZiAoY29kZVBvaW50IDwgMHhEQzAwKSB7XG4gICAgICAgIGlmICgodW5pdHMgLT0gMykgPiAtMSkgYnl0ZXMucHVzaCgweEVGLCAweEJGLCAweEJEKVxuICAgICAgICBsZWFkU3Vycm9nYXRlID0gY29kZVBvaW50XG4gICAgICAgIGNvbnRpbnVlXG4gICAgICB9XG5cbiAgICAgIC8vIHZhbGlkIHN1cnJvZ2F0ZSBwYWlyXG4gICAgICBjb2RlUG9pbnQgPSAobGVhZFN1cnJvZ2F0ZSAtIDB4RDgwMCA8PCAxMCB8IGNvZGVQb2ludCAtIDB4REMwMCkgKyAweDEwMDAwXG4gICAgfSBlbHNlIGlmIChsZWFkU3Vycm9nYXRlKSB7XG4gICAgICAvLyB2YWxpZCBibXAgY2hhciwgYnV0IGxhc3QgY2hhciB3YXMgYSBsZWFkXG4gICAgICBpZiAoKHVuaXRzIC09IDMpID4gLTEpIGJ5dGVzLnB1c2goMHhFRiwgMHhCRiwgMHhCRClcbiAgICB9XG5cbiAgICBsZWFkU3Vycm9nYXRlID0gbnVsbFxuXG4gICAgLy8gZW5jb2RlIHV0ZjhcbiAgICBpZiAoY29kZVBvaW50IDwgMHg4MCkge1xuICAgICAgaWYgKCh1bml0cyAtPSAxKSA8IDApIGJyZWFrXG4gICAgICBieXRlcy5wdXNoKGNvZGVQb2ludClcbiAgICB9IGVsc2UgaWYgKGNvZGVQb2ludCA8IDB4ODAwKSB7XG4gICAgICBpZiAoKHVuaXRzIC09IDIpIDwgMCkgYnJlYWtcbiAgICAgIGJ5dGVzLnB1c2goXG4gICAgICAgIGNvZGVQb2ludCA+PiAweDYgfCAweEMwLFxuICAgICAgICBjb2RlUG9pbnQgJiAweDNGIHwgMHg4MFxuICAgICAgKVxuICAgIH0gZWxzZSBpZiAoY29kZVBvaW50IDwgMHgxMDAwMCkge1xuICAgICAgaWYgKCh1bml0cyAtPSAzKSA8IDApIGJyZWFrXG4gICAgICBieXRlcy5wdXNoKFxuICAgICAgICBjb2RlUG9pbnQgPj4gMHhDIHwgMHhFMCxcbiAgICAgICAgY29kZVBvaW50ID4+IDB4NiAmIDB4M0YgfCAweDgwLFxuICAgICAgICBjb2RlUG9pbnQgJiAweDNGIHwgMHg4MFxuICAgICAgKVxuICAgIH0gZWxzZSBpZiAoY29kZVBvaW50IDwgMHgxMTAwMDApIHtcbiAgICAgIGlmICgodW5pdHMgLT0gNCkgPCAwKSBicmVha1xuICAgICAgYnl0ZXMucHVzaChcbiAgICAgICAgY29kZVBvaW50ID4+IDB4MTIgfCAweEYwLFxuICAgICAgICBjb2RlUG9pbnQgPj4gMHhDICYgMHgzRiB8IDB4ODAsXG4gICAgICAgIGNvZGVQb2ludCA+PiAweDYgJiAweDNGIHwgMHg4MCxcbiAgICAgICAgY29kZVBvaW50ICYgMHgzRiB8IDB4ODBcbiAgICAgIClcbiAgICB9IGVsc2Uge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKCdJbnZhbGlkIGNvZGUgcG9pbnQnKVxuICAgIH1cbiAgfVxuXG4gIHJldHVybiBieXRlc1xufVxuXG5mdW5jdGlvbiBhc2NpaVRvQnl0ZXMgKHN0cikge1xuICB2YXIgYnl0ZUFycmF5ID0gW11cbiAgZm9yICh2YXIgaSA9IDA7IGkgPCBzdHIubGVuZ3RoOyArK2kpIHtcbiAgICAvLyBOb2RlJ3MgY29kZSBzZWVtcyB0byBiZSBkb2luZyB0aGlzIGFuZCBub3QgJiAweDdGLi5cbiAgICBieXRlQXJyYXkucHVzaChzdHIuY2hhckNvZGVBdChpKSAmIDB4RkYpXG4gIH1cbiAgcmV0dXJuIGJ5dGVBcnJheVxufVxuXG5mdW5jdGlvbiB1dGYxNmxlVG9CeXRlcyAoc3RyLCB1bml0cykge1xuICB2YXIgYywgaGksIGxvXG4gIHZhciBieXRlQXJyYXkgPSBbXVxuICBmb3IgKHZhciBpID0gMDsgaSA8IHN0ci5sZW5ndGg7ICsraSkge1xuICAgIGlmICgodW5pdHMgLT0gMikgPCAwKSBicmVha1xuXG4gICAgYyA9IHN0ci5jaGFyQ29kZUF0KGkpXG4gICAgaGkgPSBjID4+IDhcbiAgICBsbyA9IGMgJSAyNTZcbiAgICBieXRlQXJyYXkucHVzaChsbylcbiAgICBieXRlQXJyYXkucHVzaChoaSlcbiAgfVxuXG4gIHJldHVybiBieXRlQXJyYXlcbn1cblxuZnVuY3Rpb24gYmFzZTY0VG9CeXRlcyAoc3RyKSB7XG4gIHJldHVybiBiYXNlNjQudG9CeXRlQXJyYXkoYmFzZTY0Y2xlYW4oc3RyKSlcbn1cblxuZnVuY3Rpb24gYmxpdEJ1ZmZlciAoc3JjLCBkc3QsIG9mZnNldCwgbGVuZ3RoKSB7XG4gIGZvciAodmFyIGkgPSAwOyBpIDwgbGVuZ3RoOyArK2kpIHtcbiAgICBpZiAoKGkgKyBvZmZzZXQgPj0gZHN0Lmxlbmd0aCkgfHwgKGkgPj0gc3JjLmxlbmd0aCkpIGJyZWFrXG4gICAgZHN0W2kgKyBvZmZzZXRdID0gc3JjW2ldXG4gIH1cbiAgcmV0dXJuIGlcbn1cblxuZnVuY3Rpb24gaXNuYW4gKHZhbCkge1xuICByZXR1cm4gdmFsICE9PSB2YWwgLy8gZXNsaW50LWRpc2FibGUtbGluZSBuby1zZWxmLWNvbXBhcmVcbn1cbiIsImV4cG9ydHMucmVhZCA9IGZ1bmN0aW9uIChidWZmZXIsIG9mZnNldCwgaXNMRSwgbUxlbiwgbkJ5dGVzKSB7XG4gIHZhciBlLCBtXG4gIHZhciBlTGVuID0gbkJ5dGVzICogOCAtIG1MZW4gLSAxXG4gIHZhciBlTWF4ID0gKDEgPDwgZUxlbikgLSAxXG4gIHZhciBlQmlhcyA9IGVNYXggPj4gMVxuICB2YXIgbkJpdHMgPSAtN1xuICB2YXIgaSA9IGlzTEUgPyAobkJ5dGVzIC0gMSkgOiAwXG4gIHZhciBkID0gaXNMRSA/IC0xIDogMVxuICB2YXIgcyA9IGJ1ZmZlcltvZmZzZXQgKyBpXVxuXG4gIGkgKz0gZFxuXG4gIGUgPSBzICYgKCgxIDw8ICgtbkJpdHMpKSAtIDEpXG4gIHMgPj49ICgtbkJpdHMpXG4gIG5CaXRzICs9IGVMZW5cbiAgZm9yICg7IG5CaXRzID4gMDsgZSA9IGUgKiAyNTYgKyBidWZmZXJbb2Zmc2V0ICsgaV0sIGkgKz0gZCwgbkJpdHMgLT0gOCkge31cblxuICBtID0gZSAmICgoMSA8PCAoLW5CaXRzKSkgLSAxKVxuICBlID4+PSAoLW5CaXRzKVxuICBuQml0cyArPSBtTGVuXG4gIGZvciAoOyBuQml0cyA+IDA7IG0gPSBtICogMjU2ICsgYnVmZmVyW29mZnNldCArIGldLCBpICs9IGQsIG5CaXRzIC09IDgpIHt9XG5cbiAgaWYgKGUgPT09IDApIHtcbiAgICBlID0gMSAtIGVCaWFzXG4gIH0gZWxzZSBpZiAoZSA9PT0gZU1heCkge1xuICAgIHJldHVybiBtID8gTmFOIDogKChzID8gLTEgOiAxKSAqIEluZmluaXR5KVxuICB9IGVsc2Uge1xuICAgIG0gPSBtICsgTWF0aC5wb3coMiwgbUxlbilcbiAgICBlID0gZSAtIGVCaWFzXG4gIH1cbiAgcmV0dXJuIChzID8gLTEgOiAxKSAqIG0gKiBNYXRoLnBvdygyLCBlIC0gbUxlbilcbn1cblxuZXhwb3J0cy53cml0ZSA9IGZ1bmN0aW9uIChidWZmZXIsIHZhbHVlLCBvZmZzZXQsIGlzTEUsIG1MZW4sIG5CeXRlcykge1xuICB2YXIgZSwgbSwgY1xuICB2YXIgZUxlbiA9IG5CeXRlcyAqIDggLSBtTGVuIC0gMVxuICB2YXIgZU1heCA9ICgxIDw8IGVMZW4pIC0gMVxuICB2YXIgZUJpYXMgPSBlTWF4ID4+IDFcbiAgdmFyIHJ0ID0gKG1MZW4gPT09IDIzID8gTWF0aC5wb3coMiwgLTI0KSAtIE1hdGgucG93KDIsIC03NykgOiAwKVxuICB2YXIgaSA9IGlzTEUgPyAwIDogKG5CeXRlcyAtIDEpXG4gIHZhciBkID0gaXNMRSA/IDEgOiAtMVxuICB2YXIgcyA9IHZhbHVlIDwgMCB8fCAodmFsdWUgPT09IDAgJiYgMSAvIHZhbHVlIDwgMCkgPyAxIDogMFxuXG4gIHZhbHVlID0gTWF0aC5hYnModmFsdWUpXG5cbiAgaWYgKGlzTmFOKHZhbHVlKSB8fCB2YWx1ZSA9PT0gSW5maW5pdHkpIHtcbiAgICBtID0gaXNOYU4odmFsdWUpID8gMSA6IDBcbiAgICBlID0gZU1heFxuICB9IGVsc2Uge1xuICAgIGUgPSBNYXRoLmZsb29yKE1hdGgubG9nKHZhbHVlKSAvIE1hdGguTE4yKVxuICAgIGlmICh2YWx1ZSAqIChjID0gTWF0aC5wb3coMiwgLWUpKSA8IDEpIHtcbiAgICAgIGUtLVxuICAgICAgYyAqPSAyXG4gICAgfVxuICAgIGlmIChlICsgZUJpYXMgPj0gMSkge1xuICAgICAgdmFsdWUgKz0gcnQgLyBjXG4gICAgfSBlbHNlIHtcbiAgICAgIHZhbHVlICs9IHJ0ICogTWF0aC5wb3coMiwgMSAtIGVCaWFzKVxuICAgIH1cbiAgICBpZiAodmFsdWUgKiBjID49IDIpIHtcbiAgICAgIGUrK1xuICAgICAgYyAvPSAyXG4gICAgfVxuXG4gICAgaWYgKGUgKyBlQmlhcyA+PSBlTWF4KSB7XG4gICAgICBtID0gMFxuICAgICAgZSA9IGVNYXhcbiAgICB9IGVsc2UgaWYgKGUgKyBlQmlhcyA+PSAxKSB7XG4gICAgICBtID0gKHZhbHVlICogYyAtIDEpICogTWF0aC5wb3coMiwgbUxlbilcbiAgICAgIGUgPSBlICsgZUJpYXNcbiAgICB9IGVsc2Uge1xuICAgICAgbSA9IHZhbHVlICogTWF0aC5wb3coMiwgZUJpYXMgLSAxKSAqIE1hdGgucG93KDIsIG1MZW4pXG4gICAgICBlID0gMFxuICAgIH1cbiAgfVxuXG4gIGZvciAoOyBtTGVuID49IDg7IGJ1ZmZlcltvZmZzZXQgKyBpXSA9IG0gJiAweGZmLCBpICs9IGQsIG0gLz0gMjU2LCBtTGVuIC09IDgpIHt9XG5cbiAgZSA9IChlIDw8IG1MZW4pIHwgbVxuICBlTGVuICs9IG1MZW5cbiAgZm9yICg7IGVMZW4gPiAwOyBidWZmZXJbb2Zmc2V0ICsgaV0gPSBlICYgMHhmZiwgaSArPSBkLCBlIC89IDI1NiwgZUxlbiAtPSA4KSB7fVxuXG4gIGJ1ZmZlcltvZmZzZXQgKyBpIC0gZF0gfD0gcyAqIDEyOFxufVxuIiwidmFyIHRvU3RyaW5nID0ge30udG9TdHJpbmc7XG5cbm1vZHVsZS5leHBvcnRzID0gQXJyYXkuaXNBcnJheSB8fCBmdW5jdGlvbiAoYXJyKSB7XG4gIHJldHVybiB0b1N0cmluZy5jYWxsKGFycikgPT0gJ1tvYmplY3QgQXJyYXldJztcbn07XG4iLCIndXNlIHN0cmljdCc7XG4vKiBlc2xpbnQtZGlzYWJsZSBuby11bnVzZWQtdmFycyAqL1xudmFyIGhhc093blByb3BlcnR5ID0gT2JqZWN0LnByb3RvdHlwZS5oYXNPd25Qcm9wZXJ0eTtcbnZhciBwcm9wSXNFbnVtZXJhYmxlID0gT2JqZWN0LnByb3RvdHlwZS5wcm9wZXJ0eUlzRW51bWVyYWJsZTtcblxuZnVuY3Rpb24gdG9PYmplY3QodmFsKSB7XG5cdGlmICh2YWwgPT09IG51bGwgfHwgdmFsID09PSB1bmRlZmluZWQpIHtcblx0XHR0aHJvdyBuZXcgVHlwZUVycm9yKCdPYmplY3QuYXNzaWduIGNhbm5vdCBiZSBjYWxsZWQgd2l0aCBudWxsIG9yIHVuZGVmaW5lZCcpO1xuXHR9XG5cblx0cmV0dXJuIE9iamVjdCh2YWwpO1xufVxuXG5mdW5jdGlvbiBzaG91bGRVc2VOYXRpdmUoKSB7XG5cdHRyeSB7XG5cdFx0aWYgKCFPYmplY3QuYXNzaWduKSB7XG5cdFx0XHRyZXR1cm4gZmFsc2U7XG5cdFx0fVxuXG5cdFx0Ly8gRGV0ZWN0IGJ1Z2d5IHByb3BlcnR5IGVudW1lcmF0aW9uIG9yZGVyIGluIG9sZGVyIFY4IHZlcnNpb25zLlxuXG5cdFx0Ly8gaHR0cHM6Ly9idWdzLmNocm9taXVtLm9yZy9wL3Y4L2lzc3Vlcy9kZXRhaWw/aWQ9NDExOFxuXHRcdHZhciB0ZXN0MSA9IG5ldyBTdHJpbmcoJ2FiYycpOyAgLy8gZXNsaW50LWRpc2FibGUtbGluZVxuXHRcdHRlc3QxWzVdID0gJ2RlJztcblx0XHRpZiAoT2JqZWN0LmdldE93blByb3BlcnR5TmFtZXModGVzdDEpWzBdID09PSAnNScpIHtcblx0XHRcdHJldHVybiBmYWxzZTtcblx0XHR9XG5cblx0XHQvLyBodHRwczovL2J1Z3MuY2hyb21pdW0ub3JnL3AvdjgvaXNzdWVzL2RldGFpbD9pZD0zMDU2XG5cdFx0dmFyIHRlc3QyID0ge307XG5cdFx0Zm9yICh2YXIgaSA9IDA7IGkgPCAxMDsgaSsrKSB7XG5cdFx0XHR0ZXN0MlsnXycgKyBTdHJpbmcuZnJvbUNoYXJDb2RlKGkpXSA9IGk7XG5cdFx0fVxuXHRcdHZhciBvcmRlcjIgPSBPYmplY3QuZ2V0T3duUHJvcGVydHlOYW1lcyh0ZXN0MikubWFwKGZ1bmN0aW9uIChuKSB7XG5cdFx0XHRyZXR1cm4gdGVzdDJbbl07XG5cdFx0fSk7XG5cdFx0aWYgKG9yZGVyMi5qb2luKCcnKSAhPT0gJzAxMjM0NTY3ODknKSB7XG5cdFx0XHRyZXR1cm4gZmFsc2U7XG5cdFx0fVxuXG5cdFx0Ly8gaHR0cHM6Ly9idWdzLmNocm9taXVtLm9yZy9wL3Y4L2lzc3Vlcy9kZXRhaWw/aWQ9MzA1NlxuXHRcdHZhciB0ZXN0MyA9IHt9O1xuXHRcdCdhYmNkZWZnaGlqa2xtbm9wcXJzdCcuc3BsaXQoJycpLmZvckVhY2goZnVuY3Rpb24gKGxldHRlcikge1xuXHRcdFx0dGVzdDNbbGV0dGVyXSA9IGxldHRlcjtcblx0XHR9KTtcblx0XHRpZiAoT2JqZWN0LmtleXMoT2JqZWN0LmFzc2lnbih7fSwgdGVzdDMpKS5qb2luKCcnKSAhPT1cblx0XHRcdFx0J2FiY2RlZmdoaWprbG1ub3BxcnN0Jykge1xuXHRcdFx0cmV0dXJuIGZhbHNlO1xuXHRcdH1cblxuXHRcdHJldHVybiB0cnVlO1xuXHR9IGNhdGNoIChlKSB7XG5cdFx0Ly8gV2UgZG9uJ3QgZXhwZWN0IGFueSBvZiB0aGUgYWJvdmUgdG8gdGhyb3csIGJ1dCBiZXR0ZXIgdG8gYmUgc2FmZS5cblx0XHRyZXR1cm4gZmFsc2U7XG5cdH1cbn1cblxubW9kdWxlLmV4cG9ydHMgPSBzaG91bGRVc2VOYXRpdmUoKSA/IE9iamVjdC5hc3NpZ24gOiBmdW5jdGlvbiAodGFyZ2V0LCBzb3VyY2UpIHtcblx0dmFyIGZyb207XG5cdHZhciB0byA9IHRvT2JqZWN0KHRhcmdldCk7XG5cdHZhciBzeW1ib2xzO1xuXG5cdGZvciAodmFyIHMgPSAxOyBzIDwgYXJndW1lbnRzLmxlbmd0aDsgcysrKSB7XG5cdFx0ZnJvbSA9IE9iamVjdChhcmd1bWVudHNbc10pO1xuXG5cdFx0Zm9yICh2YXIga2V5IGluIGZyb20pIHtcblx0XHRcdGlmIChoYXNPd25Qcm9wZXJ0eS5jYWxsKGZyb20sIGtleSkpIHtcblx0XHRcdFx0dG9ba2V5XSA9IGZyb21ba2V5XTtcblx0XHRcdH1cblx0XHR9XG5cblx0XHRpZiAoT2JqZWN0LmdldE93blByb3BlcnR5U3ltYm9scykge1xuXHRcdFx0c3ltYm9scyA9IE9iamVjdC5nZXRPd25Qcm9wZXJ0eVN5bWJvbHMoZnJvbSk7XG5cdFx0XHRmb3IgKHZhciBpID0gMDsgaSA8IHN5bWJvbHMubGVuZ3RoOyBpKyspIHtcblx0XHRcdFx0aWYgKHByb3BJc0VudW1lcmFibGUuY2FsbChmcm9tLCBzeW1ib2xzW2ldKSkge1xuXHRcdFx0XHRcdHRvW3N5bWJvbHNbaV1dID0gZnJvbVtzeW1ib2xzW2ldXTtcblx0XHRcdFx0fVxuXHRcdFx0fVxuXHRcdH1cblx0fVxuXG5cdHJldHVybiB0bztcbn07XG4iLCJtb2R1bGUuZXhwb3J0cz17XG4gICAgXCJ2ZXJzaW9uXCI6IFwiXCJcbn1cbiIsIi8qKlxuICogRXBpY2VudGVyIEphdmFzY3JpcHQgbGlicmFyaWVzXG4gKiB2PCU9IHZlcnNpb24gJT5cbiAqIGh0dHBzOi8vZ2l0aHViLmNvbS9mb3Jpby9lcGljZW50ZXItanMtbGlic1xuICovXG5cbnZhciBGID0ge1xuICAgIHV0aWw6IHt9LFxuICAgIGZhY3Rvcnk6IHt9LFxuICAgIHRyYW5zcG9ydDoge30sXG4gICAgc3RvcmU6IHt9LFxuICAgIHNlcnZpY2U6IHt9LFxuICAgIG1hbmFnZXI6IHtcbiAgICAgICAgc3RyYXRlZ3k6IHt9XG4gICAgfSxcblxufTtcblxuRi5sb2FkID0gcmVxdWlyZSgnLi9lbnYtbG9hZCcpO1xuRi5sb2FkKCk7XG5cbkYudXRpbC5xdWVyeSA9IHJlcXVpcmUoJy4vdXRpbC9xdWVyeS11dGlsJyk7XG5GLnV0aWwubWFrZVNlcXVlbmNlID0gcmVxdWlyZSgnLi91dGlsL21ha2Utc2VxdWVuY2UnKTtcbkYudXRpbC5ydW4gPSByZXF1aXJlKCcuL3V0aWwvcnVuLXV0aWwnKTtcbkYudXRpbC5jbGFzc0Zyb20gPSByZXF1aXJlKCcuL3V0aWwvaW5oZXJpdCcpO1xuXG5GLmZhY3RvcnkuVHJhbnNwb3J0ID0gcmVxdWlyZSgnLi90cmFuc3BvcnQvaHR0cC10cmFuc3BvcnQtZmFjdG9yeScpO1xuRi50cmFuc3BvcnQuQWpheCA9IHJlcXVpcmUoJy4vdHJhbnNwb3J0L2FqYXgtaHR0cC10cmFuc3BvcnQnKTtcblxuRi5zZXJ2aWNlLlVSTCA9IHJlcXVpcmUoJy4vc2VydmljZS91cmwtY29uZmlnLXNlcnZpY2UnKTtcbkYuc2VydmljZS5Db25maWcgPSByZXF1aXJlKCcuL3NlcnZpY2UvY29uZmlndXJhdGlvbi1zZXJ2aWNlJyk7XG5GLnNlcnZpY2UuUnVuID0gcmVxdWlyZSgnLi9zZXJ2aWNlL3J1bi1hcGktc2VydmljZScpO1xuRi5zZXJ2aWNlLkZpbGUgPSByZXF1aXJlKCcuL3NlcnZpY2UvYWRtaW4tZmlsZS1zZXJ2aWNlJyk7XG5GLnNlcnZpY2UuVmFyaWFibGVzID0gcmVxdWlyZSgnLi9zZXJ2aWNlL3ZhcmlhYmxlcy1hcGktc2VydmljZScpO1xuRi5zZXJ2aWNlLkRhdGEgPSByZXF1aXJlKCcuL3NlcnZpY2UvZGF0YS1hcGktc2VydmljZScpO1xuRi5zZXJ2aWNlLkF1dGggPSByZXF1aXJlKCcuL3NlcnZpY2UvYXV0aC1hcGktc2VydmljZScpO1xuRi5zZXJ2aWNlLldvcmxkID0gcmVxdWlyZSgnLi9zZXJ2aWNlL3dvcmxkLWFwaS1hZGFwdGVyJyk7XG5GLnNlcnZpY2UuU3RhdGUgPSByZXF1aXJlKCcuL3NlcnZpY2Uvc3RhdGUtYXBpLWFkYXB0ZXInKTtcbkYuc2VydmljZS5Vc2VyID0gcmVxdWlyZSgnLi9zZXJ2aWNlL3VzZXItYXBpLWFkYXB0ZXInKTtcbkYuc2VydmljZS5NZW1iZXIgPSByZXF1aXJlKCcuL3NlcnZpY2UvbWVtYmVyLWFwaS1hZGFwdGVyJyk7XG5GLnNlcnZpY2UuQXNzZXQgPSByZXF1aXJlKCcuL3NlcnZpY2UvYXNzZXQtYXBpLWFkYXB0ZXInKTtcbkYuc2VydmljZS5Hcm91cCA9IHJlcXVpcmUoJy4vc2VydmljZS9ncm91cC1hcGktc2VydmljZScpO1xuXG5GLnN0b3JlLkNvb2tpZSA9IHJlcXVpcmUoJy4vc3RvcmUvY29va2llLXN0b3JlJyk7XG5GLmZhY3RvcnkuU3RvcmUgPSByZXF1aXJlKCcuL3N0b3JlL3N0b3JlLWZhY3RvcnknKTtcblxuRi5tYW5hZ2VyLlNjZW5hcmlvTWFuYWdlciA9IHJlcXVpcmUoJy4vbWFuYWdlcnMvc2NlbmFyaW8tbWFuYWdlcicpO1xuRi5tYW5hZ2VyLlJ1bk1hbmFnZXIgPSByZXF1aXJlKCcuL21hbmFnZXJzL3J1bi1tYW5hZ2VyJyk7XG5GLm1hbmFnZXIuQXV0aE1hbmFnZXIgPSByZXF1aXJlKCcuL21hbmFnZXJzL2F1dGgtbWFuYWdlcicpO1xuRi5tYW5hZ2VyLldvcmxkTWFuYWdlciA9IHJlcXVpcmUoJy4vbWFuYWdlcnMvd29ybGQtbWFuYWdlcicpO1xuXG5GLm1hbmFnZXIuc3RyYXRlZ3lbJ2Fsd2F5cy1uZXcnXSA9IHJlcXVpcmUoJy4vbWFuYWdlcnMvcnVuLXN0cmF0ZWdpZXMvYWx3YXlzLW5ldy1zdHJhdGVneScpO1xuRi5tYW5hZ2VyLnN0cmF0ZWd5Wydjb25kaXRpb25hbC1jcmVhdGlvbiddID0gcmVxdWlyZSgnLi9tYW5hZ2Vycy9ydW4tc3RyYXRlZ2llcy9jb25kaXRpb25hbC1jcmVhdGlvbi1zdHJhdGVneScpO1xuRi5tYW5hZ2VyLnN0cmF0ZWd5LmlkZW50aXR5ID0gcmVxdWlyZSgnLi9tYW5hZ2Vycy9ydW4tc3RyYXRlZ2llcy9pZGVudGl0eS1zdHJhdGVneScpO1xuRi5tYW5hZ2VyLnN0cmF0ZWd5WyduZXctaWYtbWlzc2luZyddID0gcmVxdWlyZSgnLi9tYW5hZ2Vycy9ydW4tc3RyYXRlZ2llcy9uZXctaWYtbWlzc2luZy1zdHJhdGVneScpO1xuRi5tYW5hZ2VyLnN0cmF0ZWd5WyduZXctaWYtbWlzc2luZyddID0gcmVxdWlyZSgnLi9tYW5hZ2Vycy9ydW4tc3RyYXRlZ2llcy9uZXctaWYtbWlzc2luZy1zdHJhdGVneScpO1xuRi5tYW5hZ2VyLnN0cmF0ZWd5WyduZXctaWYtcGVyc2lzdGVkJ10gPSByZXF1aXJlKCcuL21hbmFnZXJzL3J1bi1zdHJhdGVnaWVzL25ldy1pZi1wZXJzaXN0ZWQtc3RyYXRlZ3knKTtcbkYubWFuYWdlci5zdHJhdGVneVsnbmV3LWlmLWluaXRpYWxpemVkJ10gPSByZXF1aXJlKCcuL21hbmFnZXJzL3J1bi1zdHJhdGVnaWVzL25ldy1pZi1pbml0aWFsaXplZC1zdHJhdGVneScpO1xuXG5GLm1hbmFnZXIuQ2hhbm5lbE1hbmFnZXIgPSByZXF1aXJlKCcuL21hbmFnZXJzL2VwaWNlbnRlci1jaGFubmVsLW1hbmFnZXInKTtcbkYuc2VydmljZS5DaGFubmVsID0gcmVxdWlyZSgnLi9zZXJ2aWNlL2NoYW5uZWwtc2VydmljZScpO1xuXG5GLnZlcnNpb24gPSAnPCU9IHZlcnNpb24gJT4nO1xuRi5hcGkgPSByZXF1aXJlKCcuL2FwaS12ZXJzaW9uLmpzb24nKTtcblxuZ2xvYmFsLkYgPSBGO1xubW9kdWxlLmV4cG9ydHMgPSBGO1xuIiwiJ3VzZSBzdHJpY3QnO1xuXG52YXIgdXJsQ29uZmlnU2VydmljZSA9IHJlcXVpcmUoJy4vc2VydmljZS91cmwtY29uZmlnLXNlcnZpY2UnKTtcblxudmFyIGVudkxvYWQgPSBmdW5jdGlvbiAoY2FsbGJhY2spIHtcbiAgICB2YXIgZW52UHJvbWlzZTtcbiAgICB2YXIgaG9zdDtcbiAgICB2YXIgdXJsU2VydmljZSA9IHVybENvbmZpZ1NlcnZpY2UoKTtcbiAgICB2YXIgZW52UGF0aCA9ICcvZXBpY2VudGVyL3YxL2NvbmZpZyc7XG4gICAgaWYgKHVybFNlcnZpY2UuaXNMb2NhbGhvc3QoKSkge1xuICAgICAgICBob3N0ID0gJ2h0dHBzOi8vZm9yaW8uY29tJztcbiAgICB9IGVsc2Uge1xuICAgICAgICBob3N0ID0gJyc7XG4gICAgfVxuICAgIHZhciBpbmZvVXJsID0gaG9zdCArIGVudlBhdGg7XG4gICAgZW52UHJvbWlzZSA9ICQuYWpheCh7IHVybDogaW5mb1VybCwgYXN5bmM6IGZhbHNlIH0pO1xuICAgIGVudlByb21pc2UuZG9uZShmdW5jdGlvbiAocmVzKSB7XG4gICAgICAgIHZhciBhcGkgPSByZXMuYXBpO1xuICAgICAgICAkLmV4dGVuZCh1cmxDb25maWdTZXJ2aWNlLCBhcGkpO1xuICAgIH0pLmZhaWwoZnVuY3Rpb24gKHJlcykge1xuICAgICAgICAvLyBFcGljZW50ZXIvd2Vic2VydmVyIG5vdCBwcm9wZXJseSBjb25maWd1cmVkXG4gICAgICAgIC8vIGZhbGxiYWNrIHRvIGFwaS5mb3Jpby5jb21cbiAgICAgICAgJC5leHRlbmQodXJsQ29uZmlnU2VydmljZSwgeyBwcm90b2NvbDogJ2h0dHBzJywgaG9zdDogJ2FwaS5mb3Jpby5jb20nIH0pO1xuICAgIH0pO1xuICAgIHJldHVybiBlbnZQcm9taXNlLmRvbmUoY2FsbGJhY2spLmZhaWwoY2FsbGJhY2spO1xufTtcblxubW9kdWxlLmV4cG9ydHMgPSBlbnZMb2FkO1xuIiwiLyoqXG4qICMjIEF1dGhvcml6YXRpb24gTWFuYWdlclxuKlxuKiBUaGUgQXV0aG9yaXphdGlvbiBNYW5hZ2VyIHByb3ZpZGVzIGFuIGVhc3kgd2F5IHRvIG1hbmFnZSB1c2VyIGF1dGhlbnRpY2F0aW9uIChsb2dnaW5nIGluIGFuZCBvdXQpIGFuZCBhdXRob3JpemF0aW9uIChrZWVwaW5nIHRyYWNrIG9mIHRva2Vucywgc2Vzc2lvbnMsIGFuZCBncm91cHMpIGZvciBwcm9qZWN0cy5cbipcbiogVGhlIEF1dGhvcml6YXRpb24gTWFuYWdlciBpcyBtb3N0IHVzZWZ1bCBmb3IgW3RlYW0gcHJvamVjdHNdKC4uLy4uLy4uL2dsb3NzYXJ5LyN0ZWFtKSB3aXRoIGFuIGFjY2VzcyBsZXZlbCBvZiBbQXV0aGVudGljYXRlZF0oLi4vLi4vLi4vZ2xvc3NhcnkvI2FjY2VzcykuIFRoZXNlIHByb2plY3RzIGFyZSBhY2Nlc3NlZCBieSBbZW5kIHVzZXJzXSguLi8uLi8uLi9nbG9zc2FyeS8jdXNlcnMpIHdobyBhcmUgbWVtYmVycyBvZiBvbmUgb3IgbW9yZSBbZ3JvdXBzXSguLi8uLi8uLi9nbG9zc2FyeS8jZ3JvdXBzKS5cbipcbiogIyMjIyBVc2luZyB0aGUgQXV0aG9yaXphdGlvbiBNYW5hZ2VyXG4qXG4qIFRvIHVzZSB0aGUgQXV0aG9yaXphdGlvbiBNYW5hZ2VyLCBpbnN0YW50aWF0ZSBpdC4gVGhlbiwgbWFrZSBjYWxscyB0byBhbnkgb2YgdGhlIG1ldGhvZHMgeW91IG5lZWQ6XG4qXG4qICAgICAgIHZhciBhdXRoTWdyID0gbmV3IEYubWFuYWdlci5BdXRoTWFuYWdlcih7XG4qICAgICAgICAgICBhY2NvdW50OiAnYWNtZS1zaW11bGF0aW9ucycsXG4qICAgICAgICAgICB1c2VyTmFtZTogJ2VuZHVzZXIxJyxcbiogICAgICAgICAgIHBhc3N3b3JkOiAncGFzc3cwcmQnXG4qICAgICAgIH0pO1xuKiAgICAgICBhdXRoTWdyLmxvZ2luKCkudGhlbihmdW5jdGlvbiAoKSB7XG4qICAgICAgICAgICBhdXRoTWdyLmdldEN1cnJlbnRVc2VyU2Vzc2lvbkluZm8oKTtcbiogICAgICAgfSk7XG4qXG4qXG4qIFRoZSBgb3B0aW9uc2Agb2JqZWN0IHBhc3NlZCB0byB0aGUgYEYubWFuYWdlci5BdXRoTWFuYWdlcigpYCBjYWxsIGNhbiBpbmNsdWRlOlxuKlxuKiAgICogYGFjY291bnRgOiBUaGUgYWNjb3VudCBpZCBmb3IgdGhpcyBgdXNlck5hbWVgLiBJbiB0aGUgRXBpY2VudGVyIFVJLCB0aGlzIGlzIHRoZSAqKlRlYW0gSUQqKiAoZm9yIHRlYW0gcHJvamVjdHMpIG9yIHRoZSAqKlVzZXIgSUQqKiAoZm9yIHBlcnNvbmFsIHByb2plY3RzKS5cbiogICAqIGB1c2VyTmFtZWA6IEVtYWlsIG9yIHVzZXJuYW1lIHRvIHVzZSBmb3IgbG9nZ2luZyBpbi5cbiogICAqIGBwYXNzd29yZGA6IFBhc3N3b3JkIGZvciBzcGVjaWZpZWQgYHVzZXJOYW1lYC5cbiogICAqIGBwcm9qZWN0YDogVGhlICoqUHJvamVjdCBJRCoqIGZvciB0aGUgcHJvamVjdCB0byBsb2cgdGhpcyB1c2VyIGludG8uIE9wdGlvbmFsLlxuKiAgICogYGdyb3VwSWRgOiBJZCBvZiB0aGUgZ3JvdXAgdG8gd2hpY2ggYHVzZXJOYW1lYCBiZWxvbmdzLiBSZXF1aXJlZCBmb3IgZW5kIHVzZXJzIGlmIHRoZSBgcHJvamVjdGAgaXMgc3BlY2lmaWVkLlxuKlxuKiBJZiB5b3UgcHJlZmVyIHN0YXJ0aW5nIGZyb20gYSB0ZW1wbGF0ZSwgdGhlIEVwaWNlbnRlciBKUyBMaWJzIFtMb2dpbiBDb21wb25lbnRdKC4uLy4uLyNjb21wb25lbnRzKSB1c2VzIHRoZSBBdXRob3JpemF0aW9uIE1hbmFnZXIgYXMgd2VsbC4gVGhpcyBzYW1wbGUgSFRNTCBwYWdlIChhbmQgYXNzb2NpYXRlZCBDU1MgYW5kIEpTIGZpbGVzKSBwcm92aWRlcyBhIGxvZ2luIGZvcm0gZm9yIHRlYW0gbWVtYmVycyBhbmQgZW5kIHVzZXJzIG9mIHlvdXIgcHJvamVjdC4gSXQgYWxzbyBpbmNsdWRlcyBhIGdyb3VwIHNlbGVjdG9yIGZvciBlbmQgdXNlcnMgdGhhdCBhcmUgbWVtYmVycyBvZiBtdWx0aXBsZSBncm91cHMuXG4qL1xuXG4ndXNlIHN0cmljdCc7XG52YXIgQXV0aEFkYXB0ZXIgPSByZXF1aXJlKCcuLi9zZXJ2aWNlL2F1dGgtYXBpLXNlcnZpY2UnKTtcbnZhciBNZW1iZXJBZGFwdGVyID0gcmVxdWlyZSgnLi4vc2VydmljZS9tZW1iZXItYXBpLWFkYXB0ZXInKTtcbnZhciBHcm91cFNlcnZpY2UgPSByZXF1aXJlKCcuLi9zZXJ2aWNlL2dyb3VwLWFwaS1zZXJ2aWNlJyk7XG52YXIgU2Vzc2lvbk1hbmFnZXIgPSByZXF1aXJlKCcuLi9zdG9yZS9zZXNzaW9uLW1hbmFnZXInKTtcbnZhciBCdWZmZXIgPSByZXF1aXJlKCdidWZmZXInKS5CdWZmZXI7XG52YXIgX3BpY2sgPSByZXF1aXJlKCcuLi91dGlsL29iamVjdC11dGlsJykuX3BpY2s7XG52YXIgb2JqZWN0QXNzaWduID0gcmVxdWlyZSgnb2JqZWN0LWFzc2lnbicpO1xuXG52YXIgZGVmYXVsdHMgPSB7XG4gICAgcmVxdWlyZXNHcm91cDogdHJ1ZVxufTtcblxuZnVuY3Rpb24gQXV0aE1hbmFnZXIob3B0aW9ucykge1xuICAgIG9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSwgZGVmYXVsdHMsIG9wdGlvbnMpO1xuICAgIHRoaXMuc2Vzc2lvbk1hbmFnZXIgPSBuZXcgU2Vzc2lvbk1hbmFnZXIob3B0aW9ucyk7XG4gICAgdGhpcy5vcHRpb25zID0gdGhpcy5zZXNzaW9uTWFuYWdlci5nZXRNZXJnZWRPcHRpb25zKCk7XG5cbiAgICB0aGlzLmlzTG9jYWwgPSB0aGlzLm9wdGlvbnMuaXNMb2NhbDtcbiAgICB0aGlzLmF1dGhBZGFwdGVyID0gbmV3IEF1dGhBZGFwdGVyKHRoaXMub3B0aW9ucyk7XG59XG5cbnZhciBfZmluZFVzZXJJbkdyb3VwID0gZnVuY3Rpb24gKG1lbWJlcnMsIGlkKSB7XG4gICAgZm9yICh2YXIgaiA9IDA7IGo8bWVtYmVycy5sZW5ndGg7IGorKykge1xuICAgICAgICBpZiAobWVtYmVyc1tqXS51c2VySWQgPT09IGlkKSB7XG4gICAgICAgICAgICByZXR1cm4gbWVtYmVyc1tqXTtcbiAgICAgICAgfVxuICAgIH1cblxuXG4gICAgcmV0dXJuIG51bGw7XG59O1xuXG5BdXRoTWFuYWdlci5wcm90b3R5cGUgPSAkLmV4dGVuZChBdXRoTWFuYWdlci5wcm90b3R5cGUsIHtcblxuICAgIC8qKlxuICAgICogTG9ncyB1c2VyIGluLlxuICAgICpcbiAgICAqICoqRXhhbXBsZSoqXG4gICAgKlxuICAgICogICAgICAgYXV0aE1nci5sb2dpbih7XG4gICAgKiAgICAgICAgICAgYWNjb3VudDogJ2FjbWUtc2ltdWxhdGlvbnMnLFxuICAgICogICAgICAgICAgIHByb2plY3Q6ICdzdXBwbHktY2hhaW4tZ2FtZScsXG4gICAgKiAgICAgICAgICAgdXNlck5hbWU6ICdlbmR1c2VyMScsXG4gICAgKiAgICAgICAgICAgcGFzc3dvcmQ6ICdwYXNzdzByZCdcbiAgICAqICAgICAgIH0pXG4gICAgKiAgICAgICAgICAgLnRoZW4oZnVuY3Rpb24oc3RhdHVzT2JqKSB7XG4gICAgKiAgICAgICAgICAgICAgIC8vIGlmIGVuZHVzZXIxIGJlbG9uZ3MgdG8gZXhhY3RseSBvbmUgZ3JvdXBcbiAgICAqICAgICAgICAgICAgICAgLy8gKG9yIGlmIHRoZSBsb2dpbigpIGNhbGwgaXMgbW9kaWZpZWQgdG8gaW5jbHVkZSB0aGUgZ3JvdXAgaWQpXG4gICAgKiAgICAgICAgICAgICAgIC8vIGNvbnRpbnVlIGhlcmVcbiAgICAqICAgICAgICAgICB9KVxuICAgICogICAgICAgICAgIC5mYWlsKGZ1bmN0aW9uKHN0YXR1c09iaikge1xuICAgICogICAgICAgICAgICAgICAvLyBpZiBlbmR1c2VyMSBiZWxvbmdzIHRvIG11bHRpcGxlIGdyb3VwcyxcbiAgICAqICAgICAgICAgICAgICAgLy8gdGhlIGxvZ2luKCkgY2FsbCBmYWlsc1xuICAgICogICAgICAgICAgICAgICAvLyBhbmQgcmV0dXJucyBhbGwgZ3JvdXBzIG9mIHdoaWNoIHRoZSB1c2VyIGlzIGEgbWVtYmVyXG4gICAgKiAgICAgICAgICAgICAgIGZvciAodmFyIGk9MDsgaSA8IHN0YXR1c09iai51c2VyR3JvdXBzLmxlbmd0aDsgaSsrKSB7XG4gICAgKiAgICAgICAgICAgICAgICAgICBjb25zb2xlLmxvZyhzdGF0dXNPYmoudXNlckdyb3Vwc1tpXS5uYW1lLCBzdGF0dXNPYmoudXNlckdyb3Vwc1tpXS5ncm91cElkKTtcbiAgICAqICAgICAgICAgICAgICAgfVxuICAgICogICAgICAgICAgIH0pO1xuICAgICpcbiAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgKlxuICAgICogQHBhcmFtIHtPYmplY3R9IGBvcHRpb25zYCAoT3B0aW9uYWwpIE92ZXJyaWRlcyBmb3IgY29uZmlndXJhdGlvbiBvcHRpb25zLiBJZiBub3QgcGFzc2VkIGluIHdoZW4gY3JlYXRpbmcgYW4gaW5zdGFuY2Ugb2YgdGhlIG1hbmFnZXIgKGBGLm1hbmFnZXIuQXV0aE1hbmFnZXIoKWApLCB0aGVzZSBvcHRpb25zIHNob3VsZCBpbmNsdWRlOlxuICAgICogQHBhcmFtIHtzdHJpbmd9IGBvcHRpb25zLmFjY291bnRgIFRoZSBhY2NvdW50IGlkIGZvciB0aGlzIGB1c2VyTmFtZWAuIEluIHRoZSBFcGljZW50ZXIgVUksIHRoaXMgaXMgdGhlICoqVGVhbSBJRCoqIChmb3IgdGVhbSBwcm9qZWN0cykgb3IgdGhlICoqVXNlciBJRCoqIChmb3IgcGVyc29uYWwgcHJvamVjdHMpLlxuICAgICogQHBhcmFtIHtzdHJpbmd9IGBvcHRpb25zLnVzZXJOYW1lYCBFbWFpbCBvciB1c2VybmFtZSB0byB1c2UgZm9yIGxvZ2dpbmcgaW4uXG4gICAgKiBAcGFyYW0ge3N0cmluZ30gYG9wdGlvbnMucGFzc3dvcmRgIFBhc3N3b3JkIGZvciBzcGVjaWZpZWQgYHVzZXJOYW1lYC5cbiAgICAqIEBwYXJhbSB7c3RyaW5nfSBgb3B0aW9ucy5wcm9qZWN0YCAoT3B0aW9uYWwpIFRoZSAqKlByb2plY3QgSUQqKiBmb3IgdGhlIHByb2plY3QgdG8gbG9nIHRoaXMgdXNlciBpbnRvLlxuICAgICogQHBhcmFtIHtzdHJpbmd9IGBvcHRpb25zLmdyb3VwSWRgIFRoZSBpZCBvZiB0aGUgZ3JvdXAgdG8gd2hpY2ggYHVzZXJOYW1lYCBiZWxvbmdzLiBSZXF1aXJlZCBmb3IgW2VuZCB1c2Vyc10oLi4vLi4vLi4vZ2xvc3NhcnkvI3VzZXJzKSBpZiB0aGUgYHByb2plY3RgIGlzIHNwZWNpZmllZCBhbmQgaWYgdGhlIGVuZCB1c2VycyBhcmUgbWVtYmVycyBvZiBtdWx0aXBsZSBbZ3JvdXBzXSguLi8uLi8uLi9nbG9zc2FyeS8jZ3JvdXBzKSwgb3RoZXJ3aXNlIG9wdGlvbmFsLlxuICAgICovXG4gICAgbG9naW46IGZ1bmN0aW9uIChvcHRpb25zKSB7XG4gICAgICAgIHZhciBfdGhpcyA9IHRoaXM7XG4gICAgICAgIHZhciAkZCA9ICQuRGVmZXJyZWQoKTtcbiAgICAgICAgdmFyIHNlc3Npb25NYW5hZ2VyID0gdGhpcy5zZXNzaW9uTWFuYWdlcjtcbiAgICAgICAgdmFyIGFkYXB0ZXJPcHRpb25zID0gc2Vzc2lvbk1hbmFnZXIuZ2V0TWVyZ2VkT3B0aW9ucyh7IHN1Y2Nlc3M6ICQubm9vcCwgZXJyb3I6ICQubm9vcCB9LCBvcHRpb25zKTtcbiAgICAgICAgdmFyIG91dFN1Y2Nlc3MgPSBhZGFwdGVyT3B0aW9ucy5zdWNjZXNzO1xuICAgICAgICB2YXIgb3V0RXJyb3IgPSBhZGFwdGVyT3B0aW9ucy5lcnJvcjtcbiAgICAgICAgdmFyIGdyb3VwSWQgPSBhZGFwdGVyT3B0aW9ucy5ncm91cElkO1xuXG4gICAgICAgIHZhciBkZWNvZGVUb2tlbiA9IGZ1bmN0aW9uICh0b2tlbikge1xuICAgICAgICAgICAgdmFyIGVuY29kZWQgPSB0b2tlbi5zcGxpdCgnLicpWzFdO1xuICAgICAgICAgICAgd2hpbGUgKGVuY29kZWQubGVuZ3RoICUgNCAhPT0gMCkge1xuICAgICAgICAgICAgICAgIGVuY29kZWQgKz0gJz0nO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICB2YXIgZGVjb2RlID0gd2luZG93LmF0b2IgPyB3aW5kb3cuYXRvYiA6IGZ1bmN0aW9uIChlbmNvZGVkKSB7IHJldHVybiBuZXcgQnVmZmVyKGVuY29kZWQsICdiYXNlNjQnKS50b1N0cmluZygnYXNjaWknKTsgfTtcblxuICAgICAgICAgICAgcmV0dXJuIEpTT04ucGFyc2UoZGVjb2RlKGVuY29kZWQpKTtcbiAgICAgICAgfTtcblxuICAgICAgICB2YXIgaGFuZGxlR3JvdXBFcnJvciA9IGZ1bmN0aW9uIChtZXNzYWdlLCBzdGF0dXNDb2RlLCBkYXRhKSB7XG4gICAgICAgICAgICAvLyBsb2dvdXQgdGhlIHVzZXIgc2luY2UgaXQncyBpbiBhbiBpbnZhbGlkIHN0YXRlIHdpdGggbm8gZ3JvdXAgc2VsZWN0ZWRcbiAgICAgICAgICAgIF90aGlzLmxvZ291dCgpLnRoZW4oZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgICAgIHZhciBlcnJvciA9ICQuZXh0ZW5kKHRydWUsIHt9LCBkYXRhLCB7IHN0YXR1c1RleHQ6IG1lc3NhZ2UsIHN0YXR1czogc3RhdHVzQ29kZSB9KTtcbiAgICAgICAgICAgICAgICAkZC5yZWplY3QoZXJyb3IpO1xuICAgICAgICAgICAgfSk7XG4gICAgICAgIH07XG5cbiAgICAgICAgdmFyIGhhbmRsZVN1Y2Nlc3MgPSBmdW5jdGlvbiAocmVzcG9uc2UpIHtcbiAgICAgICAgICAgIC8vanNoaW50IGNhbWVsY2FzZTogZmFsc2VcbiAgICAgICAgICAgIC8vanNjczpkaXNhYmxlXG4gICAgICAgICAgICB2YXIgdG9rZW4gPSByZXNwb25zZS5hY2Nlc3NfdG9rZW47XG4gICAgICAgICAgICB2YXIgdXNlckluZm8gPSBkZWNvZGVUb2tlbih0b2tlbik7XG4gICAgICAgICAgICB2YXIgb2xkR3JvdXBzID0gc2Vzc2lvbk1hbmFnZXIuZ2V0U2Vzc2lvbigpLmdyb3VwcyB8fCB7fTtcbiAgICAgICAgICAgIHZhciB1c2VyR3JvdXBPcHRzID0gJC5leHRlbmQodHJ1ZSwge30sIGFkYXB0ZXJPcHRpb25zLCB7IHN1Y2Nlc3M6ICQubm9vcCB9KTtcbiAgICAgICAgICAgIHZhciBkYXRhID0geyBhdXRoOiByZXNwb25zZSwgdXNlcjogdXNlckluZm8gfTtcbiAgICAgICAgICAgIHZhciBwcm9qZWN0ID0gYWRhcHRlck9wdGlvbnMucHJvamVjdDtcbiAgICAgICAgICAgIHZhciBpc1RlYW1NZW1iZXIgPSB1c2VySW5mby5wYXJlbnRfYWNjb3VudF9pZCA9PT0gbnVsbDtcbiAgICAgICAgICAgIHZhciByZXF1aXJlc0dyb3VwID0gYWRhcHRlck9wdGlvbnMucmVxdWlyZXNHcm91cCAmJiBwcm9qZWN0O1xuXG4gICAgICAgICAgICB2YXIgc2Vzc2lvbkluZm8gPSB7XG4gICAgICAgICAgICAgICAgJ2F1dGhfdG9rZW4nOiB0b2tlbixcbiAgICAgICAgICAgICAgICAnYWNjb3VudCc6IGFkYXB0ZXJPcHRpb25zLmFjY291bnQsXG4gICAgICAgICAgICAgICAgJ3Byb2plY3QnOiBwcm9qZWN0LFxuICAgICAgICAgICAgICAgICd1c2VySWQnOiB1c2VySW5mby51c2VyX2lkLFxuICAgICAgICAgICAgICAgICdncm91cHMnOiBvbGRHcm91cHMsXG4gICAgICAgICAgICAgICAgJ2lzVGVhbU1lbWJlcic6IGlzVGVhbU1lbWJlclxuICAgICAgICAgICAgfTtcbiAgICAgICAgICAgIC8vIFRoZSBncm91cCBpcyBub3QgcmVxdWlyZWQgaWYgdGhlIHVzZXIgaXMgbm90IGxvZ2dpbmcgaW50byBhIHByb2plY3RcbiAgICAgICAgICAgIGlmICghcmVxdWlyZXNHcm91cCkge1xuICAgICAgICAgICAgICAgIHNlc3Npb25NYW5hZ2VyLnNhdmVTZXNzaW9uKHNlc3Npb25JbmZvKTtcbiAgICAgICAgICAgICAgICBvdXRTdWNjZXNzLmFwcGx5KHRoaXMsIFtkYXRhXSk7XG4gICAgICAgICAgICAgICAgJGQucmVzb2x2ZShkYXRhKTtcbiAgICAgICAgICAgICAgICByZXR1cm47XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIHZhciBoYW5kbGVHcm91cExpc3QgPSBmdW5jdGlvbiAoZ3JvdXBMaXN0KSB7XG4gICAgICAgICAgICAgICAgZGF0YS51c2VyR3JvdXBzID0gZ3JvdXBMaXN0O1xuXG4gICAgICAgICAgICAgICAgdmFyIGdyb3VwID0gbnVsbDtcbiAgICAgICAgICAgICAgICBpZiAoZ3JvdXBMaXN0Lmxlbmd0aCA9PT0gMCkge1xuICAgICAgICAgICAgICAgICAgICBoYW5kbGVHcm91cEVycm9yKCdUaGUgdXNlciBoYXMgbm8gZ3JvdXBzIGFzc29jaWF0ZWQgaW4gdGhpcyBhY2NvdW50JywgNDAxLCBkYXRhKTtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgICAgICAgIH0gZWxzZSBpZiAoZ3JvdXBMaXN0Lmxlbmd0aCA9PT0gMSkge1xuICAgICAgICAgICAgICAgICAgICAvLyBTZWxlY3QgdGhlIG9ubHkgZ3JvdXBcbiAgICAgICAgICAgICAgICAgICAgZ3JvdXAgPSBncm91cExpc3RbMF07XG4gICAgICAgICAgICAgICAgfSBlbHNlIGlmIChncm91cExpc3QubGVuZ3RoID4gMSkge1xuICAgICAgICAgICAgICAgICAgICBpZiAoZ3JvdXBJZCkge1xuICAgICAgICAgICAgICAgICAgICAgICAgdmFyIGZpbHRlcmVkR3JvdXBzID0gJC5ncmVwKGdyb3VwTGlzdCwgZnVuY3Rpb24gKHJlc0dyb3VwKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIHJlc0dyb3VwLmdyb3VwSWQgPT09IGdyb3VwSWQ7XG4gICAgICAgICAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgICAgICAgICAgIGdyb3VwID0gZmlsdGVyZWRHcm91cHMubGVuZ3RoID09PSAxID8gZmlsdGVyZWRHcm91cHNbMF0gOiBudWxsO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgaWYgKGdyb3VwKSB7XG4gICAgICAgICAgICAgICAgICAgIC8vIEEgdGVhbSBtZW1iZXIgZG9lcyBub3QgZ2V0IHRoZSBncm91cCBtZW1iZXJzIGJlY2F1c2UgaXMgY2FsbGluZyB0aGUgR3JvdXAgQVBJXG4gICAgICAgICAgICAgICAgICAgIC8vIGJ1dCBpdCdzIGF1dG9tYXRpY2FsbHkgYSBmYWMgdXNlclxuICAgICAgICAgICAgICAgICAgICB2YXIgaXNGYWMgPSBpc1RlYW1NZW1iZXIgPyB0cnVlIDogX2ZpbmRVc2VySW5Hcm91cChncm91cC5tZW1iZXJzLCB1c2VySW5mby51c2VyX2lkKS5yb2xlID09PSAnZmFjaWxpdGF0b3InO1xuICAgICAgICAgICAgICAgICAgICB2YXIgZ3JvdXBEYXRhID0ge1xuICAgICAgICAgICAgICAgICAgICAgICAgZ3JvdXBJZDogZ3JvdXAuZ3JvdXBJZCxcbiAgICAgICAgICAgICAgICAgICAgICAgIGdyb3VwTmFtZTogZ3JvdXAubmFtZSxcbiAgICAgICAgICAgICAgICAgICAgICAgIGlzRmFjOiBpc0ZhY1xuICAgICAgICAgICAgICAgICAgICB9O1xuICAgICAgICAgICAgICAgICAgICB2YXIgc2Vzc2lvbkluZm9XaXRoR3JvdXAgPSBvYmplY3RBc3NpZ24oe30sIHNlc3Npb25JbmZvLCBncm91cERhdGEpO1xuICAgICAgICAgICAgICAgICAgICBzZXNzaW9uSW5mby5ncm91cHNbcHJvamVjdF0gPSBncm91cERhdGE7XG4gICAgICAgICAgICAgICAgICAgIF90aGlzLnNlc3Npb25NYW5hZ2VyLnNhdmVTZXNzaW9uKHNlc3Npb25JbmZvV2l0aEdyb3VwLCBhZGFwdGVyT3B0aW9ucyk7XG4gICAgICAgICAgICAgICAgICAgIG91dFN1Y2Nlc3MuYXBwbHkodGhpcywgW2RhdGFdKTtcbiAgICAgICAgICAgICAgICAgICAgJGQucmVzb2x2ZShkYXRhKTtcbiAgICAgICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICBoYW5kbGVHcm91cEVycm9yKCdUaGlzIHVzZXIgaXMgYXNzb2NpYXRlZCB3aXRoIG1vcmUgdGhhbiBvbmUgZ3JvdXAuIFBsZWFzZSBzcGVjaWZ5IGEgZ3JvdXAgaWQgdG8gbG9nIGludG8gYW5kIHRyeSBhZ2FpbicsIDQwMywgZGF0YSk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfTtcblxuICAgICAgICAgICAgaWYgKCFpc1RlYW1NZW1iZXIpIHtcbiAgICAgICAgICAgICAgICBfdGhpcy5nZXRVc2VyR3JvdXBzKHsgdXNlcklkOiB1c2VySW5mby51c2VyX2lkLCB0b2tlbjogdG9rZW4gfSwgdXNlckdyb3VwT3B0cylcbiAgICAgICAgICAgICAgICAgICAgLnRoZW4oaGFuZGxlR3JvdXBMaXN0LCAkZC5yZWplY3QpO1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICB2YXIgb3B0cyA9IG9iamVjdEFzc2lnbih7fSwgdXNlckdyb3VwT3B0cywgeyB0b2tlbjogdG9rZW4gfSk7XG4gICAgICAgICAgICAgICAgdmFyIGdyb3VwU2VydmljZSA9IG5ldyBHcm91cFNlcnZpY2Uob3B0cyk7XG4gICAgICAgICAgICAgICAgZ3JvdXBTZXJ2aWNlLmdldEdyb3Vwcyh7IGFjY291bnQ6IGFkYXB0ZXJPcHRpb25zLmFjY291bnQsIHByb2plY3Q6IHByb2plY3QgfSlcbiAgICAgICAgICAgICAgICAgICAgLnRoZW4oZnVuY3Rpb24gKGdyb3Vwcykge1xuICAgICAgICAgICAgICAgICAgICAgICAgLy8gR3JvdXAgQVBJIHJldHVybnMgaWQgaW5zdGVhZCBvZiBncm91cElkXG4gICAgICAgICAgICAgICAgICAgICAgICBncm91cHMuZm9yRWFjaChmdW5jdGlvbiAoZ3JvdXApIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBncm91cC5ncm91cElkID0gZ3JvdXAuaWQ7XG4gICAgICAgICAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgICAgICAgICAgIGhhbmRsZUdyb3VwTGlzdChncm91cHMpO1xuICAgICAgICAgICAgICAgICAgICB9LCAkZC5yZWplY3QpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9O1xuXG4gICAgICAgIGFkYXB0ZXJPcHRpb25zLnN1Y2Nlc3MgPSBoYW5kbGVTdWNjZXNzO1xuICAgICAgICBhZGFwdGVyT3B0aW9ucy5lcnJvciA9IGZ1bmN0aW9uIChyZXNwb25zZSkge1xuICAgICAgICAgICAgaWYgKGFkYXB0ZXJPcHRpb25zLmFjY291bnQpIHtcbiAgICAgICAgICAgICAgICAvLyBUcnkgdG8gbG9naW4gYXMgYSBzeXN0ZW0gdXNlclxuICAgICAgICAgICAgICAgIGFkYXB0ZXJPcHRpb25zLmFjY291bnQgPSBudWxsO1xuICAgICAgICAgICAgICAgIGFkYXB0ZXJPcHRpb25zLmVycm9yID0gZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgICAgICAgICBvdXRFcnJvci5hcHBseSh0aGlzLCBhcmd1bWVudHMpO1xuICAgICAgICAgICAgICAgICAgICAkZC5yZWplY3QocmVzcG9uc2UpO1xuICAgICAgICAgICAgICAgIH07XG5cbiAgICAgICAgICAgICAgICBfdGhpcy5hdXRoQWRhcHRlci5sb2dpbihhZGFwdGVyT3B0aW9ucyk7XG4gICAgICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICBvdXRFcnJvci5hcHBseSh0aGlzLCBhcmd1bWVudHMpO1xuICAgICAgICAgICAgJGQucmVqZWN0KHJlc3BvbnNlKTtcbiAgICAgICAgfTtcblxuICAgICAgICB0aGlzLmF1dGhBZGFwdGVyLmxvZ2luKGFkYXB0ZXJPcHRpb25zKTtcbiAgICAgICAgcmV0dXJuICRkLnByb21pc2UoKTtcbiAgICB9LFxuXG4gICAgLyoqXG4gICAgKiBMb2dzIHVzZXIgb3V0IGJ5IGNsZWFyaW5nIGFsbCBzZXNzaW9uIGluZm9ybWF0aW9uLlxuICAgICpcbiAgICAqICoqRXhhbXBsZSoqXG4gICAgKlxuICAgICogICAgICAgYXV0aE1nci5sb2dvdXQoKTtcbiAgICAqXG4gICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICpcbiAgICAqIEBwYXJhbSB7T2JqZWN0fSBgb3B0aW9uc2AgKE9wdGlvbmFsKSBPdmVycmlkZXMgZm9yIGNvbmZpZ3VyYXRpb24gb3B0aW9ucy5cbiAgICAqL1xuICAgIGxvZ291dDogZnVuY3Rpb24gKG9wdGlvbnMpIHtcbiAgICAgICAgdmFyIF90aGlzID0gdGhpcztcbiAgICAgICAgdmFyIGFkYXB0ZXJPcHRpb25zID0gdGhpcy5zZXNzaW9uTWFuYWdlci5nZXRNZXJnZWRPcHRpb25zKG9wdGlvbnMpO1xuXG4gICAgICAgIHZhciByZW1vdmVDb29raWVGbiA9IGZ1bmN0aW9uIChyZXNwb25zZSkge1xuICAgICAgICAgICAgX3RoaXMuc2Vzc2lvbk1hbmFnZXIucmVtb3ZlU2Vzc2lvbigpO1xuICAgICAgICB9O1xuXG4gICAgICAgIHJldHVybiB0aGlzLmF1dGhBZGFwdGVyLmxvZ291dChhZGFwdGVyT3B0aW9ucykuZG9uZShyZW1vdmVDb29raWVGbik7XG4gICAgfSxcblxuICAgIC8qKlxuICAgICAqIFJldHVybnMgdGhlIGV4aXN0aW5nIHVzZXIgYWNjZXNzIHRva2VuIGlmIHRoZSB1c2VyIGlzIGFscmVhZHkgbG9nZ2VkIGluLiBPdGhlcndpc2UsIGxvZ3MgdGhlIHVzZXIgaW4sIGNyZWF0aW5nIGEgbmV3IHVzZXIgYWNjZXNzIHRva2VuLCBhbmQgcmV0dXJucyB0aGUgbmV3IHRva2VuLiAoU2VlIFttb3JlIGJhY2tncm91bmQgb24gYWNjZXNzIHRva2Vuc10oLi4vLi4vLi4vcHJvamVjdF9hY2Nlc3MvKSkuXG4gICAgICpcbiAgICAgKiAqKkV4YW1wbGUqKlxuICAgICAqXG4gICAgICogICAgICBhdXRoTWdyLmdldFRva2VuKClcbiAgICAgKiAgICAgICAgICAudGhlbihmdW5jdGlvbiAodG9rZW4pIHtcbiAgICAgKiAgICAgICAgICAgICAgY29uc29sZS5sb2coJ015IHRva2VuIGlzICcsIHRva2VuKTtcbiAgICAgKiAgICAgICAgICB9KTtcbiAgICAgKlxuICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICogQHBhcmFtIHtPYmplY3R9IGBvcHRpb25zYCAoT3B0aW9uYWwpIE92ZXJyaWRlcyBmb3IgY29uZmlndXJhdGlvbiBvcHRpb25zLlxuICAgICAqL1xuICAgIGdldFRva2VuOiBmdW5jdGlvbiAob3B0aW9ucykge1xuICAgICAgICB2YXIgaHR0cE9wdGlvbnMgPSB0aGlzLnNlc3Npb25NYW5hZ2VyLmdldE1lcmdlZE9wdGlvbnMob3B0aW9ucyk7XG5cbiAgICAgICAgdmFyIHNlc3Npb24gPSB0aGlzLnNlc3Npb25NYW5hZ2VyLmdldFNlc3Npb24oKTtcbiAgICAgICAgdmFyICRkID0gJC5EZWZlcnJlZCgpO1xuICAgICAgICAvL2pzaGludCBjYW1lbGNhc2U6IGZhbHNlXG4gICAgICAgIC8vanNjczpkaXNhYmxlXG4gICAgICAgIGlmIChzZXNzaW9uLmF1dGhfdG9rZW4pIHtcbiAgICAgICAgICAgICRkLnJlc29sdmUoc2Vzc2lvbi5hdXRoX3Rva2VuKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIHRoaXMubG9naW4oaHR0cE9wdGlvbnMpLnRoZW4oJGQucmVzb2x2ZSk7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuICRkLnByb21pc2UoKTtcbiAgICB9LFxuXG4gICAgLyoqXG4gICAgICogUmV0dXJucyBhbiBhcnJheSBvZiBncm91cCByZWNvcmRzLCBvbmUgZm9yIGVhY2ggZ3JvdXAgb2Ygd2hpY2ggdGhlIGN1cnJlbnQgdXNlciBpcyBhIG1lbWJlci4gRWFjaCBncm91cCByZWNvcmQgaW5jbHVkZXMgdGhlIGdyb3VwIGBuYW1lYCwgYGFjY291bnRgLCBgcHJvamVjdGAsIGFuZCBgZ3JvdXBJZGAuXG4gICAgICpcbiAgICAgKiBJZiBzb21lIGVuZCB1c2VycyBpbiB5b3VyIHByb2plY3QgYXJlIG1lbWJlcnMgb2YgbXVsdGlwbGUgZ3JvdXBzLCB0aGlzIGlzIGEgdXNlZnVsIG1ldGhvZCB0byBjYWxsIG9uIHlvdXIgcHJvamVjdCdzIGxvZ2luIHBhZ2UuIFdoZW4gdGhlIHVzZXIgYXR0ZW1wdHMgdG8gbG9nIGluLCB5b3UgY2FuIHVzZSB0aGlzIHRvIGRpc3BsYXkgdGhlIGdyb3VwcyBvZiB3aGljaCB0aGUgdXNlciBpcyBtZW1iZXIsIGFuZCBoYXZlIHRoZSB1c2VyIHNlbGVjdCB0aGUgY29ycmVjdCBncm91cCB0byBsb2cgaW4gdG8gZm9yIHRoaXMgc2Vzc2lvbi5cbiAgICAgKlxuICAgICAqICoqRXhhbXBsZSoqXG4gICAgICpcbiAgICAgKiAgICAgIC8vIGdldCBncm91cHMgZm9yIGN1cnJlbnQgdXNlclxuICAgICAqICAgICAgdmFyIHNlc3Npb25PYmogPSBhdXRoTWdyLmdldEN1cnJlbnRVc2VyU2Vzc2lvbkluZm8oKTtcbiAgICAgKiAgICAgIGF1dGhNZ3IuZ2V0VXNlckdyb3Vwcyh7IHVzZXJJZDogc2Vzc2lvbk9iai51c2VySWQsIHRva2VuOiBzZXNzaW9uT2JqLmF1dGhfdG9rZW4gfSlcbiAgICAgKiAgICAgICAgICAudGhlbihmdW5jdGlvbiAoZ3JvdXBzKSB7XG4gICAgICogICAgICAgICAgICAgIGZvciAodmFyIGk9MDsgaSA8IGdyb3Vwcy5sZW5ndGg7IGkrKylcbiAgICAgKiAgICAgICAgICAgICAgICAgIHsgY29uc29sZS5sb2coZ3JvdXBzW2ldLm5hbWUpOyB9XG4gICAgICogICAgICAgICAgfSk7XG4gICAgICpcbiAgICAgKiAgICAgIC8vIGdldCBncm91cHMgZm9yIHBhcnRpY3VsYXIgdXNlclxuICAgICAqICAgICAgYXV0aE1nci5nZXRVc2VyR3JvdXBzKHt1c2VySWQ6ICdiMWMxOWRkYS0yZDJlLTQ3NzctYWQ1ZC0zOTI5ZjE3ZTg2ZDMnLCB0b2tlbjogc2F2ZWRQcm9qQWNjZXNzVG9rZW4gfSk7XG4gICAgICpcbiAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAqIEBwYXJhbSB7T2JqZWN0fSBgcGFyYW1zYCBPYmplY3Qgd2l0aCBhIHVzZXJJZCBhbmQgdG9rZW4gcHJvcGVydGllcy5cbiAgICAgKiBAcGFyYW0ge1N0cmluZ30gYHBhcmFtcy51c2VySWRgIFRoZSB1c2VySWQuIElmIGxvb2tpbmcgdXAgZ3JvdXBzIGZvciB0aGUgY3VycmVudGx5IGxvZ2dlZCBpbiB1c2VyLCB0aGlzIGlzIGluIHRoZSBzZXNzaW9uIGluZm9ybWF0aW9uLiBPdGhlcndpc2UsIHBhc3MgYSBzdHJpbmcuXG4gICAgICogQHBhcmFtIHtTdHJpbmd9IGBwYXJhbXMudG9rZW5gIFRoZSBhdXRob3JpemF0aW9uIGNyZWRlbnRpYWxzIChhY2Nlc3MgdG9rZW4pIHRvIHVzZSBmb3IgY2hlY2tpbmcgdGhlIGdyb3VwcyBmb3IgdGhpcyB1c2VyLiBJZiBsb29raW5nIHVwIGdyb3VwcyBmb3IgdGhlIGN1cnJlbnRseSBsb2dnZWQgaW4gdXNlciwgdGhpcyBpcyBpbiB0aGUgc2Vzc2lvbiBpbmZvcm1hdGlvbi4gQSB0ZWFtIG1lbWJlcidzIHRva2VuIG9yIGEgcHJvamVjdCBhY2Nlc3MgdG9rZW4gY2FuIGFjY2VzcyBhbGwgdGhlIGdyb3VwcyBmb3IgYWxsIGVuZCB1c2VycyBpbiB0aGUgdGVhbSBvciBwcm9qZWN0LlxuICAgICAqIEBwYXJhbSB7T2JqZWN0fSBgb3B0aW9uc2AgKE9wdGlvbmFsKSBPdmVycmlkZXMgZm9yIGNvbmZpZ3VyYXRpb24gb3B0aW9ucy5cbiAgICAgKi9cbiAgICBnZXRVc2VyR3JvdXBzOiBmdW5jdGlvbiAocGFyYW1zLCBvcHRpb25zKSB7XG4gICAgICAgIHZhciBhZGFwdGVyT3B0aW9ucyA9IHRoaXMuc2Vzc2lvbk1hbmFnZXIuZ2V0TWVyZ2VkT3B0aW9ucyh7IHN1Y2Nlc3M6ICQubm9vcCB9LCBvcHRpb25zKTtcbiAgICAgICAgdmFyICRkID0gJC5EZWZlcnJlZCgpO1xuICAgICAgICB2YXIgb3V0U3VjY2VzcyA9IGFkYXB0ZXJPcHRpb25zLnN1Y2Nlc3M7XG5cbiAgICAgICAgYWRhcHRlck9wdGlvbnMuc3VjY2VzcyA9IGZ1bmN0aW9uIChtZW1iZXJJbmZvKSB7XG4gICAgICAgICAgICAvLyBUaGUgbWVtYmVyIEFQSSBpcyBhdCB0aGUgYWNjb3VudCBzY29wZSwgd2UgZmlsdGVyIGJ5IHByb2plY3RcbiAgICAgICAgICAgIGlmIChhZGFwdGVyT3B0aW9ucy5wcm9qZWN0KSB7XG4gICAgICAgICAgICAgICAgbWVtYmVySW5mbyA9ICQuZ3JlcChtZW1iZXJJbmZvLCBmdW5jdGlvbiAoZ3JvdXApIHtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIGdyb3VwLnByb2plY3QgPT09IGFkYXB0ZXJPcHRpb25zLnByb2plY3Q7XG4gICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIG91dFN1Y2Nlc3MuYXBwbHkodGhpcywgW21lbWJlckluZm9dKTtcbiAgICAgICAgICAgICRkLnJlc29sdmUobWVtYmVySW5mbyk7XG4gICAgICAgIH07XG5cbiAgICAgICAgdmFyIG1lbWJlckFkYXB0ZXIgPSBuZXcgTWVtYmVyQWRhcHRlcih7IHRva2VuOiBwYXJhbXMudG9rZW4gfSk7XG4gICAgICAgIG1lbWJlckFkYXB0ZXIuZ2V0R3JvdXBzRm9yVXNlcihwYXJhbXMsIGFkYXB0ZXJPcHRpb25zKS5mYWlsKCRkLnJlamVjdCk7XG4gICAgICAgIHJldHVybiAkZC5wcm9taXNlKCk7XG4gICAgfSxcblxuICAgIC8qKlxuICAgICAqIFJldHVybnMgc2Vzc2lvbiBpbmZvcm1hdGlvbiBmb3IgdGhlIGN1cnJlbnQgdXNlciwgaW5jbHVkaW5nIHRoZSBgdXNlcklkYCwgYGFjY291bnRgLCBgcHJvamVjdGAsIGBncm91cElkYCwgYGdyb3VwTmFtZWAsIGBpc0ZhY2AgKHdoZXRoZXIgdGhlIGVuZCB1c2VyIGlzIGEgZmFjaWxpdGF0b3Igb2YgdGhpcyBncm91cCksIGFuZCBgYXV0aF90b2tlbmAgKHVzZXIgYWNjZXNzIHRva2VuKS5cbiAgICAgKlxuICAgICAqICpJbXBvcnRhbnQqOiBUaGlzIG1ldGhvZCBpcyBzeW5jaHJvbm91cy4gVGhlIHNlc3Npb24gaW5mb3JtYXRpb24gaXMgcmV0dXJuZWQgaW1tZWRpYXRlbHkgaW4gYW4gb2JqZWN0OyBubyBjYWxsYmFja3Mgb3IgcHJvbWlzZXMgYXJlIG5lZWRlZC5cbiAgICAgKlxuICAgICAqIFNlc3Npb24gaW5mb3JtYXRpb24gaXMgc3RvcmVkIGluIGEgY29va2llIGluIHRoZSBicm93c2VyLlxuICAgICAqXG4gICAgICogKipFeGFtcGxlKipcbiAgICAgKlxuICAgICAqICAgICAgdmFyIHNlc3Npb25PYmogPSBhdXRoTWdyLmdldEN1cnJlbnRVc2VyU2Vzc2lvbkluZm8oKTtcbiAgICAgKlxuICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICogQHBhcmFtIHtPYmplY3R9IGBvcHRpb25zYCAoT3B0aW9uYWwpIE92ZXJyaWRlcyBmb3IgY29uZmlndXJhdGlvbiBvcHRpb25zLlxuICAgICAqL1xuICAgIGdldEN1cnJlbnRVc2VyU2Vzc2lvbkluZm86IGZ1bmN0aW9uIChvcHRpb25zKSB7XG4gICAgICAgIHJldHVybiB0aGlzLnNlc3Npb25NYW5hZ2VyLmdldFNlc3Npb24ob3B0aW9ucyk7XG4gICAgfSxcblxuICAgIC8qXG4gICAgICogQWRkcyBvbmUgb3IgbW9yZSBncm91cHMgdG8gdGhlIGN1cnJlbnQgc2Vzc2lvbi4gXG4gICAgICpcbiAgICAgKiBUaGlzIG1ldGhvZCBhc3N1bWVzIHRoYXQgdGhlIHByb2plY3QgYW5kIGdyb3VwIGV4aXN0IGFuZCB0aGUgdXNlciBzcGVjaWZpZWQgaW4gdGhlIHNlc3Npb24gaXMgcGFydCBvZiB0aGlzIHByb2plY3QgYW5kIGdyb3VwLlxuICAgICAqXG4gICAgICogUmV0dXJucyB0aGUgbmV3IHNlc3Npb24gb2JqZWN0LlxuICAgICAqXG4gICAgICogKipFeGFtcGxlKipcbiAgICAgKlxuICAgICAqICAgICAgYXV0aE1nci5hZGRHcm91cHMoeyBwcm9qZWN0OiAnaGVsbG8td29ybGQnLCBncm91cE5hbWU6ICdncm91cE5hbWUnLCBncm91cElkOiAnZ3JvdXBJZCcgfSk7XG4gICAgICogICAgICBhdXRoTWdyLmFkZEdyb3VwcyhbeyBwcm9qZWN0OiAnaGVsbG8td29ybGQnLCBncm91cE5hbWU6ICdncm91cE5hbWUnLCBncm91cElkOiAnZ3JvdXBJZCcgfSwgeyBwcm9qZWN0OiAnaGVsbG8td29ybGQnLCBncm91cE5hbWU6ICcuLi4nIH1dKTtcbiAgICAgKlxuICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICogQHBhcmFtIHtvYmplY3R8YXJyYXl9IGBncm91cHNgIChSZXF1aXJlZCkgVGhlIGdyb3VwIG9iamVjdCBtdXN0IGNvbnRhaW4gdGhlIGBwcm9qZWN0YCAoKipQcm9qZWN0IElEKiopIGFuZCBgZ3JvdXBOYW1lYCBwcm9wZXJ0aWVzLiBJZiBwYXNzaW5nIGFuIGFycmF5IG9mIHN1Y2ggb2JqZWN0cywgYWxsIG9mIHRoZSBvYmplY3RzIG11c3QgY29udGFpbiAqZGlmZmVyZW50KiBgcHJvamVjdGAgKCoqUHJvamVjdCBJRCoqKSB2YWx1ZXM6IGFsdGhvdWdoIGVuZCB1c2VycyBtYXkgYmUgbG9nZ2VkIGluIHRvIG11bHRpcGxlIHByb2plY3RzIGF0IG9uY2UsIHRoZXkgbWF5IG9ubHkgYmUgbG9nZ2VkIGluIHRvIG9uZSBncm91cCBwZXIgcHJvamVjdCBhdCBhIHRpbWUuXG4gICAgICogQHBhcmFtIHtzdHJpbmd9IGBncm91cC5pc0ZhY2AgKG9wdGlvbmFsKSBEZWZhdWx0cyB0byBgZmFsc2VgLiBTZXQgdG8gYHRydWVgIGlmIHRoZSB1c2VyIGluIHRoZSBzZXNzaW9uIHNob3VsZCBiZSBhIGZhY2lsaXRhdG9yIGluIHRoaXMgZ3JvdXAuXG4gICAgICogQHBhcmFtIHtzdHJpbmd9IGBncm91cC5ncm91cElkYCAob3B0aW9uYWwpIERlZmF1bHRzIHRvIHVuZGVmaW5lZC4gTmVlZGVkIG1vc3RseSBmb3IgdGhlIE1lbWJlcnMgQVBJLlxuICAgICovXG4gICAgYWRkR3JvdXBzOiBmdW5jdGlvbiAoZ3JvdXBzKSB7XG4gICAgICAgIHZhciBzZXNzaW9uID0gdGhpcy5nZXRDdXJyZW50VXNlclNlc3Npb25JbmZvKCk7XG4gICAgICAgIHZhciBpc0FycmF5ID0gQXJyYXkuaXNBcnJheShncm91cHMpO1xuICAgICAgICBncm91cHMgPSBpc0FycmF5ID8gZ3JvdXBzIDogW2dyb3Vwc107XG5cbiAgICAgICAgJC5lYWNoKGdyb3VwcywgZnVuY3Rpb24gKGluZGV4LCBncm91cCkge1xuICAgICAgICAgICAgdmFyIGV4dGVuZGVkR3JvdXAgPSAkLmV4dGVuZCh7fSwgeyBpc0ZhYzogZmFsc2UgfSwgZ3JvdXApO1xuICAgICAgICAgICAgdmFyIHByb2plY3QgPSBleHRlbmRlZEdyb3VwLnByb2plY3Q7XG4gICAgICAgICAgICB2YXIgdmFsaWRQcm9wcyA9IFsnZ3JvdXBOYW1lJywgJ2dyb3VwSWQnLCAnaXNGYWMnXTtcbiAgICAgICAgICAgIGlmICghcHJvamVjdCB8fCAhZXh0ZW5kZWRHcm91cC5ncm91cE5hbWUpIHtcbiAgICAgICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ05vIHByb2plY3Qgb3IgZ3JvdXBOYW1lIHNwZWNpZmllZC4nKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIC8vIGZpbHRlciBvYmplY3RcbiAgICAgICAgICAgIGV4dGVuZGVkR3JvdXAgPSBfcGljayhleHRlbmRlZEdyb3VwLCB2YWxpZFByb3BzKTtcbiAgICAgICAgICAgIHNlc3Npb24uZ3JvdXBzW3Byb2plY3RdID0gZXh0ZW5kZWRHcm91cDtcbiAgICAgICAgfSk7XG4gICAgICAgIHRoaXMuc2Vzc2lvbk1hbmFnZXIuc2F2ZVNlc3Npb24oc2Vzc2lvbik7XG4gICAgICAgIHJldHVybiBzZXNzaW9uO1xuICAgIH1cbn0pO1xuXG5tb2R1bGUuZXhwb3J0cyA9IEF1dGhNYW5hZ2VyO1xuIiwiJ3VzZSBzdHJpY3QnO1xuXG52YXIgQ2hhbm5lbCA9IHJlcXVpcmUoJy4uL3NlcnZpY2UvY2hhbm5lbC1zZXJ2aWNlJyk7XG52YXIgU2Vzc2lvbk1hbmFnZXIgPSByZXF1aXJlKCcuLi9zdG9yZS9zZXNzaW9uLW1hbmFnZXInKTtcblxuLyoqXG4gKiAjIyBDaGFubmVsIE1hbmFnZXJcbiAqXG4gKiBUaGVyZSBhcmUgdHdvIG1haW4gdXNlIGNhc2VzIGZvciB0aGUgY2hhbm5lbDogZXZlbnQgbm90aWZpY2F0aW9ucyBhbmQgY2hhdCBtZXNzYWdlcy5cbiAqXG4gKiBUaGUgQ2hhbm5lbCBNYW5hZ2VyIGlzIGEgd3JhcHBlciBhcm91bmQgdGhlIGRlZmF1bHQgW2NvbWV0ZCBKYXZhU2NyaXB0IGxpYnJhcnldKGh0dHA6Ly9kb2NzLmNvbWV0ZC5vcmcvMi9yZWZlcmVuY2UvamF2YXNjcmlwdC5odG1sKSwgYCQuY29tZXRkYC4gSXQgcHJvdmlkZXMgYSBmZXcgbmljZSBmZWF0dXJlcyB0aGF0IGAkLmNvbWV0ZGAgZG9lc24ndCwgaW5jbHVkaW5nOlxuICpcbiAqICogQXV0b21hdGljIHJlLXN1YnNjcmlwdGlvbiB0byBjaGFubmVscyBpZiB5b3UgbG9zZSB5b3VyIGNvbm5lY3Rpb25cbiAqICogT25saW5lIC8gT2ZmbGluZSBub3RpZmljYXRpb25zXG4gKiAqICdFdmVudHMnIGZvciBjb21ldGQgbm90aWZpY2F0aW9ucyAoaW5zdGVhZCBvZiBoYXZpbmcgdG8gbGlzdGVuIG9uIHNwZWNpZmljIG1ldGEgY2hhbm5lbHMpXG4gKlxuICogV2hpbGUgeW91IGNhbiB3b3JrIGRpcmVjdGx5IHdpdGggdGhlIENoYW5uZWwgTWFuYWdlciB0aHJvdWdoIE5vZGUuanMgKGZvciBleGFtcGxlLCBgcmVxdWlyZSgnbWFuYWdlci9jaGFubmVsLW1hbmFnZXInKWApIC0tIG9yIGV2ZW4gd29yayBkaXJlY3RseSB3aXRoIGAkLmNvbWV0ZGAgYW5kIEVwaWNlbnRlcidzIHVuZGVybHlpbmcgW1B1c2ggQ2hhbm5lbCBBUEldKC4uLy4uLy4uL3Jlc3RfYXBpcy9tdWx0aXBsYXllci9jaGFubmVsLykgLS0gbW9zdCBvZnRlbiBpdCB3aWxsIGJlIGVhc2llc3QgdG8gd29yayB3aXRoIHRoZSBbRXBpY2VudGVyIENoYW5uZWwgTWFuYWdlcl0oLi4vZXBpY2VudGVyLWNoYW5uZWwtbWFuYWdlci8pLiBUaGUgRXBpY2VudGVyIENoYW5uZWwgTWFuYWdlciBpcyBhIHdyYXBwZXIgdGhhdCBpbnN0YW50aWF0ZXMgYSBDaGFubmVsIE1hbmFnZXIgd2l0aCBFcGljZW50ZXItc3BlY2lmaWMgZGVmYXVsdHMuXG4gKlxuICogWW91J2xsIG5lZWQgdG8gaW5jbHVkZSB0aGUgYGVwaWNlbnRlci1tdWx0aXBsYXllci1kZXBlbmRlbmNpZXMuanNgIGxpYnJhcnkgaW4gYWRkaXRpb24gdG8gdGhlIGBlcGljZW50ZXIuanNgIGxpYnJhcnkgaW4geW91ciBwcm9qZWN0IHRvIHVzZSB0aGUgQ2hhbm5lbCBNYW5hZ2VyLiAoU2VlIFtJbmNsdWRpbmcgRXBpY2VudGVyLmpzXSguLi8uLi8jaW5jbHVkZSkuKVxuICpcbiAqIFRvIHVzZSB0aGUgQ2hhbm5lbCBNYW5hZ2VyIGluIGNsaWVudC1zaWRlIEphdmFTY3JpcHQsIGluc3RhbnRpYXRlIHRoZSBbRXBpY2VudGVyIENoYW5uZWwgTWFuYWdlcl0oLi4vZXBpY2VudGVyLWNoYW5uZWwtbWFuYWdlci8pLCBnZXQgdGhlIGNoYW5uZWwsIHRoZW4gdXNlIHRoZSBjaGFubmVsJ3MgYHN1YnNjcmliZSgpYCBhbmQgYHB1Ymxpc2goKWAgbWV0aG9kcyB0byBzdWJzY3JpYmUgdG8gdG9waWNzIG9yIHB1Ymxpc2ggZGF0YSB0byB0b3BpY3MuXG4gKlxuICogICAgICAgIHZhciBjbSA9IG5ldyBGLm1hbmFnZXIuQ2hhbm5lbE1hbmFnZXIoKTtcbiAqICAgICAgICB2YXIgY2hhbm5lbCA9IGNtLmdldENoYW5uZWwoKTtcbiAqXG4gKiAgICAgICAgY2hhbm5lbC5zdWJzY3JpYmUoJ3RvcGljJywgY2FsbGJhY2spO1xuICogICAgICAgIGNoYW5uZWwucHVibGlzaCgndG9waWMnLCB7IG15RGF0YTogMTAwIH0pO1xuICpcbiAqIFRoZSBwYXJhbWV0ZXJzIGZvciBpbnN0YW50aWF0aW5nIGEgQ2hhbm5lbCBNYW5hZ2VyIGluY2x1ZGU6XG4gKlxuICogKiBgb3B0aW9uc2AgVGhlIG9wdGlvbnMgb2JqZWN0IHRvIGNvbmZpZ3VyZSB0aGUgQ2hhbm5lbCBNYW5hZ2VyLiBCZXNpZGVzIHRoZSBjb21tb24gb3B0aW9ucyBsaXN0ZWQgaGVyZSwgc2VlIGh0dHA6Ly9kb2NzLmNvbWV0ZC5vcmcvcmVmZXJlbmNlL2phdmFzY3JpcHQuaHRtbCBmb3Igb3RoZXIgc3VwcG9ydGVkIG9wdGlvbnMuXG4gKiAqIGBvcHRpb25zLnVybGAgVGhlIENvbWV0ZCBlbmRwb2ludCBVUkwuXG4gKiAqIGBvcHRpb25zLndlYnNvY2tldEVuYWJsZWRgIFdoZXRoZXIgd2Vic29ja2V0IHN1cHBvcnQgaXMgYWN0aXZlIChib29sZWFuKS5cbiAqICogYG9wdGlvbnMuY2hhbm5lbGAgT3RoZXIgZGVmYXVsdHMgdG8gcGFzcyBvbiB0byBpbnN0YW5jZXMgb2YgdGhlIHVuZGVybHlpbmcgQ2hhbm5lbCBTZXJ2aWNlLiBTZWUgW0NoYW5uZWwgU2VydmljZV0oLi4vY2hhbm5lbC1zZXJ2aWNlLykgZm9yIGRldGFpbHMuXG4gKlxuICovXG52YXIgQ2hhbm5lbE1hbmFnZXIgPSBmdW5jdGlvbiAob3B0aW9ucykge1xuICAgIGlmICghJC5jb21ldGQpIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdDb21ldGQgbGlicmFyeSBub3QgZm91bmQuIFBsZWFzZSBpbmNsdWRlIGVwaWNlbnRlci1tdWx0aXBsYXllci1kZXBlbmRlbmNpZXMuanMnKTtcbiAgICB9XG4gICAgaWYgKCFvcHRpb25zIHx8ICFvcHRpb25zLnVybCkge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ1BsZWFzZSBwcm92aWRlIGFuIHVybCBmb3IgdGhlIGNvbWV0ZCBzZXJ2ZXInKTtcbiAgICB9XG5cbiAgICB2YXIgZGVmYXVsdHMgPSB7XG4gICAgICAgIC8qKlxuICAgICAgICAgKiBUaGUgQ29tZXRkIGVuZHBvaW50IFVSTC5cbiAgICAgICAgICogQHR5cGUge3N0cmluZ31cbiAgICAgICAgICovXG4gICAgICAgIHVybDogJycsXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIFRoZSBsb2cgbGV2ZWwgZm9yIHRoZSBjaGFubmVsIChsb2dzIHRvIGNvbnNvbGUpLlxuICAgICAgICAgKiBAdHlwZSB7c3RyaW5nfVxuICAgICAgICAgKi9cbiAgICAgICAgbG9nTGV2ZWw6ICdpbmZvJyxcblxuICAgICAgICAvKipcbiAgICAgICAgICogV2hldGhlciB3ZWJzb2NrZXQgc3VwcG9ydCBpcyBhY3RpdmUuIERlZmF1bHRzIHRvIGBmYWxzZWA7IEVwaWNlbnRlciBkb2Vzbid0IGN1cnJlbnRseSBzdXBwb3J0IGNvbW11bmljYXRpb24gdGhyb3VnaCB3ZWJzb2NrZXRzLlxuICAgICAgICAgKiBAdHlwZSB7Ym9vbGVhbn1cbiAgICAgICAgICovXG4gICAgICAgIHdlYnNvY2tldEVuYWJsZWQ6IGZhbHNlLFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBJZiBmYWxzZSBlYWNoIGluc3RhbmNlIG9mIENoYW5uZWwgd2lsbCBoYXZlIGEgc2VwYXJhdGUgY29tZXRkIGNvbm5lY3Rpb24gdG8gc2VydmVyLCB3aGljaCBjb3VsZCBiZSBub2lzeS4gU2V0IHRvIHRydWUgdG8gcmUtdXNlIHRoZSBzYW1lIGNvbm5lY3Rpb24gYWNyb3NzIGluc3RhbmNlcy5cbiAgICAgICAgICogQHR5cGUge2Jvb2xlYW59XG4gICAgICAgICAqL1xuICAgICAgICBzaGFyZUNvbm5lY3Rpb246IGZhbHNlLFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBPdGhlciBkZWZhdWx0cyB0byBwYXNzIG9uIHRvIGluc3RhbmNlcyBvZiB0aGUgdW5kZXJseWluZyBbQ2hhbm5lbCBTZXJ2aWNlXSguLi9jaGFubmVsLXNlcnZpY2UvKSwgd2hpY2ggYXJlIGNyZWF0ZWQgdGhyb3VnaCBgZ2V0Q2hhbm5lbCgpYC5cbiAgICAgICAgICogQHR5cGUge29iamVjdH1cbiAgICAgICAgICovXG4gICAgICAgIGNoYW5uZWw6IHtcblxuICAgICAgICB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBPcHRpb25zIHRvIHBhc3MgdG8gdGhlIGNoYW5uZWwgaGFuZHNoYWtlLlxuICAgICAgICAgKlxuICAgICAgICAgKiBGb3IgZXhhbXBsZSwgdGhlIFtFcGljZW50ZXIgQ2hhbm5lbCBNYW5hZ2VyXSguLi9lcGljZW50ZXItY2hhbm5lbC1tYW5hZ2VyLykgcGFzc2VzIGBleHRgIGFuZCBhdXRob3JpemF0aW9uIGluZm9ybWF0aW9uLiBNb3JlIGluZm9ybWF0aW9uIG9uIHBvc3NpYmxlIG9wdGlvbnMgaXMgaW4gdGhlIGRldGFpbHMgb2YgdGhlIHVuZGVybHlpbmcgW1B1c2ggQ2hhbm5lbCBBUEldKC4uLy4uLy4uL3Jlc3RfYXBpcy9tdWx0aXBsYXllci9jaGFubmVsLykuXG4gICAgICAgICAqXG4gICAgICAgICAqIEB0eXBlIHtvYmplY3R9XG4gICAgICAgICAqL1xuICAgICAgICBoYW5kc2hha2U6IHVuZGVmaW5lZFxuICAgIH07XG4gICAgdGhpcy5zZXNzaW9uTWFuYWdlciA9IG5ldyBTZXNzaW9uTWFuYWdlcigpO1xuICAgIHZhciBkZWZhdWx0Q29tZXRPcHRpb25zID0gdGhpcy5zZXNzaW9uTWFuYWdlci5nZXRNZXJnZWRPcHRpb25zKGRlZmF1bHRzLCBvcHRpb25zKTtcbiAgICB0aGlzLmN1cnJlbnRTdWJzY3JpcHRpb25zID0gW107XG4gICAgdGhpcy5vcHRpb25zID0gZGVmYXVsdENvbWV0T3B0aW9ucztcblxuICAgIGlmIChkZWZhdWx0Q29tZXRPcHRpb25zLnNoYXJlQ29ubmVjdGlvbiAmJiBDaGFubmVsTWFuYWdlci5wcm90b3R5cGUuX2NvbWV0ZCkge1xuICAgICAgICB0aGlzLmNvbWV0ZCA9IENoYW5uZWxNYW5hZ2VyLnByb3RvdHlwZS5fY29tZXRkO1xuICAgICAgICByZXR1cm4gdGhpcztcbiAgICB9XG4gICAgdmFyIGNvbWV0ZCA9IG5ldyAkLkNvbWV0ZCgpO1xuICAgIENoYW5uZWxNYW5hZ2VyLnByb3RvdHlwZS5fY29tZXRkID0gY29tZXRkO1xuXG4gICAgY29tZXRkLndlYnNvY2tldEVuYWJsZWQgPSBkZWZhdWx0Q29tZXRPcHRpb25zLndlYnNvY2tldEVuYWJsZWQ7XG5cbiAgICB0aGlzLmlzQ29ubmVjdGVkID0gZmFsc2U7XG4gICAgdmFyIGNvbm5lY3Rpb25Ccm9rZW4gPSBmdW5jdGlvbiAobWVzc2FnZSkge1xuICAgICAgICAkKHRoaXMpLnRyaWdnZXIoJ2Rpc2Nvbm5lY3QnLCBtZXNzYWdlKTtcbiAgICB9O1xuICAgIHZhciBjb25uZWN0aW9uU3VjY2VlZGVkID0gZnVuY3Rpb24gKG1lc3NhZ2UpIHtcbiAgICAgICAgJCh0aGlzKS50cmlnZ2VyKCdjb25uZWN0JywgbWVzc2FnZSk7XG4gICAgfTtcbiAgICB2YXIgbWUgPSB0aGlzO1xuXG4gICAgY29tZXRkLmNvbmZpZ3VyZShkZWZhdWx0Q29tZXRPcHRpb25zKTtcblxuICAgIGNvbWV0ZC5hZGRMaXN0ZW5lcignL21ldGEvY29ubmVjdCcsIGZ1bmN0aW9uIChtZXNzYWdlKSB7XG4gICAgICAgIHZhciB3YXNDb25uZWN0ZWQgPSB0aGlzLmlzQ29ubmVjdGVkO1xuICAgICAgICB0aGlzLmlzQ29ubmVjdGVkID0gKG1lc3NhZ2Uuc3VjY2Vzc2Z1bCA9PT0gdHJ1ZSk7XG4gICAgICAgIGlmICghd2FzQ29ubmVjdGVkICYmIHRoaXMuaXNDb25uZWN0ZWQpIHsgLy9Db25uZWN0aW5nIGZvciB0aGUgZmlyc3QgdGltZVxuICAgICAgICAgICAgY29ubmVjdGlvblN1Y2NlZWRlZC5jYWxsKHRoaXMsIG1lc3NhZ2UpO1xuICAgICAgICB9IGVsc2UgaWYgKHdhc0Nvbm5lY3RlZCAmJiAhdGhpcy5pc0Nvbm5lY3RlZCkgeyAvL09ubHkgdGhyb3cgZGlzY29ubmVjdGVkIG1lc3NhZ2UgZnJvIHRoZSBmaXJzdCBkaXNjb25uZWN0LCBub3Qgb25jZSBwZXIgdHJ5XG4gICAgICAgICAgICBjb25uZWN0aW9uQnJva2VuLmNhbGwodGhpcywgbWVzc2FnZSk7XG4gICAgICAgIH1cbiAgICB9LmJpbmQodGhpcykpO1xuXG4gICAgY29tZXRkLmFkZExpc3RlbmVyKCcvbWV0YS9kaXNjb25uZWN0JywgY29ubmVjdGlvbkJyb2tlbik7XG5cbiAgICBjb21ldGQuYWRkTGlzdGVuZXIoJy9tZXRhL2hhbmRzaGFrZScsIGZ1bmN0aW9uIChtZXNzYWdlKSB7XG4gICAgICAgIGlmIChtZXNzYWdlLnN1Y2Nlc3NmdWwpIHtcbiAgICAgICAgICAgIC8vaHR0cDovL2RvY3MuY29tZXRkLm9yZy9yZWZlcmVuY2UvamF2YXNjcmlwdF9zdWJzY3JpYmUuaHRtbCNqYXZhc2NyaXB0X3N1YnNjcmliZV9tZXRhX2NoYW5uZWxzXG4gICAgICAgICAgICAvLyBeIFwiZHluYW1pYyBzdWJzY3JpcHRpb25zIGFyZSBjbGVhcmVkIChsaWtlIGFueSBvdGhlciBzdWJzY3JpcHRpb24pIGFuZCB0aGUgYXBwbGljYXRpb24gbmVlZHMgdG8gZmlndXJlIG91dCB3aGljaCBkeW5hbWljIHN1YnNjcmlwdGlvbiBtdXN0IGJlIHBlcmZvcm1lZCBhZ2FpblwiXG4gICAgICAgICAgICBjb21ldGQuYmF0Y2goZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgICAgICQobWUuY3VycmVudFN1YnNjcmlwdGlvbnMpLmVhY2goZnVuY3Rpb24gKGluZGV4LCBzdWJzKSB7XG4gICAgICAgICAgICAgICAgICAgIGNvbWV0ZC5yZXN1YnNjcmliZShzdWJzKTtcbiAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgIH0pO1xuICAgICAgICB9XG4gICAgfSk7XG5cbiAgICAvL090aGVyIGludGVyZXN0aW5nIGV2ZW50cyBmb3IgcmVmZXJlbmNlXG4gICAgY29tZXRkLmFkZExpc3RlbmVyKCcvbWV0YS9zdWJzY3JpYmUnLCBmdW5jdGlvbiAobWVzc2FnZSkge1xuICAgICAgICAkKG1lKS50cmlnZ2VyKCdzdWJzY3JpYmUnLCBtZXNzYWdlKTtcbiAgICB9KTtcbiAgICBjb21ldGQuYWRkTGlzdGVuZXIoJy9tZXRhL3Vuc3Vic2NyaWJlJywgZnVuY3Rpb24gKG1lc3NhZ2UpIHtcbiAgICAgICAgJChtZSkudHJpZ2dlcigndW5zdWJzY3JpYmUnLCBtZXNzYWdlKTtcbiAgICB9KTtcbiAgICBjb21ldGQuYWRkTGlzdGVuZXIoJy9tZXRhL3B1Ymxpc2gnLCBmdW5jdGlvbiAobWVzc2FnZSkge1xuICAgICAgICAkKG1lKS50cmlnZ2VyKCdwdWJsaXNoJywgbWVzc2FnZSk7XG4gICAgfSk7XG4gICAgY29tZXRkLmFkZExpc3RlbmVyKCcvbWV0YS91bnN1Y2Nlc3NmdWwnLCBmdW5jdGlvbiAobWVzc2FnZSkge1xuICAgICAgICAkKG1lKS50cmlnZ2VyKCdlcnJvcicsIG1lc3NhZ2UpO1xuICAgIH0pO1xuXG4gICAgY29tZXRkLmhhbmRzaGFrZShkZWZhdWx0Q29tZXRPcHRpb25zLmhhbmRzaGFrZSk7XG5cbiAgICB0aGlzLmNvbWV0ZCA9IGNvbWV0ZDtcbn07XG5cblxuQ2hhbm5lbE1hbmFnZXIucHJvdG90eXBlID0gJC5leHRlbmQoQ2hhbm5lbE1hbmFnZXIucHJvdG90eXBlLCB7XG5cbiAgICAvKipcbiAgICAgKiBDcmVhdGVzIGFuZCByZXR1cm5zIGEgY2hhbm5lbCwgdGhhdCBpcywgYW4gaW5zdGFuY2Ugb2YgYSBbQ2hhbm5lbCBTZXJ2aWNlXSguLi9jaGFubmVsLXNlcnZpY2UvKS5cbiAgICAgKlxuICAgICAqICoqRXhhbXBsZSoqXG4gICAgICpcbiAgICAgKiAgICAgIHZhciBjbSA9IG5ldyBGLm1hbmFnZXIuQ2hhbm5lbE1hbmFnZXIoKTtcbiAgICAgKiAgICAgIHZhciBjaGFubmVsID0gY20uZ2V0Q2hhbm5lbCgpO1xuICAgICAqXG4gICAgICogICAgICBjaGFubmVsLnN1YnNjcmliZSgndG9waWMnLCBjYWxsYmFjayk7XG4gICAgICogICAgICBjaGFubmVsLnB1Ymxpc2goJ3RvcGljJywgeyBteURhdGE6IDEwMCB9KTtcbiAgICAgKlxuICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICogQHBhcmFtIHtPYmplY3R8U3RyaW5nfSBgb3B0aW9uc2AgKE9wdGlvbmFsKSBJZiBzdHJpbmcsIGFzc3VtZWQgdG8gYmUgdGhlIGJhc2UgY2hhbm5lbCB1cmwuIElmIG9iamVjdCwgYXNzdW1lZCB0byBiZSBjb25maWd1cmF0aW9uIG9wdGlvbnMgZm9yIHRoZSBjb25zdHJ1Y3Rvci5cbiAgICAgKi9cbiAgICBnZXRDaGFubmVsOiBmdW5jdGlvbiAob3B0aW9ucykge1xuICAgICAgICAvL0lmIHlvdSBqdXN0IHdhbnQgdG8gcGFzcyBpbiBhIHN0cmluZ1xuICAgICAgICBpZiAob3B0aW9ucyAmJiAhJC5pc1BsYWluT2JqZWN0KG9wdGlvbnMpKSB7XG4gICAgICAgICAgICBvcHRpb25zID0ge1xuICAgICAgICAgICAgICAgIGJhc2U6IG9wdGlvbnNcbiAgICAgICAgICAgIH07XG4gICAgICAgIH1cbiAgICAgICAgdmFyIGRlZmF1bHRzID0ge1xuICAgICAgICAgICAgdHJhbnNwb3J0OiB0aGlzLmNvbWV0ZFxuICAgICAgICB9O1xuICAgICAgICB2YXIgY2hhbm5lbCA9IG5ldyBDaGFubmVsKCQuZXh0ZW5kKHRydWUsIHt9LCB0aGlzLm9wdGlvbnMuY2hhbm5lbCwgZGVmYXVsdHMsIG9wdGlvbnMpKTtcblxuXG4gICAgICAgIC8vV3JhcCBzdWJzIGFuZCB1bnN1YnMgc28gd2UgY2FuIHVzZSBpdCB0byByZS1hdHRhY2ggaGFuZGxlcnMgYWZ0ZXIgYmVpbmcgZGlzY29ubmVjdGVkXG4gICAgICAgIHZhciBzdWJzID0gY2hhbm5lbC5zdWJzY3JpYmU7XG4gICAgICAgIGNoYW5uZWwuc3Vic2NyaWJlID0gZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgdmFyIHN1YmlkID0gc3Vicy5hcHBseShjaGFubmVsLCBhcmd1bWVudHMpO1xuICAgICAgICAgICAgdGhpcy5jdXJyZW50U3Vic2NyaXB0aW9ucyAgPSB0aGlzLmN1cnJlbnRTdWJzY3JpcHRpb25zLmNvbmNhdChzdWJpZCk7XG4gICAgICAgICAgICByZXR1cm4gc3ViaWQ7XG4gICAgICAgIH0uYmluZCh0aGlzKTtcblxuXG4gICAgICAgIHZhciB1bnN1YnMgPSBjaGFubmVsLnVuc3Vic2NyaWJlO1xuICAgICAgICBjaGFubmVsLnVuc3Vic2NyaWJlID0gZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgdmFyIHJlbW92ZWQgPSB1bnN1YnMuYXBwbHkoY2hhbm5lbCwgYXJndW1lbnRzKTtcbiAgICAgICAgICAgIGZvciAodmFyIGkgPSAwOyBpIDwgdGhpcy5jdXJyZW50U3Vic2NyaXB0aW9ucy5sZW5ndGg7IGkrKykge1xuICAgICAgICAgICAgICAgIGlmICh0aGlzLmN1cnJlbnRTdWJzY3JpcHRpb25zW2ldLmlkID09PSByZW1vdmVkLmlkKSB7XG4gICAgICAgICAgICAgICAgICAgIHRoaXMuY3VycmVudFN1YnNjcmlwdGlvbnMuc3BsaWNlKGksIDEpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHJldHVybiByZW1vdmVkO1xuICAgICAgICB9LmJpbmQodGhpcyk7XG5cbiAgICAgICAgcmV0dXJuIGNoYW5uZWw7XG4gICAgfSxcblxuICAgIC8qKlxuICAgICAqIFN0YXJ0IGxpc3RlbmluZyBmb3IgZXZlbnRzIG9uIHRoaXMgaW5zdGFuY2UuIFNpZ25hdHVyZSBpcyBzYW1lIGFzIGZvciBqUXVlcnkgRXZlbnRzOiBodHRwOi8vYXBpLmpxdWVyeS5jb20vb24vLlxuICAgICAqXG4gICAgICogU3VwcG9ydGVkIGV2ZW50cyBhcmU6IGBjb25uZWN0YCwgYGRpc2Nvbm5lY3RgLCBgc3Vic2NyaWJlYCwgYHVuc3Vic2NyaWJlYCwgYHB1Ymxpc2hgLCBgZXJyb3JgLlxuICAgICAqXG4gICAgICogKipQYXJhbWV0ZXJzKipcbiAgICAgKlxuICAgICAqIEBwYXJhbSB7c3RyaW5nfSBgZXZlbnRgIFRoZSBldmVudCB0eXBlLiBTZWUgbW9yZSBkZXRhaWwgYXQgalF1ZXJ5IEV2ZW50czogaHR0cDovL2FwaS5qcXVlcnkuY29tL29uLy5cbiAgICAgKi9cbiAgICBvbjogZnVuY3Rpb24gKGV2ZW50KSB7XG4gICAgICAgICQodGhpcykub24uYXBwbHkoJCh0aGlzKSwgYXJndW1lbnRzKTtcbiAgICB9LFxuXG4gICAgLyoqXG4gICAgICogU3RvcCBsaXN0ZW5pbmcgZm9yIGV2ZW50cyBvbiB0aGlzIGluc3RhbmNlLiBTaWduYXR1cmUgaXMgc2FtZSBhcyBmb3IgalF1ZXJ5IEV2ZW50czogaHR0cDovL2FwaS5qcXVlcnkuY29tL29mZi8uXG4gICAgICpcbiAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAqXG4gICAgICogQHBhcmFtIHtzdHJpbmd9IGBldmVudGAgVGhlIGV2ZW50IHR5cGUuIFNlZSBtb3JlIGRldGFpbCBhdCBqUXVlcnkgRXZlbnRzOiBodHRwOi8vYXBpLmpxdWVyeS5jb20vb2ZmLy5cbiAgICAgKi9cbiAgICBvZmY6IGZ1bmN0aW9uIChldmVudCkge1xuICAgICAgICAkKHRoaXMpLm9mZi5hcHBseSgkKHRoaXMpLCBhcmd1bWVudHMpO1xuICAgIH0sXG5cbiAgICAvKipcbiAgICAgKiBUcmlnZ2VyIGV2ZW50cyBhbmQgZXhlY3V0ZSBoYW5kbGVycy4gU2lnbmF0dXJlIGlzIHNhbWUgYXMgZm9yIGpRdWVyeSBFdmVudHM6IGh0dHA6Ly9hcGkuanF1ZXJ5LmNvbS90cmlnZ2VyLy5cbiAgICAgKlxuICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICpcbiAgICAgKiBAcGFyYW0ge3N0cmluZ30gYGV2ZW50YCBUaGUgZXZlbnQgdHlwZS4gU2VlIG1vcmUgZGV0YWlsIGF0IGpRdWVyeSBFdmVudHM6IGh0dHA6Ly9hcGkuanF1ZXJ5LmNvbS90cmlnZ2VyLy5cbiAgICAgKi9cbiAgICB0cmlnZ2VyOiBmdW5jdGlvbiAoZXZlbnQpIHtcbiAgICAgICAgJCh0aGlzKS50cmlnZ2VyLmFwcGx5KCQodGhpcyksIGFyZ3VtZW50cyk7XG4gICAgfVxufSk7XG5cbm1vZHVsZS5leHBvcnRzID0gQ2hhbm5lbE1hbmFnZXI7XG4iLCIndXNlIHN0cmljdCc7XG5cbi8qKlxuICogIyMgRXBpY2VudGVyIENoYW5uZWwgTWFuYWdlclxuICpcbiAqIFRoZSBFcGljZW50ZXIgcGxhdGZvcm0gcHJvdmlkZXMgYSBwdXNoIGNoYW5uZWwsIHdoaWNoIGFsbG93cyB5b3UgdG8gcHVibGlzaCBhbmQgc3Vic2NyaWJlIHRvIG1lc3NhZ2VzIHdpdGhpbiBhIFtwcm9qZWN0XSguLi8uLi8uLi9nbG9zc2FyeS8jcHJvamVjdHMpLCBbZ3JvdXBdKC4uLy4uLy4uL2dsb3NzYXJ5LyNncm91cHMpLCBvciBbbXVsdGlwbGF5ZXIgd29ybGRdKC4uLy4uLy4uL2dsb3NzYXJ5LyN3b3JsZCkuIFRoZXJlIGFyZSB0d28gbWFpbiB1c2UgY2FzZXMgZm9yIHRoZSBjaGFubmVsOiBldmVudCBub3RpZmljYXRpb25zIGFuZCBjaGF0IG1lc3NhZ2VzLlxuICpcbiAqIFRoZSBFcGljZW50ZXIgQ2hhbm5lbCBNYW5hZ2VyIGlzIGEgd3JhcHBlciBhcm91bmQgdGhlIChtb3JlIGdlbmVyaWMpIFtDaGFubmVsIE1hbmFnZXJdKC4uL2NoYW5uZWwtbWFuYWdlci8pLCB0byBpbnN0YW50aWF0ZSBpdCB3aXRoIEVwaWNlbnRlci1zcGVjaWZpYyBkZWZhdWx0cy4gSWYgeW91IGFyZSBpbnRlcmVzdGVkIGluIGluY2x1ZGluZyBhIG5vdGlmaWNhdGlvbiBvciBjaGF0IGZlYXR1cmUgaW4geW91ciBwcm9qZWN0LCB1c2luZyBhbiBFcGljZW50ZXIgQ2hhbm5lbCBNYW5hZ2VyIGlzIHByb2JhYmx5IHRoZSBlYXNpZXN0IHdheSB0byBnZXQgc3RhcnRlZC5cbiAqXG4gKiBZb3UnbGwgbmVlZCB0byBpbmNsdWRlIHRoZSBgZXBpY2VudGVyLW11bHRpcGxheWVyLWRlcGVuZGVuY2llcy5qc2AgbGlicmFyeSBpbiBhZGRpdGlvbiB0byB0aGUgYGVwaWNlbnRlci5qc2AgbGlicmFyeSBpbiB5b3VyIHByb2plY3QgdG8gdXNlIHRoZSBFcGljZW50ZXIgQ2hhbm5lbCBNYW5hZ2VyLiBTZWUgW0luY2x1ZGluZyBFcGljZW50ZXIuanNdKC4uLy4uLyNpbmNsdWRlKS5cbiAqXG4gKiBUbyB1c2UgdGhlIEVwaWNlbnRlciBDaGFubmVsIE1hbmFnZXI6IGluc3RhbnRpYXRlIGl0LCBnZXQgdGhlIGNoYW5uZWwgb2YgdGhlIHNjb3BlIHlvdSB3YW50IChbdXNlcl0oLi4vLi4vLi4vZ2xvc3NhcnkvI3VzZXJzKSwgW3dvcmxkXSguLi8uLi8uLi9nbG9zc2FyeS8jd29ybGQpLCBvciBbZ3JvdXBdKC4uLy4uLy4uL2dsb3NzYXJ5LyNncm91cHMpKSwgdGhlbiB1c2UgdGhlIGNoYW5uZWwncyBgc3Vic2NyaWJlKClgIGFuZCBgcHVibGlzaCgpYCBtZXRob2RzIHRvIHN1YnNjcmliZSB0byB0b3BpY3Mgb3IgcHVibGlzaCBkYXRhIHRvIHRvcGljcy5cbiAqXG4gKiAgICAgdmFyIGNtID0gbmV3IEYubWFuYWdlci5DaGFubmVsTWFuYWdlcigpO1xuICogICAgIHZhciBnYyA9IGNtLmdldEdyb3VwQ2hhbm5lbCgpO1xuICogICAgIGdjLnN1YnNjcmliZSgnYnJvYWRjYXN0cycsIGNhbGxiYWNrKTtcbiAqXG4gKiBGb3IgYWRkaXRpb25hbCBiYWNrZ3JvdW5kIG9uIEVwaWNlbnRlcidzIHB1c2ggY2hhbm5lbCwgc2VlIHRoZSBpbnRyb2R1Y3Rvcnkgbm90ZXMgb24gdGhlIFtQdXNoIENoYW5uZWwgQVBJXSguLi8uLi8uLi9yZXN0X2FwaXMvbXVsdGlwbGF5ZXIvY2hhbm5lbC8pIHBhZ2UuXG4gKlxuICogVGhlIHBhcmFtZXRlcnMgZm9yIGluc3RhbnRpYXRpbmcgYW4gRXBpY2VudGVyIENoYW5uZWwgTWFuYWdlciBpbmNsdWRlOlxuICpcbiAqICogYG9wdGlvbnNgIE9iamVjdCB3aXRoIGRldGFpbHMgYWJvdXQgdGhlIEVwaWNlbnRlciBwcm9qZWN0IGZvciB0aGlzIEVwaWNlbnRlciBDaGFubmVsIE1hbmFnZXIgaW5zdGFuY2UuXG4gKiAqIGBvcHRpb25zLmFjY291bnRgIFRoZSBFcGljZW50ZXIgYWNjb3VudCBpZCAoKipUZWFtIElEKiogZm9yIHRlYW0gcHJvamVjdHMsICoqVXNlciBJRCoqIGZvciBwZXJzb25hbCBwcm9qZWN0cykuXG4gKiAqIGBvcHRpb25zLnByb2plY3RgIEVwaWNlbnRlciBwcm9qZWN0IGlkLlxuICogKiBgb3B0aW9ucy51c2VyTmFtZWAgRXBpY2VudGVyIHVzZXJOYW1lIHVzZWQgZm9yIGF1dGhlbnRpY2F0aW9uLlxuICogKiBgb3B0aW9ucy51c2VySWRgIEVwaWNlbnRlciB1c2VyIGlkIHVzZWQgZm9yIGF1dGhlbnRpY2F0aW9uLiBPcHRpb25hbDsgYG9wdGlvbnMudXNlck5hbWVgIGlzIHByZWZlcnJlZC5cbiAqICogYG9wdGlvbnMudG9rZW5gIEVwaWNlbnRlciB0b2tlbiB1c2VkIGZvciBhdXRoZW50aWNhdGlvbi4gKFlvdSBjYW4gcmV0cmlldmUgdGhpcyB1c2luZyBgYXV0aE1hbmFnZXIuZ2V0VG9rZW4oKWAgZnJvbSB0aGUgW0F1dGhvcml6YXRpb24gTWFuYWdlcl0oLi4vYXV0aC1tYW5hZ2VyLykuKVxuICogKiBgb3B0aW9ucy5hbGxvd0FsbENoYW5uZWxzYCBJZiBub3QgaW5jbHVkZWQgb3IgaWYgc2V0IHRvIGBmYWxzZWAsIGFsbCBjaGFubmVsIHBhdGhzIGFyZSB2YWxpZGF0ZWQ7IGlmIHlvdXIgcHJvamVjdCByZXF1aXJlcyBbUHVzaCBDaGFubmVsIEF1dGhvcml6YXRpb25dKC4uLy4uLy4uL3VwZGF0aW5nX3lvdXJfc2V0dGluZ3MvKSwgeW91IHNob3VsZCB1c2UgdGhpcyBvcHRpb24uIElmIHlvdSB3YW50IHRvIGFsbG93IG90aGVyIGNoYW5uZWwgcGF0aHMsIHNldCB0byBgdHJ1ZWA7IHRoaXMgaXMgbm90IGNvbW1vbi5cbiAqL1xuXG52YXIgQ2hhbm5lbE1hbmFnZXIgPSByZXF1aXJlKCcuL2NoYW5uZWwtbWFuYWdlcicpO1xudmFyIGNsYXNzRnJvbSA9IHJlcXVpcmUoJy4uL3V0aWwvaW5oZXJpdCcpO1xudmFyIHVybFNlcnZpY2UgPSByZXF1aXJlKCcuLi9zZXJ2aWNlL3VybC1jb25maWctc2VydmljZScpO1xudmFyIFNlc3Npb25NYW5hZ2VyID0gcmVxdWlyZSgnLi4vc3RvcmUvc2Vzc2lvbi1tYW5hZ2VyJyk7XG5cbnZhciBBdXRoTWFuYWdlciA9IHJlcXVpcmUoJy4vYXV0aC1tYW5hZ2VyJyk7XG5cbnZhciB2YWxpZFR5cGVzID0ge1xuICAgIHByb2plY3Q6IHRydWUsXG4gICAgZ3JvdXA6IHRydWUsXG4gICAgd29ybGQ6IHRydWUsXG4gICAgdXNlcjogdHJ1ZSxcbiAgICBkYXRhOiB0cnVlLFxuICAgIGdlbmVyYWw6IHRydWUsXG4gICAgY2hhdDogdHJ1ZVxufTtcbnZhciBzZXNzaW9uID0gbmV3IEF1dGhNYW5hZ2VyKCk7XG52YXIgZ2V0RnJvbVNldHRpbmdzT3JTZXNzaW9uT3JFcnJvciA9IGZ1bmN0aW9uICh2YWx1ZSwgc2Vzc2lvbktleU5hbWUsIHNldHRpbmdzKSB7XG4gICAgaWYgKCF2YWx1ZSkge1xuICAgICAgICB2YXIgdXNlckluZm8gPSBzZXNzaW9uLmdldEN1cnJlbnRVc2VyU2Vzc2lvbkluZm8oKTtcbiAgICAgICAgaWYgKHNldHRpbmdzICYmIHNldHRpbmdzW3Nlc3Npb25LZXlOYW1lXSkge1xuICAgICAgICAgICAgdmFsdWUgPSBzZXR0aW5nc1tzZXNzaW9uS2V5TmFtZV07XG4gICAgICAgIH0gZWxzZSBpZiAodXNlckluZm9bc2Vzc2lvbktleU5hbWVdKSB7XG4gICAgICAgICAgICB2YWx1ZSA9IHVzZXJJbmZvW3Nlc3Npb25LZXlOYW1lXTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihzZXNzaW9uS2V5TmFtZSArICcgbm90IGZvdW5kLiBQbGVhc2UgbG9nLWluIGFnYWluLCBvciBzcGVjaWZ5ICcgKyBzZXNzaW9uS2V5TmFtZSArICcgZXhwbGljaXRseScpO1xuICAgICAgICB9XG4gICAgfVxuICAgIHJldHVybiB2YWx1ZTtcbn07XG52YXIgX19zdXBlciA9IENoYW5uZWxNYW5hZ2VyLnByb3RvdHlwZTtcbnZhciBFcGljZW50ZXJDaGFubmVsTWFuYWdlciA9IGNsYXNzRnJvbShDaGFubmVsTWFuYWdlciwge1xuICAgIGNvbnN0cnVjdG9yOiBmdW5jdGlvbiAob3B0aW9ucykge1xuICAgICAgICB0aGlzLnNlc3Npb25NYW5hZ2VyID0gbmV3IFNlc3Npb25NYW5hZ2VyKCk7XG4gICAgICAgIHZhciBkZWZhdWx0Q29tZXRPcHRpb25zID0gdGhpcy5zZXNzaW9uTWFuYWdlci5nZXRNZXJnZWRPcHRpb25zKG9wdGlvbnMpO1xuXG4gICAgICAgIHZhciB1cmxPcHRzID0gdXJsU2VydmljZShkZWZhdWx0Q29tZXRPcHRpb25zLnNlcnZlcik7XG4gICAgICAgIGlmICghZGVmYXVsdENvbWV0T3B0aW9ucy51cmwpIHtcbiAgICAgICAgICAgIC8vRGVmYXVsdCBlcGljZW50ZXIgY29tZXRkIGVuZHBvaW50XG4gICAgICAgICAgICBkZWZhdWx0Q29tZXRPcHRpb25zLnVybCA9IHVybE9wdHMucHJvdG9jb2wgKyAnOi8vJyArIHVybE9wdHMuaG9zdCArICcvY2hhbm5lbC9zdWJzY3JpYmUnO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKGRlZmF1bHRDb21ldE9wdGlvbnMuaGFuZHNoYWtlID09PSB1bmRlZmluZWQpIHtcbiAgICAgICAgICAgIHZhciB1c2VyTmFtZSA9IGRlZmF1bHRDb21ldE9wdGlvbnMudXNlck5hbWU7XG4gICAgICAgICAgICB2YXIgdXNlcklkID0gZGVmYXVsdENvbWV0T3B0aW9ucy51c2VySWQ7XG4gICAgICAgICAgICB2YXIgdG9rZW4gPSBkZWZhdWx0Q29tZXRPcHRpb25zLnRva2VuO1xuICAgICAgICAgICAgaWYgKCh1c2VyTmFtZSB8fCB1c2VySWQpICYmIHRva2VuKSB7XG4gICAgICAgICAgICAgICAgdmFyIHVzZXJQcm9wID0gdXNlck5hbWUgPyAndXNlck5hbWUnIDogJ3VzZXJJZCc7XG4gICAgICAgICAgICAgICAgdmFyIGV4dCA9IHtcbiAgICAgICAgICAgICAgICAgICAgYXV0aG9yaXphdGlvbjogJ0JlYXJlciAnICsgdG9rZW5cbiAgICAgICAgICAgICAgICB9O1xuICAgICAgICAgICAgICAgIGV4dFt1c2VyUHJvcF0gPSB1c2VyTmFtZSA/IHVzZXJOYW1lIDogdXNlcklkO1xuXG4gICAgICAgICAgICAgICAgZGVmYXVsdENvbWV0T3B0aW9ucy5oYW5kc2hha2UgPSB7XG4gICAgICAgICAgICAgICAgICAgIGV4dDogZXh0XG4gICAgICAgICAgICAgICAgfTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuXG4gICAgICAgIHRoaXMub3B0aW9ucyA9IGRlZmF1bHRDb21ldE9wdGlvbnM7XG4gICAgICAgIHJldHVybiBfX3N1cGVyLmNvbnN0cnVjdG9yLmNhbGwodGhpcywgZGVmYXVsdENvbWV0T3B0aW9ucyk7XG4gICAgfSxcblxuICAgIC8qKlxuICAgICAqIENyZWF0ZXMgYW5kIHJldHVybnMgYSBjaGFubmVsLCB0aGF0IGlzLCBhbiBpbnN0YW5jZSBvZiBhIFtDaGFubmVsIFNlcnZpY2VdKC4uL2NoYW5uZWwtc2VydmljZS8pLlxuICAgICAqXG4gICAgICogVGhpcyBtZXRob2QgZW5mb3JjZXMgRXBpY2VudGVyLXNwZWNpZmljIGNoYW5uZWwgbmFtaW5nOiBhbGwgY2hhbm5lbHMgcmVxdWVzdGVkIG11c3QgYmUgaW4gdGhlIGZvcm0gYC97dHlwZX0ve2FjY291bnQgaWR9L3twcm9qZWN0IGlkfS97Li4ufWAsIHdoZXJlIGB0eXBlYCBpcyBvbmUgb2YgYHJ1bmAsIGBkYXRhYCwgYHVzZXJgLCBgd29ybGRgLCBvciBgY2hhdGAuXG4gICAgICpcbiAgICAgKiAqKkV4YW1wbGUqKlxuICAgICAqXG4gICAgICogICAgICB2YXIgY20gPSBuZXcgRi5tYW5hZ2VyLkVwaWNlbnRlckNoYW5uZWxNYW5hZ2VyKCk7XG4gICAgICogICAgICB2YXIgY2hhbm5lbCA9IGNtLmdldENoYW5uZWwoJy9ncm91cC9hY21lL3N1cHBseS1jaGFpbi1nYW1lLycpO1xuICAgICAqXG4gICAgICogICAgICBjaGFubmVsLnN1YnNjcmliZSgndG9waWMnLCBjYWxsYmFjayk7XG4gICAgICogICAgICBjaGFubmVsLnB1Ymxpc2goJ3RvcGljJywgeyBteURhdGE6IDEwMCB9KTtcbiAgICAgKlxuICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICogQHBhcmFtIHtPYmplY3R8U3RyaW5nfSBgb3B0aW9uc2AgKE9wdGlvbmFsKSBJZiBzdHJpbmcsIGFzc3VtZWQgdG8gYmUgdGhlIGJhc2UgY2hhbm5lbCB1cmwuIElmIG9iamVjdCwgYXNzdW1lZCB0byBiZSBjb25maWd1cmF0aW9uIG9wdGlvbnMgZm9yIHRoZSBjb25zdHJ1Y3Rvci5cbiAgICAgKi9cbiAgICBnZXRDaGFubmVsOiBmdW5jdGlvbiAob3B0aW9ucykge1xuICAgICAgICBpZiAob3B0aW9ucyAmJiB0eXBlb2Ygb3B0aW9ucyAhPT0gJ29iamVjdCcpIHtcbiAgICAgICAgICAgIG9wdGlvbnMgPSB7XG4gICAgICAgICAgICAgICAgYmFzZTogb3B0aW9uc1xuICAgICAgICAgICAgfTtcbiAgICAgICAgfVxuICAgICAgICB2YXIgY2hhbm5lbE9wdHMgPSAkLmV4dGVuZCh7fSwgdGhpcy5vcHRpb25zLCBvcHRpb25zKTtcbiAgICAgICAgdmFyIGJhc2UgPSBjaGFubmVsT3B0cy5iYXNlO1xuICAgICAgICBpZiAoIWJhc2UpIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcignTm8gYmFzZSB0b3BpYyB3YXMgcHJvdmlkZWQnKTtcbiAgICAgICAgfVxuXG4gICAgICAgIGlmICghY2hhbm5lbE9wdHMuYWxsb3dBbGxDaGFubmVscykge1xuICAgICAgICAgICAgdmFyIGJhc2VQYXJ0cyA9IGJhc2Uuc3BsaXQoJy8nKTtcbiAgICAgICAgICAgIHZhciBjaGFubmVsVHlwZSA9IGJhc2VQYXJ0c1sxXTtcbiAgICAgICAgICAgIGlmIChiYXNlUGFydHMubGVuZ3RoIDwgNCkge1xuICAgICAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcignSW52YWxpZCBjaGFubmVsIGJhc2UgbmFtZSwgaXQgbXVzdCBiZSBpbiB0aGUgZm9ybSAve3R5cGV9L3thY2NvdW50IGlkfS97cHJvamVjdCBpZH0vey4uLn0nKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGlmICghdmFsaWRUeXBlc1tjaGFubmVsVHlwZV0pIHtcbiAgICAgICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ0ludmFsaWQgY2hhbm5lbCB0eXBlJyk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIF9fc3VwZXIuZ2V0Q2hhbm5lbC5hcHBseSh0aGlzLCBhcmd1bWVudHMpO1xuICAgIH0sXG5cbiAgICAvKipcbiAgICAgKiBDcmVhdGUgYW5kIHJldHVybiBhIHB1Ymxpc2gvc3Vic2NyaWJlIGNoYW5uZWwgKGZyb20gdGhlIHVuZGVybHlpbmcgW0NoYW5uZWwgTWFuYWdlcl0oLi4vY2hhbm5lbC1tYW5hZ2VyLykpIGZvciB0aGUgZ2l2ZW4gW2dyb3VwXSguLi8uLi8uLi9nbG9zc2FyeS8jZ3JvdXBzKS4gVGhlIGdyb3VwIG11c3QgZXhpc3QgaW4gdGhlIGFjY291bnQgKHRlYW0pIGFuZCBwcm9qZWN0IHByb3ZpZGVkLlxuICAgICAqXG4gICAgICogVGhlcmUgYXJlIG5vIG5vdGlmaWNhdGlvbnMgZnJvbSBFcGljZW50ZXIgb24gdGhpcyBjaGFubmVsOyBhbGwgbWVzc2FnZXMgYXJlIHVzZXItb3JpZ2luYXRlZC5cbiAgICAgKlxuICAgICAqICoqRXhhbXBsZSoqXG4gICAgICpcbiAgICAgKiAgICAgdmFyIGNtID0gbmV3IEYubWFuYWdlci5DaGFubmVsTWFuYWdlcigpO1xuICAgICAqICAgICB2YXIgZ2MgPSBjbS5nZXRHcm91cENoYW5uZWwoKTtcbiAgICAgKiAgICAgZ2Muc3Vic2NyaWJlKCdicm9hZGNhc3RzJywgY2FsbGJhY2spO1xuICAgICAqXG4gICAgICogKipSZXR1cm4gVmFsdWUqKlxuICAgICAqXG4gICAgICogKiAqQ2hhbm5lbCogUmV0dXJucyB0aGUgY2hhbm5lbCAoYW4gaW5zdGFuY2Ugb2YgdGhlIFtDaGFubmVsIFNlcnZpY2VdKC4uL2NoYW5uZWwtc2VydmljZS8pKS5cbiAgICAgKlxuICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICpcbiAgICAgKiBAcGFyYW0gIHtTdHJpbmd9IGBncm91cE5hbWVgIChPcHRpb25hbCkgR3JvdXAgdG8gYnJvYWRjYXN0IHRvLiBJZiBub3QgcHJvdmlkZWQsIHBpY2tzIHVwIGdyb3VwIGZyb20gY3VycmVudCBzZXNzaW9uIGlmIGVuZCB1c2VyIGlzIGxvZ2dlZCBpbi5cbiAgICAgKi9cbiAgICBnZXRHcm91cENoYW5uZWw6IGZ1bmN0aW9uIChncm91cE5hbWUpIHtcbiAgICAgICAgZ3JvdXBOYW1lID0gZ2V0RnJvbVNldHRpbmdzT3JTZXNzaW9uT3JFcnJvcihncm91cE5hbWUsICdncm91cE5hbWUnLCB0aGlzLm9wdGlvbnMpO1xuICAgICAgICB2YXIgYWNjb3VudCA9IGdldEZyb21TZXR0aW5nc09yU2Vzc2lvbk9yRXJyb3IoJycsICdhY2NvdW50JywgdGhpcy5vcHRpb25zKTtcbiAgICAgICAgdmFyIHByb2plY3QgPSBnZXRGcm9tU2V0dGluZ3NPclNlc3Npb25PckVycm9yKCcnLCAncHJvamVjdCcsIHRoaXMub3B0aW9ucyk7XG5cbiAgICAgICAgdmFyIGJhc2VUb3BpYyA9IFsnL2dyb3VwJywgYWNjb3VudCwgcHJvamVjdCwgZ3JvdXBOYW1lXS5qb2luKCcvJyk7XG4gICAgICAgIHJldHVybiBfX3N1cGVyLmdldENoYW5uZWwuY2FsbCh0aGlzLCB7IGJhc2U6IGJhc2VUb3BpYyB9KTtcbiAgICB9LFxuXG4gICAgLyoqXG4gICAgICogQ3JlYXRlIGFuZCByZXR1cm4gYSBwdWJsaXNoL3N1YnNjcmliZSBjaGFubmVsIChmcm9tIHRoZSB1bmRlcmx5aW5nIFtDaGFubmVsIE1hbmFnZXJdKC4uL2NoYW5uZWwtbWFuYWdlci8pKSBmb3IgdGhlIGdpdmVuIFt3b3JsZF0oLi4vLi4vLi4vZ2xvc3NhcnkvI3dvcmxkKS5cbiAgICAgKlxuICAgICAqIFRoaXMgaXMgdHlwaWNhbGx5IHVzZWQgdG9nZXRoZXIgd2l0aCB0aGUgW1dvcmxkIE1hbmFnZXJdKC4uL3dvcmxkLW1hbmFnZXIpLlxuICAgICAqXG4gICAgICogKipFeGFtcGxlKipcbiAgICAgKlxuICAgICAqICAgICB2YXIgY20gPSBuZXcgRi5tYW5hZ2VyLkNoYW5uZWxNYW5hZ2VyKCk7XG4gICAgICogICAgIHZhciB3b3JsZE1hbmFnZXIgPSBuZXcgRi5tYW5hZ2VyLldvcmxkTWFuYWdlcih7XG4gICAgICogICAgICAgICBhY2NvdW50OiAnYWNtZS1zaW11bGF0aW9ucycsXG4gICAgICogICAgICAgICBwcm9qZWN0OiAnc3VwcGx5LWNoYWluLWdhbWUnLFxuICAgICAqICAgICAgICAgZ3JvdXA6ICd0ZWFtMScsXG4gICAgICogICAgICAgICBydW46IHsgbW9kZWw6ICdtb2RlbC5lcW4nIH1cbiAgICAgKiAgICAgfSk7XG4gICAgICogICAgIHdvcmxkTWFuYWdlci5nZXRDdXJyZW50V29ybGQoKS50aGVuKGZ1bmN0aW9uICh3b3JsZE9iamVjdCwgd29ybGRBZGFwdGVyKSB7XG4gICAgICogICAgICAgICB2YXIgd29ybGRDaGFubmVsID0gY20uZ2V0V29ybGRDaGFubmVsKHdvcmxkT2JqZWN0KTtcbiAgICAgKiAgICAgICAgIHdvcmxkQ2hhbm5lbC5zdWJzY3JpYmUoJycsIGZ1bmN0aW9uIChkYXRhKSB7XG4gICAgICogICAgICAgICAgICAgY29uc29sZS5sb2coZGF0YSk7XG4gICAgICogICAgICAgICB9KTtcbiAgICAgKiAgICAgIH0pO1xuICAgICAqXG4gICAgICogKipSZXR1cm4gVmFsdWUqKlxuICAgICAqXG4gICAgICogKiAqQ2hhbm5lbCogUmV0dXJucyB0aGUgY2hhbm5lbCAoYW4gaW5zdGFuY2Ugb2YgdGhlIFtDaGFubmVsIFNlcnZpY2VdKC4uL2NoYW5uZWwtc2VydmljZS8pKS5cbiAgICAgKlxuICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICpcbiAgICAgKiBAcGFyYW0gIHtTdHJpbmd8T2JqZWN0fSBgd29ybGRgIFRoZSB3b3JsZCBvYmplY3Qgb3IgaWQuXG4gICAgICogQHBhcmFtICB7U3RyaW5nfSBgZ3JvdXBOYW1lYCAoT3B0aW9uYWwpIEdyb3VwIHRoZSB3b3JsZCBleGlzdHMgaW4uIElmIG5vdCBwcm92aWRlZCwgcGlja3MgdXAgZ3JvdXAgZnJvbSBjdXJyZW50IHNlc3Npb24gaWYgZW5kIHVzZXIgaXMgbG9nZ2VkIGluLlxuICAgICAqL1xuICAgIGdldFdvcmxkQ2hhbm5lbDogZnVuY3Rpb24gKHdvcmxkLCBncm91cE5hbWUpIHtcbiAgICAgICAgdmFyIHdvcmxkaWQgPSAoJC5pc1BsYWluT2JqZWN0KHdvcmxkKSAmJiB3b3JsZC5pZCkgPyB3b3JsZC5pZCA6IHdvcmxkO1xuICAgICAgICBpZiAoIXdvcmxkaWQpIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcignUGxlYXNlIHNwZWNpZnkgYSB3b3JsZCBpZCcpO1xuICAgICAgICB9XG4gICAgICAgIGdyb3VwTmFtZSA9IGdldEZyb21TZXR0aW5nc09yU2Vzc2lvbk9yRXJyb3IoZ3JvdXBOYW1lLCAnZ3JvdXBOYW1lJywgdGhpcy5vcHRpb25zKTtcbiAgICAgICAgdmFyIGFjY291bnQgPSBnZXRGcm9tU2V0dGluZ3NPclNlc3Npb25PckVycm9yKCcnLCAnYWNjb3VudCcsIHRoaXMub3B0aW9ucyk7XG4gICAgICAgIHZhciBwcm9qZWN0ID0gZ2V0RnJvbVNldHRpbmdzT3JTZXNzaW9uT3JFcnJvcignJywgJ3Byb2plY3QnLCB0aGlzLm9wdGlvbnMpO1xuXG4gICAgICAgIHZhciBiYXNlVG9waWMgPSBbJy93b3JsZCcsIGFjY291bnQsIHByb2plY3QsIGdyb3VwTmFtZSwgd29ybGRpZF0uam9pbignLycpO1xuICAgICAgICByZXR1cm4gX19zdXBlci5nZXRDaGFubmVsLmNhbGwodGhpcywgeyBiYXNlOiBiYXNlVG9waWMgfSk7XG4gICAgfSxcblxuICAgIC8qKlxuICAgICAqIENyZWF0ZSBhbmQgcmV0dXJuIGEgcHVibGlzaC9zdWJzY3JpYmUgY2hhbm5lbCAoZnJvbSB0aGUgdW5kZXJseWluZyBbQ2hhbm5lbCBNYW5hZ2VyXSguLi9jaGFubmVsLW1hbmFnZXIvKSkgZm9yIHRoZSBjdXJyZW50IFtlbmQgdXNlcl0oLi4vLi4vLi4vZ2xvc3NhcnkvI3VzZXJzKSBpbiB0aGF0IHVzZXIncyBjdXJyZW50IFt3b3JsZF0oLi4vLi4vLi4vZ2xvc3NhcnkvI3dvcmxkKS5cbiAgICAgKlxuICAgICAqIFRoaXMgaXMgdHlwaWNhbGx5IHVzZWQgdG9nZXRoZXIgd2l0aCB0aGUgW1dvcmxkIE1hbmFnZXJdKC4uL3dvcmxkLW1hbmFnZXIpLiBOb3RlIHRoYXQgdGhpcyBjaGFubmVsIG9ubHkgZ2V0cyBub3RpZmljYXRpb25zIGZvciB3b3JsZHMgY3VycmVudGx5IGluIG1lbW9yeS4gKFNlZSBtb3JlIGJhY2tncm91bmQgb24gW3BlcnNpc3RlbmNlXSguLi8uLi8uLi9ydW5fcGVyc2lzdGVuY2UpLilcbiAgICAgKlxuICAgICAqICoqRXhhbXBsZSoqXG4gICAgICpcbiAgICAgKiAgICAgdmFyIGNtID0gbmV3IEYubWFuYWdlci5DaGFubmVsTWFuYWdlcigpO1xuICAgICAqICAgICB2YXIgd29ybGRNYW5hZ2VyID0gbmV3IEYubWFuYWdlci5Xb3JsZE1hbmFnZXIoe1xuICAgICAqICAgICAgICAgYWNjb3VudDogJ2FjbWUtc2ltdWxhdGlvbnMnLFxuICAgICAqICAgICAgICAgcHJvamVjdDogJ3N1cHBseS1jaGFpbi1nYW1lJyxcbiAgICAgKiAgICAgICAgIGdyb3VwOiAndGVhbTEnLFxuICAgICAqICAgICAgICAgcnVuOiB7IG1vZGVsOiAnbW9kZWwuZXFuJyB9XG4gICAgICogICAgIH0pO1xuICAgICAqICAgICB3b3JsZE1hbmFnZXIuZ2V0Q3VycmVudFdvcmxkKCkudGhlbihmdW5jdGlvbiAod29ybGRPYmplY3QsIHdvcmxkQWRhcHRlcikge1xuICAgICAqICAgICAgICAgdmFyIHVzZXJDaGFubmVsID0gY20uZ2V0VXNlckNoYW5uZWwod29ybGRPYmplY3QpO1xuICAgICAqICAgICAgICAgdXNlckNoYW5uZWwuc3Vic2NyaWJlKCcnLCBmdW5jdGlvbiAoZGF0YSkge1xuICAgICAqICAgICAgICAgICAgIGNvbnNvbGUubG9nKGRhdGEpO1xuICAgICAqICAgICAgICAgfSk7XG4gICAgICogICAgICB9KTtcbiAgICAgKlxuICAgICAqXG4gICAgICogKipSZXR1cm4gVmFsdWUqKlxuICAgICAqXG4gICAgICogKiAqQ2hhbm5lbCogUmV0dXJucyB0aGUgY2hhbm5lbCAoYW4gaW5zdGFuY2Ugb2YgdGhlIFtDaGFubmVsIFNlcnZpY2VdKC4uL2NoYW5uZWwtc2VydmljZS8pKS5cbiAgICAgKlxuICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICpcbiAgICAgKiBAcGFyYW0gIHtTdHJpbmd8T2JqZWN0fSBgd29ybGRgIFdvcmxkIG9iamVjdCBvciBpZC5cbiAgICAgKiBAcGFyYW0gIHtTdHJpbmd8T2JqZWN0fSBgdXNlcmAgKE9wdGlvbmFsKSBVc2VyIG9iamVjdCBvciBpZC4gSWYgbm90IHByb3ZpZGVkLCBwaWNrcyB1cCB1c2VyIGlkIGZyb20gY3VycmVudCBzZXNzaW9uIGlmIGVuZCB1c2VyIGlzIGxvZ2dlZCBpbi5cbiAgICAgKiBAcGFyYW0gIHtTdHJpbmd9IGBncm91cE5hbWVgIChPcHRpb25hbCkgR3JvdXAgdGhlIHdvcmxkIGV4aXN0cyBpbi4gSWYgbm90IHByb3ZpZGVkLCBwaWNrcyB1cCBncm91cCBmcm9tIGN1cnJlbnQgc2Vzc2lvbiBpZiBlbmQgdXNlciBpcyBsb2dnZWQgaW4uXG4gICAgICovXG4gICAgZ2V0VXNlckNoYW5uZWw6IGZ1bmN0aW9uICh3b3JsZCwgdXNlciwgZ3JvdXBOYW1lKSB7XG4gICAgICAgIHZhciB3b3JsZGlkID0gKCQuaXNQbGFpbk9iamVjdCh3b3JsZCkgJiYgd29ybGQuaWQpID8gd29ybGQuaWQgOiB3b3JsZDtcbiAgICAgICAgaWYgKCF3b3JsZGlkKSB7XG4gICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ1BsZWFzZSBzcGVjaWZ5IGEgd29ybGQgaWQnKTtcbiAgICAgICAgfVxuICAgICAgICB2YXIgdXNlcmlkID0gKCQuaXNQbGFpbk9iamVjdCh1c2VyKSAmJiB1c2VyLmlkKSA/IHVzZXIuaWQgOiB1c2VyO1xuICAgICAgICB1c2VyaWQgPSBnZXRGcm9tU2V0dGluZ3NPclNlc3Npb25PckVycm9yKHVzZXJpZCwgJ3VzZXJJZCcsIHRoaXMub3B0aW9ucyk7XG4gICAgICAgIGdyb3VwTmFtZSA9IGdldEZyb21TZXR0aW5nc09yU2Vzc2lvbk9yRXJyb3IoZ3JvdXBOYW1lLCAnZ3JvdXBOYW1lJywgdGhpcy5vcHRpb25zKTtcblxuICAgICAgICB2YXIgYWNjb3VudCA9IGdldEZyb21TZXR0aW5nc09yU2Vzc2lvbk9yRXJyb3IoJycsICdhY2NvdW50JywgdGhpcy5vcHRpb25zKTtcbiAgICAgICAgdmFyIHByb2plY3QgPSBnZXRGcm9tU2V0dGluZ3NPclNlc3Npb25PckVycm9yKCcnLCAncHJvamVjdCcsIHRoaXMub3B0aW9ucyk7XG5cbiAgICAgICAgdmFyIGJhc2VUb3BpYyA9IFsnL3VzZXInLCBhY2NvdW50LCBwcm9qZWN0LCBncm91cE5hbWUsIHdvcmxkaWQsIHVzZXJpZF0uam9pbignLycpO1xuICAgICAgICByZXR1cm4gX19zdXBlci5nZXRDaGFubmVsLmNhbGwodGhpcywgeyBiYXNlOiBiYXNlVG9waWMgfSk7XG4gICAgfSxcblxuICAgIC8qKlxuICAgICAqIENyZWF0ZSBhbmQgcmV0dXJuIGEgcHVibGlzaC9zdWJzY3JpYmUgY2hhbm5lbCAoZnJvbSB0aGUgdW5kZXJseWluZyBbQ2hhbm5lbCBNYW5hZ2VyXSguLi9jaGFubmVsLW1hbmFnZXIvKSkgdGhhdCBhdXRvbWF0aWNhbGx5IHRyYWNrcyB0aGUgcHJlc2VuY2Ugb2YgYW4gW2VuZCB1c2VyXSguLi8uLi8uLi9nbG9zc2FyeS8jdXNlcnMpLCB0aGF0IGlzLCB3aGV0aGVyIHRoZSBlbmQgdXNlciBpcyBjdXJyZW50bHkgb25saW5lIGluIHRoaXMgZ3JvdXAgYW5kIHdvcmxkLiBOb3RpZmljYXRpb25zIGFyZSBhdXRvbWF0aWNhbGx5IHNlbnQgd2hlbiB0aGUgZW5kIHVzZXIgY29tZXMgb25saW5lLCBhbmQgd2hlbiB0aGUgZW5kIHVzZXIgZ29lcyBvZmZsaW5lIChub3QgcHJlc2VudCBmb3IgbW9yZSB0aGFuIDIgbWludXRlcykuIFVzZWZ1bCBpbiBtdWx0aXBsYXllciBnYW1lcyBmb3IgbGV0dGluZyBlYWNoIGVuZCB1c2VyIGtub3cgd2hldGhlciBvdGhlciB1c2VycyBpbiB0aGVpciBzaGFyZWQgd29ybGQgYXJlIGFsc28gb25saW5lLlxuICAgICAqXG4gICAgICogKipFeGFtcGxlKipcbiAgICAgKlxuICAgICAqICAgICB2YXIgY20gPSBuZXcgRi5tYW5hZ2VyLkNoYW5uZWxNYW5hZ2VyKCk7XG4gICAgICogICAgIHZhciB3b3JsZE1hbmFnZXIgPSBuZXcgRi5tYW5hZ2VyLldvcmxkTWFuYWdlcih7XG4gICAgICogICAgICAgICBhY2NvdW50OiAnYWNtZS1zaW11bGF0aW9ucycsXG4gICAgICogICAgICAgICBwcm9qZWN0OiAnc3VwcGx5LWNoYWluLWdhbWUnLFxuICAgICAqICAgICAgICAgbW9kZWw6ICdtb2RlbC5lcW4nXG4gICAgICogICAgIH0pO1xuICAgICAqICAgICB3b3JsZE1hbmFnZXIuZ2V0Q3VycmVudFdvcmxkKCkudGhlbihmdW5jdGlvbiAod29ybGRPYmplY3QsIHdvcmxkU2VydmljZSkge1xuICAgICAqICAgICAgICAgdmFyIHByZXNlbmNlQ2hhbm5lbCA9IGNtLmdldFByZXNlbmNlQ2hhbm5lbCh3b3JsZE9iamVjdCk7XG4gICAgICogICAgICAgICBwcmVzZW5jZUNoYW5uZWwub24oJ3ByZXNlbmNlJywgZnVuY3Rpb24gKGV2dCwgbm90aWZpY2F0aW9uKSB7XG4gICAgICogICAgICAgICAgICAgIGNvbnNvbGUubG9nKG5vdGlmaWNhdGlvbi5vbmxpbmUsIG5vdGlmaWNhdGlvbi51c2VySWQpO1xuICAgICAqICAgICAgICAgIH0pO1xuICAgICAqICAgICAgfSk7XG4gICAgICpcbiAgICAgKlxuICAgICAqICoqUmV0dXJuIFZhbHVlKipcbiAgICAgKlxuICAgICAqICogKkNoYW5uZWwqIFJldHVybnMgdGhlIGNoYW5uZWwgKGFuIGluc3RhbmNlIG9mIHRoZSBbQ2hhbm5lbCBTZXJ2aWNlXSguLi9jaGFubmVsLXNlcnZpY2UvKSkuXG4gICAgICpcbiAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAqXG4gICAgICogQHBhcmFtICB7U3RyaW5nfE9iamVjdH0gYHdvcmxkYCBXb3JsZCBvYmplY3Qgb3IgaWQuXG4gICAgICogQHBhcmFtICB7U3RyaW5nfE9iamVjdH0gYHVzZXJpZGAgKE9wdGlvbmFsKSBVc2VyIG9iamVjdCBvciBpZC4gSWYgbm90IHByb3ZpZGVkLCBwaWNrcyB1cCB1c2VyIGlkIGZyb20gY3VycmVudCBzZXNzaW9uIGlmIGVuZCB1c2VyIGlzIGxvZ2dlZCBpbi5cbiAgICAgKiBAcGFyYW0gIHtTdHJpbmd9IGBncm91cE5hbWVgIChPcHRpb25hbCkgR3JvdXAgdGhlIHdvcmxkIGV4aXN0cyBpbi4gSWYgbm90IHByb3ZpZGVkLCBwaWNrcyB1cCBncm91cCBmcm9tIGN1cnJlbnQgc2Vzc2lvbiBpZiBlbmQgdXNlciBpcyBsb2dnZWQgaW4uXG4gICAgICovXG4gICAgZ2V0UHJlc2VuY2VDaGFubmVsOiBmdW5jdGlvbiAod29ybGQsIHVzZXJpZCwgZ3JvdXBOYW1lKSB7XG4gICAgICAgIHZhciB3b3JsZGlkID0gKCQuaXNQbGFpbk9iamVjdCh3b3JsZCkgJiYgd29ybGQuaWQpID8gd29ybGQuaWQgOiB3b3JsZDtcbiAgICAgICAgaWYgKCF3b3JsZGlkKSB7XG4gICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ1BsZWFzZSBzcGVjaWZ5IGEgd29ybGQgaWQnKTtcbiAgICAgICAgfVxuICAgICAgICB1c2VyaWQgPSBnZXRGcm9tU2V0dGluZ3NPclNlc3Npb25PckVycm9yKHVzZXJpZCwgJ3VzZXJJZCcsIHRoaXMub3B0aW9ucyk7XG4gICAgICAgIGdyb3VwTmFtZSA9IGdldEZyb21TZXR0aW5nc09yU2Vzc2lvbk9yRXJyb3IoZ3JvdXBOYW1lLCAnZ3JvdXBOYW1lJywgdGhpcy5vcHRpb25zKTtcblxuICAgICAgICB2YXIgYWNjb3VudCA9IGdldEZyb21TZXR0aW5nc09yU2Vzc2lvbk9yRXJyb3IoJycsICdhY2NvdW50JywgdGhpcy5vcHRpb25zKTtcbiAgICAgICAgdmFyIHByb2plY3QgPSBnZXRGcm9tU2V0dGluZ3NPclNlc3Npb25PckVycm9yKCcnLCAncHJvamVjdCcsIHRoaXMub3B0aW9ucyk7XG5cbiAgICAgICAgdmFyIGJhc2VUb3BpYyA9IFsnL3VzZXInLCBhY2NvdW50LCBwcm9qZWN0LCBncm91cE5hbWUsIHdvcmxkaWRdLmpvaW4oJy8nKTtcbiAgICAgICAgdmFyIGNoYW5uZWwgPSBfX3N1cGVyLmdldENoYW5uZWwuY2FsbCh0aGlzLCB7IGJhc2U6IGJhc2VUb3BpYyB9KTtcblxuICAgICAgICB2YXIgbGFzdFBpbmdUaW1lID0geyB9O1xuXG4gICAgICAgIHZhciBQSU5HX0lOVEVSVkFMID0gNjAwMDtcbiAgICAgICAgY2hhbm5lbC5zdWJzY3JpYmUoJ2ludGVybmFsLXBpbmctY2hhbm5lbCcsIGZ1bmN0aW9uIChub3RpZmljYXRpb24pIHtcbiAgICAgICAgICAgIHZhciBpbmNvbWluZ1VzZXJJZCA9IG5vdGlmaWNhdGlvbi5kYXRhLnVzZXI7XG4gICAgICAgICAgICBpZiAoIWxhc3RQaW5nVGltZVtpbmNvbWluZ1VzZXJJZF0gJiYgaW5jb21pbmdVc2VySWQgIT09IHVzZXJpZCkge1xuICAgICAgICAgICAgICAgIGNoYW5uZWwudHJpZ2dlci5jYWxsKGNoYW5uZWwsICdwcmVzZW5jZScsIHsgdXNlcklkOiBpbmNvbWluZ1VzZXJJZCwgb25saW5lOiB0cnVlIH0pO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgbGFzdFBpbmdUaW1lW2luY29taW5nVXNlcklkXSA9IChuZXcgRGF0ZSgpKS52YWx1ZU9mKCk7XG4gICAgICAgIH0pO1xuXG4gICAgICAgIHNldEludGVydmFsKGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIGNoYW5uZWwucHVibGlzaCgnaW50ZXJuYWwtcGluZy1jaGFubmVsJywgeyB1c2VyOiB1c2VyaWQgfSk7XG5cbiAgICAgICAgICAgICQuZWFjaChsYXN0UGluZ1RpbWUsIGZ1bmN0aW9uIChrZXksIHZhbHVlKSB7XG4gICAgICAgICAgICAgICAgdmFyIG5vdyA9IChuZXcgRGF0ZSgpKS52YWx1ZU9mKCk7XG4gICAgICAgICAgICAgICAgaWYgKHZhbHVlICYmIHZhbHVlICsgKFBJTkdfSU5URVJWQUwgKiAyKSA8IG5vdykge1xuICAgICAgICAgICAgICAgICAgICBsYXN0UGluZ1RpbWVba2V5XSA9IG51bGw7XG4gICAgICAgICAgICAgICAgICAgIGNoYW5uZWwudHJpZ2dlci5jYWxsKGNoYW5uZWwsICdwcmVzZW5jZScsIHsgdXNlcklkOiBrZXksIG9ubGluZTogZmFsc2UgfSk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfSk7XG4gICAgICAgIH0sIFBJTkdfSU5URVJWQUwpO1xuXG4gICAgICAgIHJldHVybiBjaGFubmVsO1xuICAgIH0sXG5cbiAgICAvKipcbiAgICAgKiBDcmVhdGUgYW5kIHJldHVybiBhIHB1Ymxpc2gvc3Vic2NyaWJlIGNoYW5uZWwgKGZyb20gdGhlIHVuZGVybHlpbmcgW0NoYW5uZWwgTWFuYWdlcl0oLi4vY2hhbm5lbC1tYW5hZ2VyLykpIGZvciB0aGUgZ2l2ZW4gY29sbGVjdGlvbi4gKFRoZSBjb2xsZWN0aW9uIG5hbWUgaXMgc3BlY2lmaWVkIGluIHRoZSBgcm9vdGAgYXJndW1lbnQgd2hlbiB0aGUgW0RhdGEgU2VydmljZV0oLi4vZGF0YS1hcGktc2VydmljZS8pIGlzIGluc3RhbnRpYXRlZC4pIE11c3QgYmUgb25lIG9mIHRoZSBjb2xsZWN0aW9ucyBpbiB0aGlzIGFjY291bnQgKHRlYW0pIGFuZCBwcm9qZWN0LlxuICAgICAqXG4gICAgICogVGhlcmUgYXJlIGF1dG9tYXRpYyBub3RpZmljYXRpb25zIGZyb20gRXBpY2VudGVyIG9uIHRoaXMgY2hhbm5lbCB3aGVuIGRhdGEgaXMgY3JlYXRlZCwgdXBkYXRlZCwgb3IgZGVsZXRlZCBpbiB0aGlzIGNvbGxlY3Rpb24uIFNlZSBtb3JlIG9uIFthdXRvbWF0aWMgbWVzc2FnZXMgdG8gdGhlIGRhdGEgY2hhbm5lbF0oLi4vLi4vLi4vcmVzdF9hcGlzL211bHRpcGxheWVyL2NoYW5uZWwvI2RhdGEtbWVzc2FnZXMpLlxuICAgICAqXG4gICAgICogKipFeGFtcGxlKipcbiAgICAgKlxuICAgICAqICAgICB2YXIgY20gPSBuZXcgRi5tYW5hZ2VyLkNoYW5uZWxNYW5hZ2VyKCk7XG4gICAgICogICAgIHZhciBkYyA9IGNtLmdldERhdGFDaGFubmVsKCdzdXJ2ZXktcmVzcG9uc2VzJyk7XG4gICAgICogICAgIGRjLnN1YnNjcmliZSgnJywgZnVuY3Rpb24oZGF0YSwgbWV0YSkge1xuICAgICAqICAgICAgICAgIGNvbnNvbGUubG9nKGRhdGEpO1xuICAgICAqXG4gICAgICogICAgICAgICAgLy8gbWV0YS5kYXRlIGlzIHRpbWUgb2YgY2hhbmdlLFxuICAgICAqICAgICAgICAgIC8vIG1ldGEuc3ViVHlwZSBpcyB0aGUga2luZCBvZiBjaGFuZ2U6IG5ldywgdXBkYXRlLCBvciBkZWxldGVcbiAgICAgKiAgICAgICAgICAvLyBtZXRhLnBhdGggaXMgdGhlIGZ1bGwgcGF0aCB0byB0aGUgY2hhbmdlZCBkYXRhXG4gICAgICogICAgICAgICAgY29uc29sZS5sb2cobWV0YSk7XG4gICAgICogICAgIH0pO1xuICAgICAqXG4gICAgICogKipSZXR1cm4gVmFsdWUqKlxuICAgICAqXG4gICAgICogKiAqQ2hhbm5lbCogUmV0dXJucyB0aGUgY2hhbm5lbCAoYW4gaW5zdGFuY2Ugb2YgdGhlIFtDaGFubmVsIFNlcnZpY2VdKC4uL2NoYW5uZWwtc2VydmljZS8pKS5cbiAgICAgKlxuICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICpcbiAgICAgKiBAcGFyYW0gIHtTdHJpbmd9IGBjb2xsZWN0aW9uYCBOYW1lIG9mIGNvbGxlY3Rpb24gd2hvc2UgYXV0b21hdGljIG5vdGlmaWNhdGlvbnMgeW91IHdhbnQgdG8gcmVjZWl2ZS5cbiAgICAgKi9cbiAgICBnZXREYXRhQ2hhbm5lbDogZnVuY3Rpb24gKGNvbGxlY3Rpb24pIHtcbiAgICAgICAgaWYgKCFjb2xsZWN0aW9uKSB7XG4gICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ1BsZWFzZSBzcGVjaWZ5IGEgY29sbGVjdGlvbiB0byBsaXN0ZW4gb24uJyk7XG4gICAgICAgIH1cbiAgICAgICAgdmFyIGFjY291bnQgPSBnZXRGcm9tU2V0dGluZ3NPclNlc3Npb25PckVycm9yKCcnLCAnYWNjb3VudCcsIHRoaXMub3B0aW9ucyk7XG4gICAgICAgIHZhciBwcm9qZWN0ID0gZ2V0RnJvbVNldHRpbmdzT3JTZXNzaW9uT3JFcnJvcignJywgJ3Byb2plY3QnLCB0aGlzLm9wdGlvbnMpO1xuICAgICAgICB2YXIgYmFzZVRvcGljID0gWycvZGF0YScsIGFjY291bnQsIHByb2plY3QsIGNvbGxlY3Rpb25dLmpvaW4oJy8nKTtcbiAgICAgICAgdmFyIGNoYW5uZWwgPSBfX3N1cGVyLmdldENoYW5uZWwuY2FsbCh0aGlzLCB7IGJhc2U6IGJhc2VUb3BpYyB9KTtcblxuICAgICAgICAvL1RPRE86IEZpeCBhZnRlciBFcGljZW50ZXIgYnVnIGlzIHJlc29sdmVkXG4gICAgICAgIHZhciBvbGRzdWJzID0gY2hhbm5lbC5zdWJzY3JpYmU7XG4gICAgICAgIGNoYW5uZWwuc3Vic2NyaWJlID0gZnVuY3Rpb24gKHRvcGljLCBjYWxsYmFjaywgY29udGV4dCwgb3B0aW9ucykge1xuICAgICAgICAgICAgdmFyIGNhbGxiYWNrV2l0aENsZWFuRGF0YSA9IGZ1bmN0aW9uIChwYXlsb2FkKSB7XG4gICAgICAgICAgICAgICAgdmFyIG1ldGEgPSB7XG4gICAgICAgICAgICAgICAgICAgIHBhdGg6IHBheWxvYWQuY2hhbm5lbCxcbiAgICAgICAgICAgICAgICAgICAgc3ViVHlwZTogcGF5bG9hZC5kYXRhLnN1YlR5cGUsXG4gICAgICAgICAgICAgICAgICAgIGRhdGU6IHBheWxvYWQuZGF0YS5kYXRlXG4gICAgICAgICAgICAgICAgfTtcbiAgICAgICAgICAgICAgICB2YXIgYWN0dWFsRGF0YSA9IHBheWxvYWQuZGF0YS5kYXRhO1xuICAgICAgICAgICAgICAgIGlmIChhY3R1YWxEYXRhLmRhdGEpIHsgLy9EZWxldGUgbm90aWZpY2F0aW9ucyBhcmUgb25lIGRhdGEtbGV2ZWwgYmVoaW5kIG9mIGNvdXJzZVxuICAgICAgICAgICAgICAgICAgICBhY3R1YWxEYXRhID0gYWN0dWFsRGF0YS5kYXRhO1xuICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgIGNhbGxiYWNrLmNhbGwoY29udGV4dCwgYWN0dWFsRGF0YSwgbWV0YSk7XG4gICAgICAgICAgICB9O1xuICAgICAgICAgICAgcmV0dXJuIG9sZHN1YnMuY2FsbChjaGFubmVsLCB0b3BpYywgY2FsbGJhY2tXaXRoQ2xlYW5EYXRhLCBjb250ZXh0LCBvcHRpb25zKTtcbiAgICAgICAgfTtcblxuICAgICAgICByZXR1cm4gY2hhbm5lbDtcbiAgICB9XG59KTtcblxubW9kdWxlLmV4cG9ydHMgPSBFcGljZW50ZXJDaGFubmVsTWFuYWdlcjtcbiIsIid1c2Ugc3RyaWN0JztcblxubW9kdWxlLmV4cG9ydHMgPSB7XG4gICAgRVBJX1NFU1NJT05fS0VZOiAnZXBpY2VudGVyanMuc2Vzc2lvbicsXG4gICAgU1RSQVRFR1lfU0VTU0lPTl9LRVk6ICdlcGljZW50ZXItc2NlbmFyaW8nXG59OyIsIi8qKlxuKiAjIyBSdW4gTWFuYWdlclxuKlxuKiBUaGUgUnVuIE1hbmFnZXIgZ2l2ZXMgeW91IGFjY2VzcyB0byBydW5zIGZvciB5b3VyIHByb2plY3QuIFRoaXMgYWxsb3dzIHlvdSB0byByZWFkIGFuZCB1cGRhdGUgdmFyaWFibGVzLCBjYWxsIG9wZXJhdGlvbnMsIGV0Yy4gQWRkaXRpb25hbGx5LCB0aGUgUnVuIE1hbmFnZXIgZ2l2ZXMgeW91IGNvbnRyb2wgb3ZlciBydW4gY3JlYXRpb24gZGVwZW5kaW5nIG9uIHJ1biBzdGF0ZXMuIFNwZWNpZmljYWxseSwgeW91IGNhbiBzZWxlY3QgW3J1biBjcmVhdGlvbiBzdHJhdGVnaWVzIChydWxlcyldKC4uLy4uL3N0cmF0ZWd5LykgZm9yIHdoaWNoIHJ1bnMgZW5kIHVzZXJzIG9mIHlvdXIgcHJvamVjdCB3b3JrIHdpdGggd2hlbiB0aGV5IGxvZyBpbiB0byB5b3VyIHByb2plY3QuXG4qXG4qIFRoZXJlIGFyZSBtYW55IHdheXMgdG8gY3JlYXRlIG5ldyBydW5zLCBpbmNsdWRpbmcgdGhlIEVwaWNlbnRlci5qcyBbUnVuIFNlcnZpY2VdKC4uL3J1bi1hcGktc2VydmljZS8pLCB0aGUgUkVTRlRmdWwgW1J1biBBUEldKC4uLy4uLy4uL3Jlc3RfYXBpcy9hZ2dyZWdhdGVfcnVuX2FwaSkgYW5kIHRoZSBbTW9kZWwgUnVuIEFQSV0oLi4vLi4vLi4vcmVzdF9hcGlzL290aGVyX2FwaXMvbW9kZWxfYXBpcy9ydW4vKS4gSG93ZXZlciwgZm9yIHNvbWUgcHJvamVjdHMgaXQgbWFrZXMgbW9yZSBzZW5zZSB0byBwaWNrIHVwIHdoZXJlIHRoZSB1c2VyIGxlZnQgb2ZmLCB1c2luZyBhbiBleGlzdGluZyBydW4uIEFuZCBpbiBzb21lIHByb2plY3RzLCB3aGV0aGVyIHRvIGNyZWF0ZSBhIG5ldyBydW4gb3IgdXNlIGFuIGV4aXN0aW5nIG9uZSBpcyBjb25kaXRpb25hbCwgZm9yIGV4YW1wbGUgYmFzZWQgb24gY2hhcmFjdGVyaXN0aWNzIG9mIHRoZSBleGlzdGluZyBydW4gb3IgeW91ciBvd24ga25vd2xlZGdlIGFib3V0IHRoZSBtb2RlbC4gVGhlIFJ1biBNYW5hZ2VyIHByb3ZpZGVzIHRoaXMgbGV2ZWwgb2YgY29udHJvbDogeW91ciBjYWxsIHRvIGBnZXRSdW4oKWAsIHJhdGhlciB0aGFuIGFsd2F5cyByZXR1cm5pbmcgYSBuZXcgcnVuLCByZXR1cm5zIGEgcnVuIGJhc2VkIG9uIHRoZSBzdHJhdGVneSB5b3UndmUgc3BlY2lmaWVkLiAoTm90ZSB0aGF0IG1hbnkgb2YgdGhlIEVwaWNlbnRlciBzYW1wbGUgcHJvamVjdHMgdXNlIGEgUnVuIFNlcnZpY2UgZGlyZWN0bHksIGJlY2F1c2UgZ2VuZXJhbGx5IHRoZSBzYW1wbGUgcHJvamVjdHMgYXJlIHBsYXllZCBpbiBvbmUgZW5kIHVzZXIgc2Vzc2lvbiBhbmQgZG9uJ3QgY2FyZSBhYm91dCBydW4gc3RhdGVzIG9yIHJ1biBzdHJhdGVnaWVzLilcbipcbipcbiogIyMjIFVzaW5nIHRoZSBSdW4gTWFuYWdlciB0byBjcmVhdGUgYW5kIGFjY2VzcyBydW5zXG4qXG4qIFRvIHVzZSB0aGUgUnVuIE1hbmFnZXIsIGluc3RhbnRpYXRlIGl0IGJ5IHBhc3NpbmcgaW46XG4qXG4qICAgKiBgcnVuYDogKHJlcXVpcmVkKSBSdW4gb2JqZWN0LiBNdXN0IGNvbnRhaW46XG4qICAgICAgICogYGFjY291bnRgOiBFcGljZW50ZXIgYWNjb3VudCBpZCAoKipUZWFtIElEKiogZm9yIHRlYW0gcHJvamVjdHMsICoqVXNlciBJRCoqIGZvciBwZXJzb25hbCBwcm9qZWN0cykuXG4qICAgICAgICogYHByb2plY3RgOiBFcGljZW50ZXIgcHJvamVjdCBpZC5cbiogICAgICAgKiBgbW9kZWxgOiBUaGUgbmFtZSBvZiB5b3VyIHByaW1hcnkgbW9kZWwgZmlsZS4gKFNlZSBtb3JlIG9uIFtXcml0aW5nIHlvdXIgTW9kZWxdKC4uLy4uLy4uL3dyaXRpbmdfeW91cl9tb2RlbC8pLilcbiogICAgICAgKiBgc2NvcGVgOiAob3B0aW9uYWwpIFNjb3BlIG9iamVjdCBmb3IgdGhlIHJ1biwgZm9yIGV4YW1wbGUgYHNjb3BlLmdyb3VwYCB3aXRoIHZhbHVlIG9mIHRoZSBuYW1lIG9mIHRoZSBncm91cC5cbiogICAgICAgKiBgc2VydmVyYDogKG9wdGlvbmFsKSBBbiBvYmplY3Qgd2l0aCBvbmUgZmllbGQsIGBob3N0YC4gVGhlIHZhbHVlIG9mIGBob3N0YCBpcyB0aGUgc3RyaW5nIGBhcGkuZm9yaW8uY29tYCwgdGhlIFVSSSBvZiB0aGUgRm9yaW8gc2VydmVyLiBUaGlzIGlzIGF1dG9tYXRpY2FsbHkgc2V0LCBidXQgeW91IGNhbiBwYXNzIGl0IGV4cGxpY2l0bHkgaWYgZGVzaXJlZC4gSXQgaXMgbW9zdCBjb21tb25seSB1c2VkIGZvciBjbGFyaXR5IHdoZW4geW91IGFyZSBbaG9zdGluZyBhbiBFcGljZW50ZXIgcHJvamVjdCBvbiB5b3VyIG93biBzZXJ2ZXJdKC4uLy4uLy4uL2hvd190by9zZWxmX2hvc3RpbmcvKS5cbiogICAgICAgKiBgZmlsZXNgOiAob3B0aW9uYWwpIElmIGFuZCBvbmx5IGlmIHlvdSBhcmUgdXNpbmcgYSBWZW5zaW0gbW9kZWwgYW5kIHlvdSBoYXZlIGFkZGl0aW9uYWwgZGF0YSB0byBwYXNzIGluIHRvIHlvdXIgbW9kZWwsIHlvdSBjYW4gcGFzcyBhIGBmaWxlc2Agb2JqZWN0IHdpdGggdGhlIG5hbWVzIG9mIHRoZSBmaWxlcywgZm9yIGV4YW1wbGU6IGBcImZpbGVzXCI6IHtcImRhdGFcIjogXCJteUV4dHJhRGF0YS54bHNcIn1gLiAoTm90ZSB0aGF0IHlvdSdsbCBhbHNvIG5lZWQgdG8gYWRkIHRoaXMgc2FtZSBmaWxlcyBvYmplY3QgdG8geW91ciBWZW5zaW0gW2NvbmZpZ3VyYXRpb24gZmlsZV0oLi4vLi4vLi4vbW9kZWxfY29kZS92ZW5zaW0vKS4pIFNlZSB0aGUgW3VuZGVybHlpbmcgTW9kZWwgUnVuIEFQSV0oLi4vLi4vLi4vcmVzdF9hcGlzL290aGVyX2FwaXMvbW9kZWxfYXBpcy9ydW4vI3Bvc3QtY3JlYXRpbmctYS1uZXctcnVuLWZvci10aGlzLXByb2plY3QpIGZvciBhZGRpdGlvbmFsIGluZm9ybWF0aW9uLlxuKlxuKiAgICogYHN0cmF0ZWd5YDogKG9wdGlvbmFsKSBSdW4gY3JlYXRpb24gc3RyYXRlZ3kgZm9yIHdoZW4gdG8gY3JlYXRlIGEgbmV3IHJ1biBhbmQgd2hlbiB0byByZXVzZSBhbiBlbmQgdXNlcidzIGV4aXN0aW5nIHJ1bi4gU2VlIFtSdW4gTWFuYWdlciBTdHJhdGVnaWVzXSguLi8uLi9zdHJhdGVneS8pIGZvciBkZXRhaWxzLiBEZWZhdWx0cyB0byBgbmV3LWlmLWluaXRpYWxpemVkYC5cbipcbiogICAqIGBzZXNzaW9uS2V5YDogKG9wdGlvbmFsKSBOYW1lIG9mIGJyb3dzZXIgY29va2llIGluIHdoaWNoIHRvIHN0b3JlIHJ1biBpbmZvcm1hdGlvbiwgaW5jbHVkaW5nIHJ1biBpZC4gTWFueSBjb25kaXRpb25hbCBzdHJhdGVnaWVzLCBpbmNsdWRpbmcgdGhlIHByb3ZpZGVkIHN0cmF0ZWdpZXMsIHJlbHkgb24gdGhpcyBicm93c2VyIGNvb2tpZSB0byBzdG9yZSB0aGUgcnVuIGlkIGFuZCBoZWxwIG1ha2UgdGhlIGRlY2lzaW9uIG9mIHdoZXRoZXIgdG8gY3JlYXRlIGEgbmV3IHJ1biBvciB1c2UgYW4gZXhpc3Rpbmcgb25lLiBUaGUgbmFtZSBvZiB0aGlzIGNvb2tpZSBkZWZhdWx0cyB0byBgZXBpY2VudGVyLXNjZW5hcmlvYCBhbmQgY2FuIGJlIHNldCB3aXRoIHRoZSBgc2Vzc2lvbktleWAgcGFyYW1ldGVyLlxuKlxuKlxuKiBBZnRlciBpbnN0YW50aWF0aW5nIGEgUnVuIE1hbmFnZXIsIG1ha2UgYSBjYWxsIHRvIGBnZXRSdW4oKWAgd2hlbmV2ZXIgeW91IG5lZWQgdG8gYWNjZXNzIGEgcnVuIGZvciB0aGlzIGVuZCB1c2VyLiBUaGUgYFJ1bk1hbmFnZXIucnVuYCBjb250YWlucyB0aGUgaW5zdGFudGlhdGVkIFtSdW4gU2VydmljZV0oLi4vcnVuLWFwaS1zZXJ2aWNlLykuIFRoZSBSdW4gU2VydmljZSBhbGxvd3MgeW91IHRvIGFjY2VzcyB2YXJpYWJsZXMsIGNhbGwgb3BlcmF0aW9ucywgZXRjLlxuKlxuKiAqKkV4YW1wbGUqKlxuKlxuKiAgICAgICB2YXIgcm0gPSBuZXcgRi5tYW5hZ2VyLlJ1bk1hbmFnZXIoe1xuKiAgICAgICAgICAgcnVuOiB7XG4qICAgICAgICAgICAgICAgYWNjb3VudDogJ2FjbWUtc2ltdWxhdGlvbnMnLFxuKiAgICAgICAgICAgICAgIHByb2plY3Q6ICdzdXBwbHktY2hhaW4tZ2FtZScsXG4qICAgICAgICAgICAgICAgbW9kZWw6ICdzdXBwbHktY2hhaW4tbW9kZWwuamwnLFxuKiAgICAgICAgICAgICAgIHNlcnZlcjogeyBob3N0OiAnYXBpLmZvcmlvLmNvbScgfVxuKiAgICAgICAgICAgfSxcbiogICAgICAgICAgIHN0cmF0ZWd5OiAnYWx3YXlzLW5ldycsXG4qICAgICAgICAgICBzZXNzaW9uS2V5OiAnZXBpY2VudGVyLXNlc3Npb24nXG4qICAgICAgIH0pO1xuKiAgICAgICBybS5nZXRSdW4oKVxuKiAgICAgICAgICAgLnRoZW4oZnVuY3Rpb24ocnVuKSB7XG4qICAgICAgICAgICAgICAgLy8gdGhlIHJldHVybiB2YWx1ZSBvZiBnZXRSdW4oKSBpcyBhIHJ1biBvYmplY3RcbiogICAgICAgICAgICAgICB2YXIgdGhpc1J1bklkID0gcnVuLmlkO1xuKiAgICAgICAgICAgICAgIC8vIHRoZSBSdW5NYW5hZ2VyLnJ1biBhbHNvIGNvbnRhaW5zIHRoZSBpbnN0YW50aWF0ZWQgUnVuIFNlcnZpY2UsXG4qICAgICAgICAgICAgICAgLy8gc28gYW55IFJ1biBTZXJ2aWNlIG1ldGhvZCBpcyB2YWxpZCBoZXJlXG4qICAgICAgICAgICAgICAgcm0ucnVuLmRvKCdydW5Nb2RlbCcpO1xuKiAgICAgICB9KVxuKlxuKi9cblxuJ3VzZSBzdHJpY3QnO1xudmFyIHN0cmF0ZWdpZXNNYXAgPSByZXF1aXJlKCcuL3J1bi1zdHJhdGVnaWVzL3N0cmF0ZWdpZXMtbWFwJyk7XG52YXIgc3BlY2lhbE9wZXJhdGlvbnMgPSByZXF1aXJlKCcuL3NwZWNpYWwtb3BlcmF0aW9ucycpO1xudmFyIFJ1blNlcnZpY2UgPSByZXF1aXJlKCcuLi9zZXJ2aWNlL3J1bi1hcGktc2VydmljZScpO1xuXG5cbmZ1bmN0aW9uIHBhdGNoUnVuU2VydmljZShzZXJ2aWNlLCBtYW5hZ2VyKSB7XG4gICAgaWYgKHNlcnZpY2UucGF0Y2hlZCkge1xuICAgICAgICByZXR1cm4gc2VydmljZTtcbiAgICB9XG5cbiAgICB2YXIgb3JpZyA9IHNlcnZpY2UuZG87XG4gICAgc2VydmljZS5kbyA9IGZ1bmN0aW9uIChvcGVyYXRpb24sIHBhcmFtcywgb3B0aW9ucykge1xuICAgICAgICB2YXIgcmVzZXJ2ZWRPcHMgPSBPYmplY3Qua2V5cyhzcGVjaWFsT3BlcmF0aW9ucyk7XG4gICAgICAgIGlmIChyZXNlcnZlZE9wcy5pbmRleE9mKG9wZXJhdGlvbikgPT09IC0xKSB7XG4gICAgICAgICAgICByZXR1cm4gb3JpZy5hcHBseShzZXJ2aWNlLCBhcmd1bWVudHMpO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgcmV0dXJuIHNwZWNpYWxPcGVyYXRpb25zW29wZXJhdGlvbl0uY2FsbChzZXJ2aWNlLCBwYXJhbXMsIG9wdGlvbnMsIG1hbmFnZXIpO1xuICAgICAgICB9XG4gICAgfTtcblxuICAgIHNlcnZpY2UucGF0Y2hlZCA9IHRydWU7XG5cbiAgICByZXR1cm4gc2VydmljZTtcbn1cblxuXG5cbnZhciBkZWZhdWx0cyA9IHtcbiAgICAvKipcbiAgICAgKiBSdW4gY3JlYXRpb24gc3RyYXRlZ3kgZm9yIHdoZW4gdG8gY3JlYXRlIGEgbmV3IHJ1biBhbmQgd2hlbiB0byByZXVzZSBhbiBlbmQgdXNlcidzIGV4aXN0aW5nIHJ1bi4gU2VlIFtSdW4gTWFuYWdlciBTdHJhdGVnaWVzXSguLi8uLi9zdHJhdGVneS8pIGZvciBkZXRhaWxzLiBEZWZhdWx0cyB0byBgbmV3LWlmLWluaXRpYWxpemVkYC5cbiAgICAgKiBAdHlwZSB7U3RyaW5nfVxuICAgICAqL1xuXG4gICAgc3RyYXRlZ3k6ICduZXctaWYtaW5pdGlhbGl6ZWQnXG59O1xuXG5mdW5jdGlvbiBSdW5NYW5hZ2VyKG9wdGlvbnMpIHtcbiAgICB0aGlzLm9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSwgZGVmYXVsdHMsIG9wdGlvbnMpO1xuXG4gICAgaWYgKHRoaXMub3B0aW9ucy5ydW4gaW5zdGFuY2VvZiBSdW5TZXJ2aWNlKSB7XG4gICAgICAgIHRoaXMucnVuID0gdGhpcy5vcHRpb25zLnJ1bjtcbiAgICB9IGVsc2Uge1xuICAgICAgICB0aGlzLnJ1biA9IG5ldyBSdW5TZXJ2aWNlKHRoaXMub3B0aW9ucy5ydW4pO1xuICAgIH1cblxuICAgIHBhdGNoUnVuU2VydmljZSh0aGlzLnJ1biwgdGhpcyk7XG5cbiAgICB2YXIgU3RyYXRlZ3lDdG9yID0gdHlwZW9mIHRoaXMub3B0aW9ucy5zdHJhdGVneSA9PT0gJ2Z1bmN0aW9uJyA/IHRoaXMub3B0aW9ucy5zdHJhdGVneSA6IHN0cmF0ZWdpZXNNYXBbdGhpcy5vcHRpb25zLnN0cmF0ZWd5XTtcblxuICAgIGlmICghU3RyYXRlZ3lDdG9yKSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcignU3BlY2lmaWVkIHJ1biBjcmVhdGlvbiBzdHJhdGVneSB3YXMgaW52YWxpZDonLCB0aGlzLm9wdGlvbnMuc3RyYXRlZ3kpO1xuICAgIH1cblxuICAgIHRoaXMuc3RyYXRlZ3kgPSBuZXcgU3RyYXRlZ3lDdG9yKHRoaXMucnVuLCB0aGlzLm9wdGlvbnMpO1xufVxuXG5SdW5NYW5hZ2VyLnByb3RvdHlwZSA9IHtcbiAgICAvKipcbiAgICAgKiBSZXR1cm5zIHRoZSBydW4gb2JqZWN0IGZvciBhICdnb29kJyBydW4uXG4gICAgICpcbiAgICAgKiBBIGdvb2QgcnVuIGlzIGRlZmluZWQgYnkgdGhlIHN0cmF0ZWd5LiBGb3IgZXhhbXBsZSwgaWYgdGhlIHN0cmF0ZWd5IGlzIGBhbHdheXMtbmV3YCwgdGhlIGNhbGxcbiAgICAgKiB0byBgZ2V0UnVuKClgIGFsd2F5cyByZXR1cm5zIGEgbmV3bHkgY3JlYXRlZCBydW47IGlmIHRoZSBzdHJhdGVneSBpcyBgbmV3LWlmLXBlcnNpc3RlZGAsXG4gICAgICogYGdldFJ1bigpYCBjcmVhdGVzIGEgbmV3IHJ1biBpZiB0aGUgcHJldmlvdXMgcnVuIGlzIGluIGEgcGVyc2lzdGVkIHN0YXRlLCBvdGhlcndpc2VcbiAgICAgKiBpdCByZXR1cm5zIHRoZSBwcmV2aW91cyBydW4uIFNlZSBbUnVuIE1hbmFnZXIgU3RyYXRlZ2llc10oLi4vLi4vc3RyYXRlZ3kvKSBmb3IgbW9yZSBvbiBzdHJhdGVnaWVzLlxuICAgICAqXG4gICAgICogICoqRXhhbXBsZSoqXG4gICAgICpcbiAgICAgKiAgICAgIHJtLmdldFJ1bigpLnRoZW4oZnVuY3Rpb24gKHJ1bikge1xuICAgICAqICAgICAgICAgIC8vIHVzZSB0aGUgcnVuIG9iamVjdFxuICAgICAqICAgICAgICAgIHZhciB0aGlzUnVuSWQgPSBydW4uaWQ7XG4gICAgICpcbiAgICAgKiAgICAgICAgICAvLyB1c2UgdGhlIFJ1biBTZXJ2aWNlIG9iamVjdFxuICAgICAqICAgICAgICAgIHJtLnJ1bi5kbygncnVuTW9kZWwnKTtcbiAgICAgKiAgICAgIH0pO1xuICAgICAqXG4gICAgICogQHJldHVybiB7JHByb21pc2V9IFByb21pc2UgdG8gY29tcGxldGUgdGhlIGNhbGwuXG4gICAgICovXG4gICAgZ2V0UnVuOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHJldHVybiB0aGlzLnN0cmF0ZWd5XG4gICAgICAgICAgICAgICAgLmdldFJ1bigpO1xuICAgIH0sXG5cbiAgICAvKipcbiAgICAgKiBSZXR1cm5zIHRoZSBydW4gb2JqZWN0IGZvciBhIG5ldyBydW4sIHJlZ2FyZGxlc3Mgb2Ygc3RyYXRlZ3k6IGZvcmNlIGNyZWF0aW9uIG9mIGEgbmV3IHJ1bi5cbiAgICAgKlxuICAgICAqICAqKkV4YW1wbGUqKlxuICAgICAqXG4gICAgICogICAgICBybS5yZXNldCgpLnRoZW4oZnVuY3Rpb24gKHJ1bikge1xuICAgICAqICAgICAgICAgIC8vIHVzZSB0aGUgKG5ldykgcnVuIG9iamVjdFxuICAgICAqICAgICAgICAgIHZhciB0aGlzUnVuSWQgPSBydW4uaWQ7XG4gICAgICpcbiAgICAgKiAgICAgICAgICAvLyB1c2UgdGhlIFJ1biBTZXJ2aWNlIG9iamVjdFxuICAgICAqICAgICAgICAgIHJtLnJ1bi5kbygncnVuTW9kZWwnKTtcbiAgICAgKiAgICAgIH0pO1xuICAgICAqXG4gICAgICogKipQYXJhbWV0ZXJzKipcbiAgICAgKiBAcGFyYW0ge09iamVjdH0gYHJ1blNlcnZpY2VPcHRpb25zYCBUaGUgb3B0aW9ucyBvYmplY3QgdG8gY29uZmlndXJlIHRoZSBSdW4gU2VydmljZS4gU2VlIFtSdW4gQVBJIFNlcnZpY2VdKC4uL3J1bi1hcGktc2VydmljZS8pIGZvciBtb3JlLlxuICAgICAqL1xuICAgIHJlc2V0OiBmdW5jdGlvbiAocnVuU2VydmljZU9wdGlvbnMpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuc3RyYXRlZ3kucmVzZXQocnVuU2VydmljZU9wdGlvbnMpO1xuICAgIH1cbn07XG5cbm1vZHVsZS5leHBvcnRzID0gUnVuTWFuYWdlcjtcbiIsIid1c2Ugc3RyaWN0JztcblxudmFyIGNsYXNzRnJvbSA9IHJlcXVpcmUoJy4uLy4uL3V0aWwvaW5oZXJpdCcpO1xudmFyIENvbmRpdGlvbmFsU3RyYXRlZ3kgPSByZXF1aXJlKCcuL2NvbmRpdGlvbmFsLWNyZWF0aW9uLXN0cmF0ZWd5Jyk7XG5cbnZhciBfX3N1cGVyID0gQ29uZGl0aW9uYWxTdHJhdGVneS5wcm90b3R5cGU7XG5cbnZhciBTdHJhdGVneSA9IGNsYXNzRnJvbShDb25kaXRpb25hbFN0cmF0ZWd5LCB7XG4gICAgY29uc3RydWN0b3I6IGZ1bmN0aW9uIChydW5TZXJ2aWNlLCBvcHRpb25zKSB7XG4gICAgICAgIF9fc3VwZXIuY29uc3RydWN0b3IuY2FsbCh0aGlzLCBydW5TZXJ2aWNlLCB0aGlzLmNyZWF0ZUlmLCBvcHRpb25zKTtcbiAgICB9LFxuXG4gICAgY3JlYXRlSWY6IGZ1bmN0aW9uIChydW4sIGhlYWRlcnMpIHtcbiAgICAgICAgLy8gYWx3YXlzIGNyZWF0ZSBhIG5ldyBydW4hXG4gICAgICAgIHJldHVybiB0cnVlO1xuICAgIH1cbn0pO1xuXG5tb2R1bGUuZXhwb3J0cyA9IFN0cmF0ZWd5O1xuIiwiJ3VzZSBzdHJpY3QnO1xuXG52YXIgbWFrZVNlcSA9IHJlcXVpcmUoJy4uLy4uL3V0aWwvbWFrZS1zZXF1ZW5jZScpO1xudmFyIEJhc2UgPSByZXF1aXJlKCcuL2lkZW50aXR5LXN0cmF0ZWd5Jyk7XG52YXIgU2Vzc2lvbk1hbmFnZXIgPSByZXF1aXJlKCcuLi8uLi9zdG9yZS9zZXNzaW9uLW1hbmFnZXInKTtcbnZhciBjbGFzc0Zyb20gPSByZXF1aXJlKCcuLi8uLi91dGlsL2luaGVyaXQnKTtcbnZhciBBdXRoTWFuYWdlciA9IHJlcXVpcmUoJy4uL2F1dGgtbWFuYWdlcicpO1xuXG52YXIga2V5TmFtZXMgPSByZXF1aXJlKCcuLi9rZXktbmFtZXMnKTtcblxudmFyIGRlZmF1bHRzID0ge1xuICAgIHNlc3Npb25LZXk6IGtleU5hbWVzLlNUUkFURUdZX1NFU1NJT05fS0VZLFxuICAgIHBhdGg6ICcnXG59O1xuXG5mdW5jdGlvbiBzZXRSdW5JblNlc3Npb24oc2Vzc2lvbktleSwgcnVuLCBzZXNzaW9uTWFuYWdlcikge1xuICAgIHNlc3Npb25NYW5hZ2VyLmdldFN0b3JlKCkuc2V0KHNlc3Npb25LZXksIEpTT04uc3RyaW5naWZ5KHsgcnVuSWQ6IHJ1bi5pZCB9KSk7XG59XG5cbi8qKlxuKiBDb25kaXRpb25hbCBDcmVhdGlvbiBTdHJhdGVneVxuKiBUaGlzIHN0cmF0ZWd5IHdpbGwgdHJ5IHRvIGdldCB0aGUgcnVuIHN0b3JlZCBpbiB0aGUgY29va2llIGFuZFxuKiBldmFsdWF0ZSBpZiBuZWVkcyB0byBjcmVhdGUgYSBuZXcgcnVuIGJ5IGNhbGxpbmcgdGhlICdjb25kaXRpb24nIGZ1bmN0aW9uXG4qL1xuXG4vKiBqc2hpbnQgZXFudWxsOiB0cnVlICovXG52YXIgU3RyYXRlZ3kgPSBjbGFzc0Zyb20oQmFzZSwge1xuICAgIGNvbnN0cnVjdG9yOiBmdW5jdGlvbiBTdHJhdGVneShydW5TZXJ2aWNlLCBjb25kaXRpb24sIG9wdGlvbnMpIHtcblxuICAgICAgICBpZiAoY29uZGl0aW9uID09IG51bGwpIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcignQ29uZGl0aW9uYWwgc3RyYXRlZ3kgbmVlZHMgYSBjb25kaXRpb24gdG8gY3JlYXRldGUgYSBydW4nKTtcbiAgICAgICAgfVxuXG4gICAgICAgIHRoaXMuX2F1dGggPSBuZXcgQXV0aE1hbmFnZXIoKTtcbiAgICAgICAgdGhpcy5ydW4gPSBtYWtlU2VxKHJ1blNlcnZpY2UpO1xuICAgICAgICB0aGlzLmNvbmRpdGlvbiA9IHR5cGVvZiBjb25kaXRpb24gIT09ICdmdW5jdGlvbicgPyBmdW5jdGlvbiAoKSB7IHJldHVybiBjb25kaXRpb247IH0gOiBjb25kaXRpb247XG4gICAgICAgIHRoaXMub3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LCBkZWZhdWx0cywgb3B0aW9ucyk7XG4gICAgICAgIHRoaXMuc2Vzc2lvbk1hbmFnZXIgPSBuZXcgU2Vzc2lvbk1hbmFnZXIob3B0aW9ucyk7XG4gICAgICAgIHRoaXMucnVuT3B0aW9ucyA9IHRoaXMub3B0aW9ucy5ydW47XG4gICAgfSxcblxuICAgIHJ1bk9wdGlvbnNXaXRoU2NvcGU6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgdmFyIHVzZXJTZXNzaW9uID0gdGhpcy5fYXV0aC5nZXRDdXJyZW50VXNlclNlc3Npb25JbmZvKCk7XG4gICAgICAgIHJldHVybiAkLmV4dGVuZCh7XG4gICAgICAgICAgICBzY29wZTogeyBncm91cDogdXNlclNlc3Npb24uZ3JvdXBOYW1lIH1cbiAgICAgICAgfSwgdGhpcy5ydW5PcHRpb25zKTtcbiAgICB9LFxuXG4gICAgcmVzZXQ6IGZ1bmN0aW9uIChydW5TZXJ2aWNlT3B0aW9ucykge1xuICAgICAgICB2YXIgX3RoaXMgPSB0aGlzO1xuICAgICAgICB2YXIgb3B0ID0gdGhpcy5ydW5PcHRpb25zV2l0aFNjb3BlKCk7XG5cbiAgICAgICAgcmV0dXJuIHRoaXMucnVuXG4gICAgICAgICAgICAgICAgLmNyZWF0ZShvcHQsIHJ1blNlcnZpY2VPcHRpb25zKVxuICAgICAgICAgICAgLnRoZW4oZnVuY3Rpb24gKHJ1bikge1xuICAgICAgICAgICAgICAgIHNldFJ1bkluU2Vzc2lvbihfdGhpcy5vcHRpb25zLnNlc3Npb25LZXksIHJ1biwgX3RoaXMuc2Vzc2lvbk1hbmFnZXIpO1xuICAgICAgICAgICAgICAgIHJ1bi5mcmVzaGx5Q3JlYXRlZCA9IHRydWU7XG4gICAgICAgICAgICAgICAgcmV0dXJuIHJ1bjtcbiAgICAgICAgICAgIH0pXG4gICAgICAgICAgICAuc3RhcnQoKTtcbiAgICB9LFxuXG4gICAgZ2V0UnVuOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHZhciBzZXNzaW9uU3RvcmUgPSB0aGlzLnNlc3Npb25NYW5hZ2VyLmdldFN0b3JlKCk7XG4gICAgICAgIHZhciBydW5TZXNzaW9uID0gSlNPTi5wYXJzZShzZXNzaW9uU3RvcmUuZ2V0KHRoaXMub3B0aW9ucy5zZXNzaW9uS2V5KSk7XG5cbiAgICAgICAgaWYgKHJ1blNlc3Npb24gJiYgcnVuU2Vzc2lvbi5ydW5JZCkge1xuICAgICAgICAgICAgcmV0dXJuIHRoaXMuX2xvYWRBbmRDaGVjayhydW5TZXNzaW9uKS5mYWlsKGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gdGhpcy5yZXNldCgpOyAvL2lmIGl0IGdvdCB0aGUgd3JvbmcgY29va2llIGZvciBlLmcuXG4gICAgICAgICAgICB9LmJpbmQodGhpcykpO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgcmV0dXJuIHRoaXMucmVzZXQoKTtcbiAgICAgICAgfVxuICAgIH0sXG5cbiAgICBfbG9hZEFuZENoZWNrOiBmdW5jdGlvbiAocnVuU2Vzc2lvbikge1xuICAgICAgICB2YXIgc2hvdWxkQ3JlYXRlID0gZmFsc2U7XG4gICAgICAgIHZhciBfdGhpcyA9IHRoaXM7XG5cbiAgICAgICAgcmV0dXJuIHRoaXMucnVuXG4gICAgICAgICAgICAubG9hZChydW5TZXNzaW9uLnJ1bklkLCBudWxsLCB7XG4gICAgICAgICAgICAgICAgc3VjY2VzczogZnVuY3Rpb24gKHJ1biwgbXNnLCBoZWFkZXJzKSB7XG4gICAgICAgICAgICAgICAgICAgIHNob3VsZENyZWF0ZSA9IF90aGlzLmNvbmRpdGlvbi5jYWxsKF90aGlzLCBydW4sIGhlYWRlcnMpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH0pXG4gICAgICAgICAgICAudGhlbihmdW5jdGlvbiAocnVuKSB7XG4gICAgICAgICAgICAgICAgaWYgKHNob3VsZENyZWF0ZSkge1xuICAgICAgICAgICAgICAgICAgICB2YXIgb3B0ID0gX3RoaXMucnVuT3B0aW9uc1dpdGhTY29wZSgpO1xuICAgICAgICAgICAgICAgICAgICAvLyB3ZSBuZWVkIHRvIGRvIHRoaXMsIG9uIHRoZSBvcmlnaW5hbCBydW5TZXJ2aWNlIChpZSBub3Qgc2VxdWVuY2lhbGl6ZWQpXG4gICAgICAgICAgICAgICAgICAgIC8vIHNvIHdlIGRvbid0IGdldCBpbiB0aGUgbWlkZGxlIG9mIHRoZSBxdWV1ZVxuICAgICAgICAgICAgICAgICAgICByZXR1cm4gX3RoaXMucnVuLm9yaWdpbmFsLmNyZWF0ZShvcHQpXG4gICAgICAgICAgICAgICAgICAgIC50aGVuKGZ1bmN0aW9uIChydW4pIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHNldFJ1bkluU2Vzc2lvbihfdGhpcy5vcHRpb25zLnNlc3Npb25LZXksIHJ1biwgX3RoaXMuc2Vzc2lvbk1hbmFnZXIpO1xuICAgICAgICAgICAgICAgICAgICAgICAgcnVuLmZyZXNobHlDcmVhdGVkID0gdHJ1ZTtcbiAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybiBydW47XG4gICAgICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgIHJldHVybiBydW47XG4gICAgICAgICAgICB9KVxuICAgICAgICAgICAgLnN0YXJ0KCk7XG4gICAgfVxufSk7XG5cbm1vZHVsZS5leHBvcnRzID0gU3RyYXRlZ3k7XG4iLCIndXNlIHN0cmljdCc7XG5cbnZhciBjbGFzc0Zyb20gPSByZXF1aXJlKCcuLi8uLi91dGlsL2luaGVyaXQnKTtcbnZhciBCYXNlID0ge307XG5cbi8vIEludGVyZmFjZSB0aGF0IGFsbCBzdHJhdGVnaWVzIG5lZWQgdG8gaW1wbGVtZW50XG5tb2R1bGUuZXhwb3J0cyA9IGNsYXNzRnJvbShCYXNlLCB7XG4gICAgY29uc3RydWN0b3I6IGZ1bmN0aW9uIChydW5TZXJ2aWNlLCBvcHRpb25zKSB7XG4gICAgICAgIHRoaXMucnVuU2VydmljZSAgPSBydW5TZXJ2aWNlO1xuICAgIH0sXG5cbiAgICByZXNldDogZnVuY3Rpb24gKCkge1xuICAgICAgICAvLyByZXR1cm4gYSBuZXdseSBjcmVhdGVkIHJ1blxuICAgICAgICByZXR1cm4gJC5EZWZlcnJlZCgpLnJlc29sdmUoKS5wcm9taXNlKCk7XG4gICAgfSxcblxuICAgIGdldFJ1bjogZnVuY3Rpb24gKCkge1xuICAgICAgICAvLyByZXR1cm4gYSB1c2FibGUgcnVuXG4gICAgICAgIHJldHVybiAkLkRlZmVycmVkKCkucmVzb2x2ZSh0aGlzLnJ1blNlcnZpY2UpLnByb21pc2UoKTtcbiAgICB9XG59KTtcbiIsIid1c2Ugc3RyaWN0JztcblxudmFyIGNsYXNzRnJvbSA9IHJlcXVpcmUoJy4uLy4uL3V0aWwvaW5oZXJpdCcpO1xuXG52YXIgSWRlbnRpdHlTdHJhdGVneSA9IHJlcXVpcmUoJy4vaWRlbnRpdHktc3RyYXRlZ3knKTtcbnZhciBXb3JsZEFwaUFkYXB0ZXIgPSByZXF1aXJlKCcuLi8uLi9zZXJ2aWNlL3dvcmxkLWFwaS1hZGFwdGVyJyk7XG52YXIgQXV0aE1hbmFnZXIgPSByZXF1aXJlKCcuLi9hdXRoLW1hbmFnZXInKTtcblxudmFyIGRlZmF1bHRzID0ge1xuICAgIHN0b3JlOiB7XG4gICAgICAgIHN5bmNocm9ub3VzOiB0cnVlXG4gICAgfVxufTtcblxudmFyIFN0cmF0ZWd5ID0gY2xhc3NGcm9tKElkZW50aXR5U3RyYXRlZ3ksIHtcblxuICAgIGNvbnN0cnVjdG9yOiBmdW5jdGlvbiAocnVuU2VydmljZSwgb3B0aW9ucykge1xuICAgICAgICB0aGlzLnJ1blNlcnZpY2UgPSBydW5TZXJ2aWNlO1xuICAgICAgICB0aGlzLm9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSwgZGVmYXVsdHMsIG9wdGlvbnMpO1xuICAgICAgICB0aGlzLl9hdXRoID0gbmV3IEF1dGhNYW5hZ2VyKCk7XG4gICAgICAgIHRoaXMuX2xvYWRSdW4gPSB0aGlzLl9sb2FkUnVuLmJpbmQodGhpcyk7XG4gICAgICAgIHRoaXMud29ybGRBcGkgPSBuZXcgV29ybGRBcGlBZGFwdGVyKHRoaXMub3B0aW9ucy5ydW4pO1xuICAgIH0sXG5cbiAgICByZXNldDogZnVuY3Rpb24gKCkge1xuICAgICAgICB2YXIgc2Vzc2lvbiA9IHRoaXMuX2F1dGguZ2V0Q3VycmVudFVzZXJTZXNzaW9uSW5mbygpO1xuICAgICAgICB2YXIgY3VyVXNlcklkID0gc2Vzc2lvbi51c2VySWQ7XG4gICAgICAgIHZhciBjdXJHcm91cE5hbWUgPSBzZXNzaW9uLmdyb3VwTmFtZTtcblxuICAgICAgICByZXR1cm4gdGhpcy53b3JsZEFwaVxuICAgICAgICAgICAgLmdldEN1cnJlbnRXb3JsZEZvclVzZXIoY3VyVXNlcklkLCBjdXJHcm91cE5hbWUpXG4gICAgICAgICAgICAudGhlbihmdW5jdGlvbiAod29ybGQpIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gdGhpcy53b3JsZEFwaS5uZXdSdW5Gb3JXb3JsZCh3b3JsZC5pZCk7XG4gICAgICAgICAgICB9LmJpbmQodGhpcykpO1xuICAgIH0sXG5cbiAgICBnZXRSdW46IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgdmFyIHNlc3Npb24gPSB0aGlzLl9hdXRoLmdldEN1cnJlbnRVc2VyU2Vzc2lvbkluZm8oKTtcbiAgICAgICAgdmFyIGN1clVzZXJJZCA9IHNlc3Npb24udXNlcklkO1xuICAgICAgICB2YXIgY3VyR3JvdXBOYW1lID0gc2Vzc2lvbi5ncm91cE5hbWU7XG4gICAgICAgIHZhciB3b3JsZEFwaSA9IHRoaXMud29ybGRBcGk7XG4gICAgICAgIHZhciBtb2RlbCA9IHRoaXMub3B0aW9ucy5tb2RlbDtcbiAgICAgICAgdmFyIF90aGlzID0gdGhpcztcbiAgICAgICAgdmFyIGR0ZCA9ICQuRGVmZXJyZWQoKTtcblxuICAgICAgICBpZiAoIWN1clVzZXJJZCkge1xuICAgICAgICAgICAgcmV0dXJuIGR0ZC5yZWplY3QoeyBzdGF0dXNDb2RlOiA0MDAsIGVycm9yOiAnV2UgbmVlZCBhbiBhdXRoZW50aWNhdGVkIHVzZXIgdG8gam9pbiBhIG11bHRpcGxheWVyIHdvcmxkLiAoRVJSOiBubyB1c2VySWQgaW4gc2Vzc2lvbiknIH0sIHNlc3Npb24pLnByb21pc2UoKTtcbiAgICAgICAgfVxuXG4gICAgICAgIHZhciBsb2FkUnVuRnJvbVdvcmxkID0gZnVuY3Rpb24gKHdvcmxkKSB7XG4gICAgICAgICAgICBpZiAoIXdvcmxkKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIGR0ZC5yZWplY3QoeyBzdGF0dXNDb2RlOiA0MDQsIGVycm9yOiAnVGhlIHVzZXIgaXMgbm90IGluIGFueSB3b3JsZC4nIH0sIHsgb3B0aW9uczogdGhpcy5vcHRpb25zLCBzZXNzaW9uOiBzZXNzaW9uIH0pO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICByZXR1cm4gd29ybGRBcGkuZ2V0Q3VycmVudFJ1bklkKHsgbW9kZWw6IG1vZGVsLCBmaWx0ZXI6IHdvcmxkLmlkIH0pXG4gICAgICAgICAgICAgICAgLnRoZW4oX3RoaXMuX2xvYWRSdW4pXG4gICAgICAgICAgICAgICAgLnRoZW4oZHRkLnJlc29sdmUpXG4gICAgICAgICAgICAgICAgLmZhaWwoZHRkLnJlamVjdCk7XG4gICAgICAgIH07XG5cbiAgICAgICAgdmFyIHNlcnZlckVycm9yID0gZnVuY3Rpb24gKGVycm9yKSB7XG4gICAgICAgICAgICAvLyBpcyB0aGlzIHBvc3NpYmxlP1xuICAgICAgICAgICAgZHRkLnJlamVjdChlcnJvciwgc2Vzc2lvbiwgdGhpcy5vcHRpb25zKTtcbiAgICAgICAgfTtcblxuICAgICAgICB0aGlzLndvcmxkQXBpXG4gICAgICAgICAgICAuZ2V0Q3VycmVudFdvcmxkRm9yVXNlcihjdXJVc2VySWQsIGN1ckdyb3VwTmFtZSlcbiAgICAgICAgICAgIC50aGVuKGxvYWRSdW5Gcm9tV29ybGQpXG4gICAgICAgICAgICAuZmFpbChzZXJ2ZXJFcnJvcik7XG5cbiAgICAgICAgcmV0dXJuIGR0ZC5wcm9taXNlKCk7XG4gICAgfSxcblxuICAgIF9sb2FkUnVuOiBmdW5jdGlvbiAoaWQsIG9wdGlvbnMpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMucnVuU2VydmljZS5sb2FkKGlkLCBudWxsLCBvcHRpb25zKTtcbiAgICB9XG59KTtcblxubW9kdWxlLmV4cG9ydHMgPSBTdHJhdGVneTtcbiIsIid1c2Ugc3RyaWN0JztcbnZhciBjbGFzc0Zyb20gPSByZXF1aXJlKCcuLi8uLi91dGlsL2luaGVyaXQnKTtcbnZhciBDb25kaXRpb25hbFN0cmF0ZWd5ID0gcmVxdWlyZSgnLi9jb25kaXRpb25hbC1jcmVhdGlvbi1zdHJhdGVneScpO1xuXG52YXIgX19zdXBlciA9IENvbmRpdGlvbmFsU3RyYXRlZ3kucHJvdG90eXBlO1xuXG52YXIgU3RyYXRlZ3kgPSBjbGFzc0Zyb20oQ29uZGl0aW9uYWxTdHJhdGVneSwge1xuICAgIGNvbnN0cnVjdG9yOiBmdW5jdGlvbiAocnVuU2VydmljZSwgb3B0aW9ucykge1xuICAgICAgICBfX3N1cGVyLmNvbnN0cnVjdG9yLmNhbGwodGhpcywgcnVuU2VydmljZSwgdGhpcy5jcmVhdGVJZiwgb3B0aW9ucyk7XG4gICAgfSxcblxuICAgIGNyZWF0ZUlmOiBmdW5jdGlvbiAocnVuLCBoZWFkZXJzKSB7XG4gICAgICAgIHJldHVybiBoZWFkZXJzLmdldFJlc3BvbnNlSGVhZGVyKCdwcmFnbWEnKSA9PT0gJ3BlcnNpc3RlbnQnIHx8IHJ1bi5pbml0aWFsaXplZDtcbiAgICB9XG59KTtcblxubW9kdWxlLmV4cG9ydHMgPSBTdHJhdGVneTtcbiIsIid1c2Ugc3RyaWN0JztcblxudmFyIGNsYXNzRnJvbSA9IHJlcXVpcmUoJy4uLy4uL3V0aWwvaW5oZXJpdCcpO1xudmFyIENvbmRpdGlvbmFsU3RyYXRlZ3kgPSByZXF1aXJlKCcuL2NvbmRpdGlvbmFsLWNyZWF0aW9uLXN0cmF0ZWd5Jyk7XG5cbnZhciBfX3N1cGVyID0gQ29uZGl0aW9uYWxTdHJhdGVneS5wcm90b3R5cGU7XG5cbi8qXG4qICBjcmVhdGUgYSBuZXcgcnVuIG9ubHkgaWYgbm90aGluZyBpcyBzdG9yZWQgaW4gdGhlIGNvb2tpZVxuKiAgdGhpcyBpcyB1c2VmdWwgZm9yIGJhc2VSdW5zLlxuKi9cbnZhciBTdHJhdGVneSA9IGNsYXNzRnJvbShDb25kaXRpb25hbFN0cmF0ZWd5LCB7XG4gICAgY29uc3RydWN0b3I6IGZ1bmN0aW9uIChydW5TZXJ2aWNlLCBvcHRpb25zKSB7XG4gICAgICAgIF9fc3VwZXIuY29uc3RydWN0b3IuY2FsbCh0aGlzLCBydW5TZXJ2aWNlLCB0aGlzLmNyZWF0ZUlmLCBvcHRpb25zKTtcbiAgICB9LFxuXG4gICAgY3JlYXRlSWY6IGZ1bmN0aW9uIChydW4sIGhlYWRlcnMpIHtcbiAgICAgICAgLy8gaWYgd2UgYXJlIGhlcmUsIGl0IG1lYW5zIHRoYXQgdGhlIHJ1biBleGlzdHMuLi4gc28gd2UgZG9uJ3QgbmVlZCBhIG5ldyBvbmVcbiAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgIH1cbn0pO1xuXG5tb2R1bGUuZXhwb3J0cyA9IFN0cmF0ZWd5O1xuIiwiJ3VzZSBzdHJpY3QnO1xudmFyIGNsYXNzRnJvbSA9IHJlcXVpcmUoJy4uLy4uL3V0aWwvaW5oZXJpdCcpO1xudmFyIENvbmRpdGlvbmFsU3RyYXRlZ3kgPSByZXF1aXJlKCcuL2NvbmRpdGlvbmFsLWNyZWF0aW9uLXN0cmF0ZWd5Jyk7XG5cbnZhciBfX3N1cGVyID0gQ29uZGl0aW9uYWxTdHJhdGVneS5wcm90b3R5cGU7XG5cbnZhciBTdHJhdGVneSA9IGNsYXNzRnJvbShDb25kaXRpb25hbFN0cmF0ZWd5LCB7XG4gICAgY29uc3RydWN0b3I6IGZ1bmN0aW9uIChydW5TZXJ2aWNlLCBvcHRpb25zKSB7XG4gICAgICAgIF9fc3VwZXIuY29uc3RydWN0b3IuY2FsbCh0aGlzLCBydW5TZXJ2aWNlLCB0aGlzLmNyZWF0ZUlmLCBvcHRpb25zKTtcbiAgICB9LFxuXG4gICAgY3JlYXRlSWY6IGZ1bmN0aW9uIChydW4sIGhlYWRlcnMpIHtcbiAgICAgICAgcmV0dXJuIGhlYWRlcnMuZ2V0UmVzcG9uc2VIZWFkZXIoJ3ByYWdtYScpID09PSAncGVyc2lzdGVudCc7XG4gICAgfVxufSk7XG5cbm1vZHVsZS5leHBvcnRzID0gU3RyYXRlZ3k7XG4iLCIndXNlIHN0cmljdCc7XG5cbnZhciBjbGFzc0Zyb20gPSByZXF1aXJlKCcuLi8uLi91dGlsL2luaGVyaXQnKTtcbnZhciBJZGVudGl0eVN0cmF0ZWd5ID0gcmVxdWlyZSgnLi9pZGVudGl0eS1zdHJhdGVneScpO1xudmFyIFN0b3JhZ2VGYWN0b3J5ID0gcmVxdWlyZSgnLi4vLi4vc3RvcmUvc3RvcmUtZmFjdG9yeScpO1xudmFyIFN0YXRlQXBpID0gcmVxdWlyZSgnLi4vLi4vc2VydmljZS9zdGF0ZS1hcGktYWRhcHRlcicpO1xudmFyIEF1dGhNYW5hZ2VyID0gcmVxdWlyZSgnLi4vYXV0aC1tYW5hZ2VyJyk7XG5cbnZhciBrZXlOYW1lcyA9IHJlcXVpcmUoJy4uL2tleS1uYW1lcycpO1xuXG52YXIgZGVmYXVsdHMgPSB7XG4gICAgc3RvcmU6IHtcbiAgICAgICAgc3luY2hyb25vdXM6IHRydWVcbiAgICB9XG59O1xuXG52YXIgU3RyYXRlZ3kgPSBjbGFzc0Zyb20oSWRlbnRpdHlTdHJhdGVneSwge1xuICAgIGNvbnN0cnVjdG9yOiBmdW5jdGlvbiBTdHJhdGVneShydW5TZXJ2aWNlLCBvcHRpb25zKSB7XG4gICAgICAgIHRoaXMucnVuID0gcnVuU2VydmljZTtcbiAgICAgICAgdGhpcy5vcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sIGRlZmF1bHRzLCBvcHRpb25zKTtcbiAgICAgICAgdGhpcy5ydW5PcHRpb25zID0gdGhpcy5vcHRpb25zLnJ1bjtcbiAgICAgICAgdGhpcy5fc3RvcmUgPSBuZXcgU3RvcmFnZUZhY3RvcnkodGhpcy5vcHRpb25zLnN0b3JlKTtcbiAgICAgICAgdGhpcy5zdGF0ZUFwaSA9IG5ldyBTdGF0ZUFwaSgpO1xuICAgICAgICB0aGlzLl9hdXRoID0gbmV3IEF1dGhNYW5hZ2VyKCk7XG5cbiAgICAgICAgdGhpcy5fbG9hZEFuZENoZWNrID0gdGhpcy5fbG9hZEFuZENoZWNrLmJpbmQodGhpcyk7XG4gICAgICAgIHRoaXMuX3Jlc3RvcmVSdW4gPSB0aGlzLl9yZXN0b3JlUnVuLmJpbmQodGhpcyk7XG4gICAgICAgIHRoaXMuX2dldEFsbFJ1bnMgPSB0aGlzLl9nZXRBbGxSdW5zLmJpbmQodGhpcyk7XG4gICAgICAgIHRoaXMuX2xvYWRSdW4gPSB0aGlzLl9sb2FkUnVuLmJpbmQodGhpcyk7XG4gICAgfSxcblxuICAgIHJlc2V0OiBmdW5jdGlvbiAocnVuU2VydmljZU9wdGlvbnMpIHtcbiAgICAgICAgdmFyIHNlc3Npb24gPSB0aGlzLl9hdXRoLmdldEN1cnJlbnRVc2VyU2Vzc2lvbkluZm8oKTtcbiAgICAgICAgdmFyIG9wdCA9ICQuZXh0ZW5kKHtcbiAgICAgICAgICAgIHNjb3BlOiB7IGdyb3VwOiBzZXNzaW9uLmdyb3VwTmFtZSB9XG4gICAgICAgIH0sIHRoaXMucnVuT3B0aW9ucyk7XG5cbiAgICAgICAgcmV0dXJuIHRoaXMucnVuXG4gICAgICAgICAgICAuY3JlYXRlKG9wdCwgcnVuU2VydmljZU9wdGlvbnMpXG4gICAgICAgICAgICAudGhlbihmdW5jdGlvbiAocnVuKSB7XG4gICAgICAgICAgICAgICAgcnVuLmZyZXNobHlDcmVhdGVkID0gdHJ1ZTtcbiAgICAgICAgICAgICAgICByZXR1cm4gcnVuO1xuICAgICAgICAgICAgfSk7XG4gICAgfSxcblxuICAgIGdldFJ1bjogZnVuY3Rpb24gKCkge1xuICAgICAgICByZXR1cm4gdGhpcy5fZ2V0QWxsUnVucygpXG4gICAgICAgICAgICAudGhlbih0aGlzLl9sb2FkQW5kQ2hlY2spO1xuICAgIH0sXG5cbiAgICBfZ2V0QWxsUnVuczogZnVuY3Rpb24gKCkge1xuICAgICAgICB2YXIgc2Vzc2lvbiA9IEpTT04ucGFyc2UodGhpcy5fc3RvcmUuZ2V0KGtleU5hbWVzLkVQSV9TRVNTSU9OX0tFWSkgfHwgJ3t9Jyk7XG4gICAgICAgIHJldHVybiB0aGlzLnJ1bi5xdWVyeSh7XG4gICAgICAgICAgICAndXNlci5pZCc6IHNlc3Npb24udXNlcklkIHx8ICcwMDAwJyxcbiAgICAgICAgICAgICdzY29wZS5ncm91cCc6IHNlc3Npb24uZ3JvdXBOYW1lXG4gICAgICAgIH0pO1xuICAgIH0sXG5cbiAgICBfbG9hZEFuZENoZWNrOiBmdW5jdGlvbiAocnVucykge1xuICAgICAgICBpZiAoIXJ1bnMgfHwgIXJ1bnMubGVuZ3RoKSB7XG4gICAgICAgICAgICByZXR1cm4gdGhpcy5yZXNldCgpO1xuICAgICAgICB9XG5cbiAgICAgICAgdmFyIGRhdGVDb21wID0gZnVuY3Rpb24gKGEsIGIpIHsgcmV0dXJuIG5ldyBEYXRlKGIuZGF0ZSkgLSBuZXcgRGF0ZShhLmRhdGUpOyB9O1xuICAgICAgICB2YXIgbGF0ZXN0UnVuID0gcnVucy5zb3J0KGRhdGVDb21wKVswXTtcbiAgICAgICAgdmFyIF90aGlzID0gdGhpcztcbiAgICAgICAgdmFyIHNob3VsZFJlcGxheSA9IGZhbHNlO1xuXG4gICAgICAgIHJldHVybiB0aGlzLnJ1bi5sb2FkKGxhdGVzdFJ1bi5pZCwgbnVsbCwge1xuICAgICAgICAgICAgc3VjY2VzczogZnVuY3Rpb24gKHJ1biwgbXNnLCBoZWFkZXJzKSB7XG4gICAgICAgICAgICAgICAgc2hvdWxkUmVwbGF5ID0gaGVhZGVycy5nZXRSZXNwb25zZUhlYWRlcigncHJhZ21hJykgPT09ICdwZXJzaXN0ZW50JztcbiAgICAgICAgICAgIH1cbiAgICAgICAgfSkudGhlbihmdW5jdGlvbiAocnVuKSB7XG4gICAgICAgICAgICByZXR1cm4gc2hvdWxkUmVwbGF5ID8gX3RoaXMuX3Jlc3RvcmVSdW4ocnVuLmlkKSA6IHJ1bjtcbiAgICAgICAgfSk7XG4gICAgfSxcblxuICAgIF9yZXN0b3JlUnVuOiBmdW5jdGlvbiAocnVuSWQpIHtcbiAgICAgICAgdmFyIF90aGlzID0gdGhpcztcbiAgICAgICAgcmV0dXJuIHRoaXMuc3RhdGVBcGkucmVwbGF5KHsgcnVuSWQ6IHJ1bklkIH0pXG4gICAgICAgICAgICAudGhlbihmdW5jdGlvbiAocmVzcCkge1xuICAgICAgICAgICAgICAgIHJldHVybiBfdGhpcy5fbG9hZFJ1bihyZXNwLnJ1bik7XG4gICAgICAgICAgICB9KTtcbiAgICB9LFxuXG4gICAgX2xvYWRSdW46IGZ1bmN0aW9uIChpZCwgb3B0aW9ucykge1xuICAgICAgICByZXR1cm4gdGhpcy5ydW4ubG9hZChpZCwgbnVsbCwgb3B0aW9ucyk7XG4gICAgfVxuXG59KTtcblxubW9kdWxlLmV4cG9ydHMgPSBTdHJhdGVneTtcbiIsIm1vZHVsZS5leHBvcnRzID0ge1xuICAgICduZXctaWYtaW5pdGlhbGl6ZWQnOiByZXF1aXJlKCcuL25ldy1pZi1pbml0aWFsaXplZC1zdHJhdGVneScpLFxuICAgICduZXctaWYtcGVyc2lzdGVkJzogcmVxdWlyZSgnLi9uZXctaWYtcGVyc2lzdGVkLXN0cmF0ZWd5JyksXG4gICAgJ25ldy1pZi1taXNzaW5nJzogcmVxdWlyZSgnLi9uZXctaWYtbWlzc2luZy1zdHJhdGVneScpLFxuICAgICdhbHdheXMtbmV3JzogcmVxdWlyZSgnLi9hbHdheXMtbmV3LXN0cmF0ZWd5JyksXG4gICAgJ211bHRpcGxheWVyJzogcmVxdWlyZSgnLi9tdWx0aXBsYXllci1zdHJhdGVneScpLFxuICAgICdwZXJzaXN0ZW50LXNpbmdsZS1wbGF5ZXInOiByZXF1aXJlKCcuL3BlcnNpc3RlbnQtc2luZ2xlLXBsYXllci1zdHJhdGVneScpLFxuICAgICdub25lJzogcmVxdWlyZSgnLi9pZGVudGl0eS1zdHJhdGVneScpXG59O1xuIiwiJ3VzZSBzdHJpY3QnO1xudmFyIFJ1blNlcnZpY2UgPSByZXF1aXJlKCcuLi9zZXJ2aWNlL3J1bi1hcGktc2VydmljZScpO1xuXG52YXIgZGVmYXVsdHMgPSB7XG4gICAgdmFsaWRGaWx0ZXI6IHsgc2F2ZWQ6IHRydWUgfVxufTtcblxuZnVuY3Rpb24gU2NlbmFyaW9NYW5hZ2VyKG9wdGlvbnMpIHtcbiAgICB0aGlzLm9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSwgZGVmYXVsdHMsIG9wdGlvbnMpO1xuICAgIHRoaXMucnVuU2VydmljZSA9IHRoaXMub3B0aW9ucy5ydW4gfHwgbmV3IFJ1blNlcnZpY2UodGhpcy5vcHRpb25zKTtcbn1cblxuU2NlbmFyaW9NYW5hZ2VyLnByb3RvdHlwZSA9IHtcbiAgICBnZXRSdW5zOiBmdW5jdGlvbiAoZmlsdGVyKSB7XG4gICAgICAgIHRoaXMuZmlsdGVyID0gJC5leHRlbmQodHJ1ZSwge30sIHRoaXMub3B0aW9ucy52YWxpZEZpbHRlciwgZmlsdGVyKTtcbiAgICAgICAgcmV0dXJuIHRoaXMucnVuU2VydmljZS5xdWVyeSh0aGlzLmZpbHRlcik7XG4gICAgfSxcblxuICAgIGxvYWRWYXJpYWJsZXM6IGZ1bmN0aW9uICh2YXJzKSB7XG4gICAgICAgIHJldHVybiB0aGlzLnJ1blNlcnZpY2UucXVlcnkodGhpcy5maWx0ZXIsIHsgaW5jbHVkZTogdmFycyB9KTtcbiAgICB9LFxuXG4gICAgc2F2ZTogZnVuY3Rpb24gKHJ1biwgbWV0YSkge1xuICAgICAgICByZXR1cm4gdGhpcy5fZ2V0U2VydmljZShydW4pLnNhdmUoJC5leHRlbmQodHJ1ZSwge30sIHsgc2F2ZWQ6IHRydWUgfSwgbWV0YSkpO1xuICAgIH0sXG5cbiAgICBhcmNoaXZlOiBmdW5jdGlvbiAocnVuKSB7XG4gICAgICAgIHJldHVybiB0aGlzLl9nZXRTZXJ2aWNlKHJ1bikuc2F2ZSh7IHNhdmVkOiBmYWxzZSB9KTtcbiAgICB9LFxuXG4gICAgX2dldFNlcnZpY2U6IGZ1bmN0aW9uIChydW4pIHtcbiAgICAgICAgaWYgKHR5cGVvZiBydW4gPT09ICdzdHJpbmcnKSB7XG4gICAgICAgICAgICByZXR1cm4gbmV3IFJ1blNlcnZpY2UoJC5leHRlbmQodHJ1ZSwge30sICB0aGlzLm9wdGlvbnMsIHsgZmlsdGVyOiBydW4gfSkpO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKHR5cGVvZiBydW4gPT09ICdvYmplY3QnICYmIHJ1biBpbnN0YW5jZW9mIFJ1blNlcnZpY2UpIHtcbiAgICAgICAgICAgIHJldHVybiBydW47XG4gICAgICAgIH1cblxuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ1NhdmUgbWV0aG9kIHJlcXVpcmVzIGEgcnVuIHNlcnZpY2Ugb3IgYSBydW5JZCcpO1xuICAgIH0sXG5cbiAgICBnZXRSdW46IGZ1bmN0aW9uIChydW5JZCkge1xuICAgICAgICByZXR1cm4gbmV3IFJ1blNlcnZpY2UoJC5leHRlbmQodHJ1ZSwge30sICB0aGlzLm9wdGlvbnMsIHsgZmlsdGVyOiBydW5JZCB9KSk7XG4gICAgfVxufTtcblxubW9kdWxlLmV4cG9ydHMgPSBTY2VuYXJpb01hbmFnZXI7XG5cbiIsIid1c2Ugc3RyaWN0JztcblxuXG5tb2R1bGUuZXhwb3J0cyA9IHtcbiAgICByZXNldDogZnVuY3Rpb24gKHBhcmFtcywgb3B0aW9ucywgbWFuYWdlcikge1xuICAgICAgICByZXR1cm4gbWFuYWdlci5yZXNldChvcHRpb25zKTtcbiAgICB9XG59O1xuIiwiLyoqXG4qICMjIFdvcmxkIE1hbmFnZXJcbipcbiogQXMgZGlzY3Vzc2VkIHVuZGVyIHRoZSBbV29ybGQgQVBJIEFkYXB0ZXJdKC4uL3dvcmxkLWFwaS1hZGFwdGVyLyksIGEgW3J1bl0oLi4vLi4vLi4vZ2xvc3NhcnkvI3J1bikgaXMgYSBjb2xsZWN0aW9uIG9mIGVuZCB1c2VyIGludGVyYWN0aW9ucyB3aXRoIGEgcHJvamVjdCBhbmQgaXRzIG1vZGVsLiBGb3IgYnVpbGRpbmcgbXVsdGlwbGF5ZXIgc2ltdWxhdGlvbnMgeW91IHR5cGljYWxseSB3YW50IG11bHRpcGxlIGVuZCB1c2VycyB0byBzaGFyZSB0aGUgc2FtZSBzZXQgb2YgaW50ZXJhY3Rpb25zLCBhbmQgd29yayB3aXRoaW4gYSBjb21tb24gc3RhdGUuIEVwaWNlbnRlciBhbGxvd3MgeW91IHRvIGNyZWF0ZSBcIndvcmxkc1wiIHRvIGhhbmRsZSBzdWNoIGNhc2VzLlxuKlxuKiBUaGUgV29ybGQgTWFuYWdlciBwcm92aWRlcyBhbiBlYXN5IHdheSB0byB0cmFjayBhbmQgYWNjZXNzIHRoZSBjdXJyZW50IHdvcmxkIGFuZCBydW4gZm9yIHBhcnRpY3VsYXIgZW5kIHVzZXJzLiBJdCBpcyB0eXBpY2FsbHkgdXNlZCBpbiBwYWdlcyB0aGF0IGVuZCB1c2VycyB3aWxsIGludGVyYWN0IHdpdGguIChUaGUgcmVsYXRlZCBbV29ybGQgQVBJIEFkYXB0ZXJdKC4uL3dvcmxkLWFwaS1hZGFwdGVyLykgaGFuZGxlcyBjcmVhdGluZyBtdWx0aXBsYXllciB3b3JsZHMsIGFuZCBhZGRpbmcgYW5kIHJlbW92aW5nIGVuZCB1c2VycyBhbmQgcnVucyBmcm9tIGEgd29ybGQuIEJlY2F1c2Ugb2YgdGhpcywgdHlwaWNhbGx5IHRoZSBXb3JsZCBBZGFwdGVyIGlzIHVzZWQgZm9yIGZhY2lsaXRhdG9yIHBhZ2VzIGluIHlvdXIgcHJvamVjdC4pXG4qXG4qICMjIyBVc2luZyB0aGUgV29ybGQgTWFuYWdlclxuKlxuKiBUbyB1c2UgdGhlIFdvcmxkIE1hbmFnZXIsIGluc3RhbnRpYXRlIGl0LiBUaGVuLCBtYWtlIGNhbGxzIHRvIGFueSBvZiB0aGUgbWV0aG9kcyB5b3UgbmVlZC5cbipcbiogV2hlbiB5b3UgaW5zdGFudGlhdGUgYSBXb3JsZCBNYW5hZ2VyLCB0aGUgd29ybGQncyBhY2NvdW50IGlkLCBwcm9qZWN0IGlkLCBhbmQgZ3JvdXAgYXJlIGF1dG9tYXRpY2FsbHkgdGFrZW4gZnJvbSB0aGUgc2Vzc2lvbiAodGhhbmtzIHRvIHRoZSBbQXV0aGVudGljYXRpb24gU2VydmljZV0oLi4vYXV0aC1hcGktc2VydmljZSkpLlxuKlxuKiBOb3RlIHRoYXQgdGhlIFdvcmxkIE1hbmFnZXIgZG9lcyAqbm90KiBjcmVhdGUgd29ybGRzIGF1dG9tYXRpY2FsbHkuIChUaGlzIGlzIGRpZmZlcmVudCB0aGFuIHRoZSBbUnVuIE1hbmFnZXJdKC4uL3J1bi1tYW5hZ2VyKS4pIEhvd2V2ZXIsIHlvdSBjYW4gcGFzcyBpbiBzcGVjaWZpYyBvcHRpb25zIHRvIGFueSBydW5zIGNyZWF0ZWQgYnkgdGhlIG1hbmFnZXIsIHVzaW5nIGEgYHJ1bmAgb2JqZWN0LlxuKlxuKiBUaGUgcGFyYW1ldGVycyBmb3IgY3JlYXRpbmcgYSBXb3JsZCBNYW5hZ2VyIGFyZTpcbipcbiogICAqIGBhY2NvdW50YDogVGhlICoqVGVhbSBJRCoqIGluIHRoZSBFcGljZW50ZXIgdXNlciBpbnRlcmZhY2UgZm9yIHRoaXMgcHJvamVjdC5cbiogICAqIGBwcm9qZWN0YDogVGhlICoqUHJvamVjdCBJRCoqIGZvciB0aGlzIHByb2plY3QuXG4qICAgKiBgZ3JvdXBgOiBUaGUgKipHcm91cCBOYW1lKiogZm9yIHRoaXMgd29ybGQuXG4qICAgKiBgcnVuYDogT3B0aW9ucyB0byB1c2Ugd2hlbiBjcmVhdGluZyBuZXcgcnVucyB3aXRoIHRoZSBtYW5hZ2VyLCBlLmcuIGBydW46IHsgZmlsZXM6IFsnZGF0YS54bHMnXSB9YC5cbiogICAqIGBydW4ubW9kZWxgOiBUaGUgbmFtZSBvZiB0aGUgcHJpbWFyeSBtb2RlbCBmaWxlIGZvciB0aGlzIHByb2plY3QuIFJlcXVpcmVkIGlmIHlvdSBoYXZlIG5vdCBhbHJlYWR5IHBhc3NlZCBpdCBpbiBhcyBwYXJ0IG9mIHRoZSBgb3B0aW9uc2AgcGFyYW1ldGVyIGZvciBhbiBlbmNsb3NpbmcgY2FsbC5cbipcbiogRm9yIGV4YW1wbGU6XG4qXG4qICAgICAgIHZhciB3TWdyID0gbmV3IEYubWFuYWdlci5Xb3JsZE1hbmFnZXIoe1xuKiAgICAgICAgICBhY2NvdW50OiAnYWNtZS1zaW11bGF0aW9ucycsXG4qICAgICAgICAgIHByb2plY3Q6ICdzdXBwbHktY2hhaW4tZ2FtZScsXG4qICAgICAgICAgIHJ1bjogeyBtb2RlbDogJ3N1cHBseS1jaGFpbi5weScgfSxcbiogICAgICAgICAgZ3JvdXA6ICd0ZWFtMSdcbiogICAgICAgfSk7XG4qXG4qICAgICAgIHdNZ3IuZ2V0Q3VycmVudFJ1bigpO1xuKi9cblxuJ3VzZSBzdHJpY3QnO1xuXG52YXIgV29ybGRBcGkgPSByZXF1aXJlKCcuLi9zZXJ2aWNlL3dvcmxkLWFwaS1hZGFwdGVyJyk7XG52YXIgUnVuTWFuYWdlciA9ICByZXF1aXJlKCcuL3J1bi1tYW5hZ2VyJyk7XG52YXIgQXV0aE1hbmFnZXIgPSByZXF1aXJlKCcuL2F1dGgtbWFuYWdlcicpO1xudmFyIHdvcmxkQXBpO1xuXG4vLyB2YXIgZGVmYXVsdHMgPSB7XG4vLyAgYWNjb3VudDogJycsXG4vLyAgcHJvamVjdDogJycsXG4vLyAgZ3JvdXA6ICcnLFxuLy8gIHRyYW5zcG9ydDoge1xuLy8gIH1cbi8vIH07XG5cblxuZnVuY3Rpb24gYnVpbGRTdHJhdGVneSh3b3JsZElkLCBkdGQpIHtcblxuICAgIHJldHVybiBmdW5jdGlvbiBDdG9yKHJ1blNlcnZpY2UsIG9wdGlvbnMpIHtcbiAgICAgICAgdGhpcy5ydW5TZXJ2aWNlID0gcnVuU2VydmljZTtcbiAgICAgICAgdGhpcy5vcHRpb25zID0gb3B0aW9ucztcblxuICAgICAgICAkLmV4dGVuZCh0aGlzLCB7XG4gICAgICAgICAgICByZXNldDogZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcignbm90IGltcGxlbWVudGQuIE5lZWQgYXBpIGNoYW5nZXMnKTtcbiAgICAgICAgICAgIH0sXG5cbiAgICAgICAgICAgIGdldFJ1bjogZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgICAgIHZhciBfdGhpcyA9IHRoaXM7XG4gICAgICAgICAgICAgICAgLy9nZXQgb3IgY3JlYXRlIVxuICAgICAgICAgICAgICAgIC8vIE1vZGVsIGlzIHJlcXVpcmVkIGluIHRoZSBvcHRpb25zXG4gICAgICAgICAgICAgICAgdmFyIG1vZGVsID0gdGhpcy5vcHRpb25zLnJ1bi5tb2RlbCB8fCB0aGlzLm9wdGlvbnMubW9kZWw7XG4gICAgICAgICAgICAgICAgcmV0dXJuIHdvcmxkQXBpLmdldEN1cnJlbnRSdW5JZCh7IG1vZGVsOiBtb2RlbCwgZmlsdGVyOiB3b3JsZElkIH0pXG4gICAgICAgICAgICAgICAgICAgIC50aGVuKGZ1bmN0aW9uIChydW5JZCkge1xuICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIF90aGlzLnJ1blNlcnZpY2UubG9hZChydW5JZCk7XG4gICAgICAgICAgICAgICAgICAgIH0pXG4gICAgICAgICAgICAgICAgICAgIC50aGVuKGZ1bmN0aW9uIChydW4pIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGR0ZC5yZXNvbHZlLmNhbGwodGhpcywgcnVuLCBfdGhpcy5ydW5TZXJ2aWNlKTtcbiAgICAgICAgICAgICAgICAgICAgfSlcbiAgICAgICAgICAgICAgICAgICAgLmZhaWwoZHRkLnJlamVjdCk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICApO1xuICAgIH07XG59XG5cblxubW9kdWxlLmV4cG9ydHMgPSBmdW5jdGlvbiAob3B0aW9ucykge1xuICAgIHRoaXMub3B0aW9ucyA9IG9wdGlvbnMgfHwgeyBydW46IHt9LCB3b3JsZDoge30gfTtcblxuICAgICQuZXh0ZW5kKHRydWUsIHRoaXMub3B0aW9ucywgdGhpcy5vcHRpb25zLnJ1bik7XG4gICAgJC5leHRlbmQodHJ1ZSwgdGhpcy5vcHRpb25zLCB0aGlzLm9wdGlvbnMud29ybGQpO1xuXG4gICAgd29ybGRBcGkgPSBuZXcgV29ybGRBcGkodGhpcy5vcHRpb25zKTtcbiAgICB0aGlzLl9hdXRoID0gbmV3IEF1dGhNYW5hZ2VyKCk7XG4gICAgdmFyIF90aGlzID0gdGhpcztcblxuICAgIHZhciBhcGkgPSB7XG5cbiAgICAgICAgLyoqXG4gICAgICAgICogUmV0dXJucyB0aGUgY3VycmVudCB3b3JsZCAob2JqZWN0KSBhbmQgYW4gaW5zdGFuY2Ugb2YgdGhlIFtXb3JsZCBBUEkgQWRhcHRlcl0oLi4vd29ybGQtYXBpLWFkYXB0ZXIvKS5cbiAgICAgICAgKlxuICAgICAgICAqICoqRXhhbXBsZSoqXG4gICAgICAgICpcbiAgICAgICAgKiAgICAgICB3TWdyLmdldEN1cnJlbnRXb3JsZCgpXG4gICAgICAgICogICAgICAgICAgIC50aGVuKGZ1bmN0aW9uKHdvcmxkLCB3b3JsZEFkYXB0ZXIpIHtcbiAgICAgICAgKiAgICAgICAgICAgICAgIGNvbnNvbGUubG9nKHdvcmxkLmlkKTtcbiAgICAgICAgKiAgICAgICAgICAgICAgIHdvcmxkQWRhcHRlci5nZXRDdXJyZW50UnVuSWQoKTtcbiAgICAgICAgKiAgICAgICAgICAgfSk7XG4gICAgICAgICpcbiAgICAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAqIEBwYXJhbSB7c3RyaW5nfSBgdXNlcklkYCAoT3B0aW9uYWwpIFRoZSBpZCBvZiB0aGUgdXNlciB3aG9zZSB3b3JsZCBpcyBiZWluZyBhY2Nlc3NlZC4gRGVmYXVsdHMgdG8gdGhlIHVzZXIgaW4gdGhlIGN1cnJlbnQgc2Vzc2lvbi5cbiAgICAgICAgKiBAcGFyYW0ge3N0cmluZ30gYGdyb3VwTmFtZWAgKE9wdGlvbmFsKSBUaGUgbmFtZSBvZiB0aGUgZ3JvdXAgd2hvc2Ugd29ybGQgaXMgYmVpbmcgYWNjZXNzZWQuIERlZmF1bHRzIHRvIHRoZSBncm91cCBmb3IgdGhlIHVzZXIgaW4gdGhlIGN1cnJlbnQgc2Vzc2lvbi5cbiAgICAgICAgKi9cbiAgICAgICAgZ2V0Q3VycmVudFdvcmxkOiBmdW5jdGlvbiAodXNlcklkLCBncm91cE5hbWUpIHtcbiAgICAgICAgICAgIHZhciBzZXNzaW9uID0gdGhpcy5fYXV0aC5nZXRDdXJyZW50VXNlclNlc3Npb25JbmZvKCk7XG4gICAgICAgICAgICBpZiAoIXVzZXJJZCkge1xuICAgICAgICAgICAgICAgIHVzZXJJZCA9IHNlc3Npb24udXNlcklkO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgaWYgKCFncm91cE5hbWUpIHtcbiAgICAgICAgICAgICAgICBncm91cE5hbWUgPSBzZXNzaW9uLmdyb3VwTmFtZTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHJldHVybiB3b3JsZEFwaS5nZXRDdXJyZW50V29ybGRGb3JVc2VyKHVzZXJJZCwgZ3JvdXBOYW1lKTtcbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgKiBSZXR1cm5zIHRoZSBjdXJyZW50IHJ1biAob2JqZWN0KSBhbmQgYW4gaW5zdGFuY2Ugb2YgdGhlIFtSdW4gQVBJIFNlcnZpY2VdKC4uL3J1bi1hcGktc2VydmljZS8pLlxuICAgICAgICAqXG4gICAgICAgICogKipFeGFtcGxlKipcbiAgICAgICAgKlxuICAgICAgICAqICAgICAgIHdNZ3IuZ2V0Q3VycmVudFJ1bih7bW9kZWw6ICdteU1vZGVsLnB5J30pXG4gICAgICAgICogICAgICAgICAgIC50aGVuKGZ1bmN0aW9uKHJ1biwgcnVuU2VydmljZSkge1xuICAgICAgICAqICAgICAgICAgICAgICAgY29uc29sZS5sb2cocnVuLmlkKTtcbiAgICAgICAgKiAgICAgICAgICAgICAgIHJ1blNlcnZpY2UuZG8oJ3N0YXJ0R2FtZScpO1xuICAgICAgICAqICAgICAgICAgICB9KTtcbiAgICAgICAgKlxuICAgICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICAgICogQHBhcmFtIHtzdHJpbmd9IGBtb2RlbGAgKE9wdGlvbmFsKSBUaGUgbmFtZSBvZiB0aGUgbW9kZWwgZmlsZS4gUmVxdWlyZWQgaWYgbm90IGFscmVhZHkgcGFzc2VkIGluIGFzIGBydW4ubW9kZWxgIHdoZW4gdGhlIFdvcmxkIE1hbmFnZXIgaXMgY3JlYXRlZC5cbiAgICAgICAgKi9cbiAgICAgICAgZ2V0Q3VycmVudFJ1bjogZnVuY3Rpb24gKG1vZGVsKSB7XG4gICAgICAgICAgICB2YXIgZHRkID0gJC5EZWZlcnJlZCgpO1xuICAgICAgICAgICAgdmFyIHNlc3Npb24gPSB0aGlzLl9hdXRoLmdldEN1cnJlbnRVc2VyU2Vzc2lvbkluZm8oKTtcbiAgICAgICAgICAgIHZhciBjdXJVc2VySWQgPSBzZXNzaW9uLnVzZXJJZDtcbiAgICAgICAgICAgIHZhciBjdXJHcm91cE5hbWUgPSBzZXNzaW9uLmdyb3VwTmFtZTtcblxuICAgICAgICAgICAgZnVuY3Rpb24gZ2V0QW5kUmVzdG9yZUxhdGVzdFJ1bih3b3JsZCkge1xuICAgICAgICAgICAgICAgIGlmICghd29ybGQpIHtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIGR0ZC5yZWplY3QoeyBlcnJvcjogJ1RoZSB1c2VyIGlzIG5vdCBwYXJ0IG9mIGFueSB3b3JsZCEnIH0pO1xuICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgIHZhciBjdXJyZW50V29ybGRJZCA9IHdvcmxkLmlkO1xuICAgICAgICAgICAgICAgIHZhciBydW5PcHRzID0gJC5leHRlbmQodHJ1ZSwgX3RoaXMub3B0aW9ucywgeyBtb2RlbDogbW9kZWwgfSk7XG4gICAgICAgICAgICAgICAgdmFyIHN0cmF0ZWd5ID0gYnVpbGRTdHJhdGVneShjdXJyZW50V29ybGRJZCwgZHRkKTtcbiAgICAgICAgICAgICAgICB2YXIgb3B0ID0gJC5leHRlbmQodHJ1ZSwge30sIHtcbiAgICAgICAgICAgICAgICAgICAgc3RyYXRlZ3k6IHN0cmF0ZWd5LFxuICAgICAgICAgICAgICAgICAgICBydW46IHJ1bk9wdHNcbiAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgICB2YXIgcm0gPSBuZXcgUnVuTWFuYWdlcihvcHQpO1xuXG4gICAgICAgICAgICAgICAgcmV0dXJuIHJtLmdldFJ1bigpXG4gICAgICAgICAgICAgICAgICAgIC50aGVuKGZ1bmN0aW9uIChydW4pIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGR0ZC5yZXNvbHZlKHJ1biwgcm0ucnVuU2VydmljZSwgcm0pO1xuICAgICAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgdGhpcy5nZXRDdXJyZW50V29ybGQoY3VyVXNlcklkLCBjdXJHcm91cE5hbWUpXG4gICAgICAgICAgICAgICAgLnRoZW4oZ2V0QW5kUmVzdG9yZUxhdGVzdFJ1bik7XG5cbiAgICAgICAgICAgIHJldHVybiBkdGQucHJvbWlzZSgpO1xuICAgICAgICB9XG4gICAgfTtcblxuICAgICQuZXh0ZW5kKHRoaXMsIGFwaSk7XG59O1xuIiwiLyoqXG4gKiAjIyBGaWxlIEFQSSBTZXJ2aWNlXG4gKlxuICogVGhpcyBpcyB1c2VkIHRvIHVwbG9hZC9kb3dubG9hZCBmaWxlcyBkaXJlY3RseSBvbnRvIEVwaWNlbnRlciwgYW5hbG9nb3VzIHRvIHVzaW5nIHRoZSBGaWxlIE1hbmFnZXIgVUkgaW4gRXBpY2VudGVyIGRpcmVjdGx5IG9yIFNGVFBpbmcgZmlsZXMgaW4uIFRoZSBBc3NldCBBUEkgaXMgdHlwaWNhbGx5IHVzZWQgZm9yIGFsbCBwcm9qZWN0IHVzZS1jYXNlcywgYW5kIGl0J3MgdW5saWtlbHkgdGhpcyBGaWxlIFNlcnZpY2Ugd2lsbCBiZSB1c2VkIGRpcmVjdGx5IGV4Y2VwdCBieSBBZG1pbiB0b29scyAoZS5nLiBGbG93IEluc3BlY3RvcikuXG4gKlxuICogUGFydGlhbGx5IGltcGxlbWVudGVkLlxuICovXG5cbid1c2Ugc3RyaWN0JztcblxudmFyIENvbmZpZ1NlcnZpY2UgPSByZXF1aXJlKCcuL2NvbmZpZ3VyYXRpb24tc2VydmljZScpO1xudmFyIFRyYW5zcG9ydEZhY3RvcnkgPSByZXF1aXJlKCcuLi90cmFuc3BvcnQvaHR0cC10cmFuc3BvcnQtZmFjdG9yeScpO1xudmFyIFNlc3Npb25NYW5hZ2VyID0gcmVxdWlyZSgnLi4vc3RvcmUvc2Vzc2lvbi1tYW5hZ2VyJyk7XG5cbm1vZHVsZS5leHBvcnRzID0gZnVuY3Rpb24gKGNvbmZpZykge1xuICAgIHZhciBkZWZhdWx0cyA9IHtcbiAgICAgICAgLyoqXG4gICAgICAgICAqIEZvciBwcm9qZWN0cyB0aGF0IHJlcXVpcmUgYXV0aGVudGljYXRpb24sIHBhc3MgaW4gdGhlIHVzZXIgYWNjZXNzIHRva2VuIChkZWZhdWx0cyB0byBlbXB0eSBzdHJpbmcpLiBJZiB0aGUgdXNlciBpcyBhbHJlYWR5IGxvZ2dlZCBpbiB0byBFcGljZW50ZXIsIHRoZSB1c2VyIGFjY2VzcyB0b2tlbiBpcyBhbHJlYWR5IHNldCBpbiBhIGNvb2tpZSBhbmQgYXV0b21hdGljYWxseSBsb2FkZWQgZnJvbSB0aGVyZS4gKFNlZSBbbW9yZSBiYWNrZ3JvdW5kIG9uIGFjY2VzcyB0b2tlbnNdKC4uLy4uLy4uL3Byb2plY3RfYWNjZXNzLykpLlxuICAgICAgICAgKiBAc2VlIFtBdXRoZW50aWNhdGlvbiBBUEkgU2VydmljZV0oLi4vYXV0aC1hcGktc2VydmljZS8pIGZvciBnZXR0aW5nIHRva2Vucy5cbiAgICAgICAgICogQHR5cGUge1N0cmluZ31cbiAgICAgICAgICovXG4gICAgICAgIHRva2VuOiB1bmRlZmluZWQsXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIFRoZSBhY2NvdW50IGlkLiBJbiB0aGUgRXBpY2VudGVyIFVJLCB0aGlzIGlzIHRoZSAqKlRlYW0gSUQqKiAoZm9yIHRlYW0gcHJvamVjdHMpIG9yICoqVXNlciBJRCoqIChmb3IgcGVyc29uYWwgcHJvamVjdHMpLiBEZWZhdWx0cyB0byBlbXB0eSBzdHJpbmcuXG4gICAgICAgICAqIEB0eXBlIHtTdHJpbmd9XG4gICAgICAgICAqL1xuICAgICAgICBhY2NvdW50OiB1bmRlZmluZWQsXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIFRoZSBwcm9qZWN0IGlkLiBEZWZhdWx0cyB0byBlbXB0eSBzdHJpbmcuXG4gICAgICAgICAqIEB0eXBlIHtTdHJpbmd9XG4gICAgICAgICAqL1xuICAgICAgICBwcm9qZWN0OiB1bmRlZmluZWQsXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIFRoZSBmb2xkZXIgdHlwZS4gIE9uZSBvZiBNb2RlbHxTdGF0aWN8Tm9kZVxuICAgICAgICAgKiBAdHlwZSB7U3RyaW5nfVxuICAgICAgICAgKi9cbiAgICAgICAgZm9sZGVyVHlwZTogJ3N0YXRpYycsXG5cblxuICAgICAgICAvKipcbiAgICAgICAgICogT3B0aW9ucyB0byBwYXNzIG9uIHRvIHRoZSB1bmRlcmx5aW5nIHRyYW5zcG9ydCBsYXllci4gQWxsIGpxdWVyeS5hamF4IG9wdGlvbnMgYXQgaHR0cDovL2FwaS5qcXVlcnkuY29tL2pRdWVyeS5hamF4LyBhcmUgYXZhaWxhYmxlLiBEZWZhdWx0cyB0byBlbXB0eSBvYmplY3QuXG4gICAgICAgICAqIEB0eXBlIHtPYmplY3R9XG4gICAgICAgICAqL1xuICAgICAgICB0cmFuc3BvcnQ6IHt9XG4gICAgfTtcblxuICAgIHRoaXMuc2Vzc2lvbk1hbmFnZXIgPSBuZXcgU2Vzc2lvbk1hbmFnZXIoKTtcbiAgICB2YXIgc2VydmljZU9wdGlvbnMgPSB0aGlzLnNlc3Npb25NYW5hZ2VyLmdldE1lcmdlZE9wdGlvbnMoZGVmYXVsdHMsIGNvbmZpZyk7XG4gICAgdmFyIHVybENvbmZpZyA9IG5ldyBDb25maWdTZXJ2aWNlKHNlcnZpY2VPcHRpb25zKS5nZXQoJ3NlcnZlcicpO1xuICAgIGlmIChzZXJ2aWNlT3B0aW9ucy5hY2NvdW50KSB7XG4gICAgICAgIHVybENvbmZpZy5hY2NvdW50UGF0aCA9IHNlcnZpY2VPcHRpb25zLmFjY291bnQ7XG4gICAgfVxuICAgIGlmIChzZXJ2aWNlT3B0aW9ucy5wcm9qZWN0KSB7XG4gICAgICAgIHVybENvbmZpZy5wcm9qZWN0UGF0aCA9IHNlcnZpY2VPcHRpb25zLnByb2plY3Q7XG4gICAgfVxuXG4gICAgdmFyIGh0dHBPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sIHNlcnZpY2VPcHRpb25zLnRyYW5zcG9ydCwge1xuICAgICAgICB1cmw6IHVybENvbmZpZy5nZXRBUElQYXRoKCdmaWxlJylcbiAgICB9KTtcblxuICAgIGlmIChzZXJ2aWNlT3B0aW9ucy50b2tlbikge1xuICAgICAgICBodHRwT3B0aW9ucy5oZWFkZXJzID0ge1xuICAgICAgICAgICAgJ0F1dGhvcml6YXRpb24nOiAnQmVhcmVyICcgKyBzZXJ2aWNlT3B0aW9ucy50b2tlblxuICAgICAgICB9O1xuICAgIH1cbiAgICB2YXIgaHR0cCA9IG5ldyBUcmFuc3BvcnRGYWN0b3J5KGh0dHBPcHRpb25zKTtcblxuICAgIHZhciBwdWJsaWNBc3luY0FQSSA9IHtcbiAgICAgICAgLyoqXG4gICAgICAgICAqIEdldCBhIGRpcmVjdG9yeSBsaXN0aW5nLCBvciBjb250ZW50cyBvZiBhIGZpbGVcbiAgICAgICAgICogQHBhcmFtICB7U3RyaW5nfSBgZmlsZVBhdGhgICAgUGF0aCB0byB0aGUgZmlsZVxuICAgICAgICAgKiBAcGFyYW0gIHtPYmplY3R9IGBvcHRpb25zYCAoT3B0aW9uYWwpIE92ZXJyaWRlcyBmb3IgY29uZmlndXJhdGlvbiBvcHRpb25zLlxuICAgICAgICAgKi9cbiAgICAgICAgZ2V0Q29udGVudHM6IGZ1bmN0aW9uIChmaWxlUGF0aCwgb3B0aW9ucykge1xuICAgICAgICAgICAgdmFyIHBhdGggPSBzZXJ2aWNlT3B0aW9ucy5mb2xkZXJUeXBlICsgJy8nICsgZmlsZVBhdGg7XG4gICAgICAgICAgICB2YXIgaHR0cE9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSwgc2VydmljZU9wdGlvbnMsIG9wdGlvbnMsIHtcbiAgICAgICAgICAgICAgICB1cmw6IHVybENvbmZpZy5nZXRBUElQYXRoKCdmaWxlJykgKyBwYXRoXG4gICAgICAgICAgICB9KTtcbiAgICAgICAgICAgIHJldHVybiBodHRwLmdldCgnJywgaHR0cE9wdGlvbnMpO1xuICAgICAgICB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBXcml0ZXMgdG8gdGhlIGdpdmVuIGZpbGUgcGF0aDsgcmVwbGFjZXMgdGhlIGV4aXN0aW5nIGZpbGUgaWYgaXQgZXhpc3RzXG4gICAgICAgICAqIEBwYXJhbSAge1N0cmluZ30gYGZpbGVQYXRoYCBQYXRoIHRvIHRoZSBmaWxlXG4gICAgICAgICAqIEBwYXJhbSAge1N0cmluZ30gYGNvbnRlbnRzYCBDb250ZW50cyB0byB3cml0ZSB0byBmaWxlXG4gICAgICAgICAqIEBwYXJhbSAge09iamVjdH0gYG9wdGlvbnNgICAoT3B0aW9uYWwpIE92ZXJyaWRlcyBmb3IgY29uZmlndXJhdGlvbiBvcHRpb25zXG4gICAgICAgICAqL1xuICAgICAgICB3cml0ZVRvRmlsZTogZnVuY3Rpb24gKGZpbGVQYXRoLCBjb250ZW50cywgb3B0aW9ucykge1xuICAgICAgICAgICAgZmlsZVBhdGggPSBmaWxlUGF0aC5zcGxpdCgnLycpO1xuICAgICAgICAgICAgdmFyIGZpbGVOYW1lID0gZmlsZVBhdGgucG9wKCk7XG4gICAgICAgICAgICBmaWxlUGF0aCA9IGZpbGVQYXRoLmpvaW4oJy8nKTtcbiAgICAgICAgICAgIHZhciBwYXRoID0gc2VydmljZU9wdGlvbnMuZm9sZGVyVHlwZSArICcvJyArIGZpbGVQYXRoO1xuICAgICAgICAgICAgdmFyIGJvdW5kYXJ5ID0gJy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLTdkYTI0ZjJlNTAwNDYnO1xuXG4gICAgICAgICAgICB2YXIgYm9keSA9ICctLScgKyBib3VuZGFyeSArICdcXHJcXG4nICtcbiAgICAgICAgICAgICAgICAnQ29udGVudC1EaXNwb3NpdGlvbjogZm9ybS1kYXRhOyBuYW1lPVwiZmlsZVwiOycgK1xuICAgICAgICAgICAgICAgICdmaWxlbmFtZT1cIicgKyBmaWxlTmFtZSArICdcIlxcclxcbicgK1xuICAgICAgICAgICAgICAgICdDb250ZW50LXR5cGU6IHRleHQvaHRtbFxcclxcblxcclxcbicgK1xuICAgICAgICAgICAgICAgIGNvbnRlbnRzICsgJ1xcclxcbicgK1xuICAgICAgICAgICAgICAgICctLScgKyBib3VuZGFyeSArICctLSc7XG5cbiAgICAgICAgICAgIHZhciBodHRwT3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LCBzZXJ2aWNlT3B0aW9ucywgb3B0aW9ucywge1xuICAgICAgICAgICAgICAgIHVybDogdXJsQ29uZmlnLmdldEFQSVBhdGgoJ2ZpbGUnKSArIHBhdGgsXG4gICAgICAgICAgICAgICAgZGF0YTogYm9keSxcbiAgICAgICAgICAgICAgICBjb250ZW50VHlwZTogJ211bHRpcGFydC9mb3JtLWRhdGE7IGJvdW5kYXJ5PScgKyBib3VuZGFyeVxuICAgICAgICAgICAgfSk7XG5cbiAgICAgICAgICAgIHJldHVybiBodHRwLnB1dChib2R5LCBodHRwT3B0aW9ucyk7XG4gICAgICAgIH0sXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIFJlbW92ZXMgdGhlIGZpbGVcbiAgICAgICAgICogQHBhcmFtICB7U3RyaW5nfSBgZmlsZVBhdGhgIFBhdGggdG8gdGhlIGZpbGVcbiAgICAgICAgICogQHBhcmFtICB7T2JqZWN0fSBgb3B0aW9uc2AgIChPcHRpb25hbCkgT3ZlcnJpZGVzIGZvciBjb25maWd1cmF0aW9uIG9wdGlvbnNcbiAgICAgICAgICovXG4gICAgICAgIHJlbW92ZTogZnVuY3Rpb24gKGZpbGVQYXRoLCBvcHRpb25zKSB7XG4gICAgICAgICAgICB2YXIgcGF0aCA9IHNlcnZpY2VPcHRpb25zLmZvbGRlclR5cGUgKyAnLycgKyBmaWxlUGF0aDtcbiAgICAgICAgICAgIHZhciBodHRwT3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LCBzZXJ2aWNlT3B0aW9ucywgb3B0aW9ucywge1xuICAgICAgICAgICAgICAgIHVybDogdXJsQ29uZmlnLmdldEFQSVBhdGgoJ2ZpbGUnKSArIHBhdGhcbiAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgcmV0dXJuIGh0dHAuZGVsZXRlKG51bGwsIGh0dHBPcHRpb25zKTtcbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgICogUmVuYW1lIHRoZSBmaWxlXG4gICAgICAgICAqIEBwYXJhbSAge1N0cmluZ30gZmlsZVBhdGggUGF0aCB0byB0aGUgZmlsZVxuICAgICAgICAgKiBAcGFyYW0gIHtTdGlybmd9IG5ld05hbWUgIE5ldyBuYW1lIG9mIGZpbGVcbiAgICAgICAgICogQHBhcmFtICB7T2JqZWN0fSBvcHRpb25zICAoT3B0aW9uYWwpIE92ZXJyaWRlcyBmb3IgY29uZmlndXJhdGlvbiBvcHRpb25zXG4gICAgICAgICAqL1xuICAgICAgICByZW5hbWU6IGZ1bmN0aW9uIChmaWxlUGF0aCwgbmV3TmFtZSwgb3B0aW9ucykge1xuICAgICAgICAgICAgdmFyIHBhdGggPSBzZXJ2aWNlT3B0aW9ucy5mb2xkZXJUeXBlICsgJy8nICsgZmlsZVBhdGg7XG4gICAgICAgICAgICB2YXIgaHR0cE9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSwgc2VydmljZU9wdGlvbnMsIG9wdGlvbnMsIHtcbiAgICAgICAgICAgICAgICB1cmw6IHVybENvbmZpZy5nZXRBUElQYXRoKCdmaWxlJykgKyBwYXRoXG4gICAgICAgICAgICB9KTtcbiAgICAgICAgICAgIHJldHVybiBodHRwLnBhdGNoKHsgJ25hbWUnOiBuZXdOYW1lIH0sIGh0dHBPcHRpb25zKTtcbiAgICAgICAgfVxuICAgIH07XG5cbiAgICAkLmV4dGVuZCh0aGlzLCBwdWJsaWNBc3luY0FQSSk7XG59O1xuIiwiLyoqXG4gKiAjIyBBc3NldCBBUEkgQWRhcHRlclxuICpcbiAqIFRoZSBBc3NldCBBUEkgQWRhcHRlciBhbGxvd3MgeW91IHRvIHN0b3JlIGFzc2V0cyAtLSByZXNvdXJjZXMgb3IgZmlsZXMgb2YgYW55IGtpbmQgLS0gdXNlZCBieSBhIHByb2plY3Qgd2l0aCBhIHNjb3BlIHRoYXQgaXMgc3BlY2lmaWMgdG8gcHJvamVjdCwgZ3JvdXAsIG9yIGVuZCB1c2VyLlxuICpcbiAqIEFzc2V0cyBhcmUgdXNlZCB3aXRoIFt0ZWFtIHByb2plY3RzXSguLi8uLi8uLi9wcm9qZWN0X2FkbWluLyN0ZWFtKS4gT25lIGNvbW1vbiB1c2UgY2FzZSBpcyBoYXZpbmcgZW5kIHVzZXJzIGluIGEgW2dyb3VwXSguLi8uLi8uLi9nbG9zc2FyeS8jZ3JvdXBzKSBvciBpbiBhIFttdWx0aXBsYXllciB3b3JsZF0oLi4vLi4vLi4vZ2xvc3NhcnkvI3dvcmxkKSB1cGxvYWQgZGF0YSAtLSB2aWRlb3MgY3JlYXRlZCBkdXJpbmcgZ2FtZSBwbGF5LCBwcm9maWxlIHBpY3R1cmVzIGZvciBjdXN0b21pemluZyB0aGVpciBleHBlcmllbmNlLCBldGMuIC0tIGFzIHBhcnQgb2YgcGxheWluZyB0aHJvdWdoIHRoZSBwcm9qZWN0LlxuICpcbiAqIFJlc291cmNlcyBjcmVhdGVkIHVzaW5nIHRoZSBBc3NldCBBZGFwdGVyIGFyZSBzY29wZWQ6XG4gKlxuICogICogUHJvamVjdCBhc3NldHMgYXJlIHdyaXRhYmxlIG9ubHkgYnkgW3RlYW0gbWVtYmVyc10oLi4vLi4vLi4vZ2xvc3NhcnkvI3RlYW0pLCB0aGF0IGlzLCBFcGljZW50ZXIgYXV0aG9ycy5cbiAqICAqIEdyb3VwIGFzc2V0cyBhcmUgd3JpdGFibGUgYnkgYW55b25lIHdpdGggYWNjZXNzIHRvIHRoZSBwcm9qZWN0IHRoYXQgaXMgcGFydCBvZiB0aGF0IHBhcnRpY3VsYXIgW2dyb3VwXSguLi8uLi8uLi9nbG9zc2FyeS8jZ3JvdXBzKS4gVGhpcyBpbmNsdWRlcyBhbGwgW3RlYW0gbWVtYmVyc10oLi4vLi4vLi4vZ2xvc3NhcnkvI3RlYW0pIChFcGljZW50ZXIgYXV0aG9ycykgYW5kIGFueSBbZW5kIHVzZXJzXSguLi8uLi8uLi9nbG9zc2FyeS8jdXNlcnMpIHdobyBhcmUgbWVtYmVycyBvZiB0aGUgZ3JvdXAgLS0gYm90aCBmYWNpbGl0YXRvcnMgYW5kIHN0YW5kYXJkIGVuZCB1c2Vycy5cbiAqICAqIFVzZXIgYXNzZXRzIGFyZSB3cml0YWJsZSBieSB0aGUgc3BlY2lmaWMgZW5kIHVzZXIsIGFuZCBieSB0aGUgZmFjaWxpdGF0b3Igb2YgdGhlIGdyb3VwLlxuICogICogQWxsIGFzc2V0cyBhcmUgcmVhZGFibGUgYnkgYW55b25lIHdpdGggdGhlIGV4YWN0IFVSSS5cbiAqXG4gKiBUbyB1c2UgdGhlIEFzc2V0IEFkYXB0ZXIsIGluc3RhbnRpYXRlIGl0IGFuZCB0aGVuIGFjY2VzcyB0aGUgbWV0aG9kcyBwcm92aWRlZC4gSW5zdGFudGlhdGluZyByZXF1aXJlcyB0aGUgYWNjb3VudCBpZCAoKipUZWFtIElEKiogaW4gdGhlIEVwaWNlbnRlciB1c2VyIGludGVyZmFjZSkgYW5kIHByb2plY3QgaWQgKCoqUHJvamVjdCBJRCoqKS4gVGhlIGdyb3VwIG5hbWUgaXMgcmVxdWlyZWQgZm9yIGFzc2V0cyB3aXRoIGEgZ3JvdXAgc2NvcGUsIGFuZCB0aGUgZ3JvdXAgbmFtZSBhbmQgdXNlcklkIGFyZSByZXF1aXJlZCBmb3IgYXNzZXRzIHdpdGggYSB1c2VyIHNjb3BlLiBJZiBub3QgaW5jbHVkZWQsIHRoZXkgYXJlIHRha2VuIGZyb20gdGhlIGxvZ2dlZCBpbiB1c2VyJ3Mgc2Vzc2lvbiBpbmZvcm1hdGlvbiBpZiBuZWVkZWQuXG4gKlxuICogV2hlbiBjcmVhdGluZyBhbiBhc3NldCwgeW91IGNhbiBwYXNzIGluIHRleHQgKGVuY29kZWQgZGF0YSkgdG8gdGhlIGBjcmVhdGUoKWAgY2FsbC4gQWx0ZXJuYXRpdmVseSwgeW91IGNhbiBtYWtlIHRoZSBgY3JlYXRlKClgIGNhbGwgYXMgcGFydCBvZiBhbiBIVE1MIGZvcm0gYW5kIHBhc3MgaW4gYSBmaWxlIHVwbG9hZGVkIHZpYSB0aGUgZm9ybS5cbiAqXG4gKiAgICAgICAvLyBpbnN0YW50aWF0ZSB0aGUgQXNzZXQgQWRhcHRlclxuICogICAgICAgdmFyIGFhID0gbmV3IEYuc2VydmljZS5Bc3NldCh7XG4gKiAgICAgICAgICBhY2NvdW50OiAnYWNtZS1zaW11bGF0aW9ucycsXG4gKiAgICAgICAgICBwcm9qZWN0OiAnc3VwcGx5LWNoYWluLWdhbWUnLFxuICogICAgICAgICAgZ3JvdXA6ICd0ZWFtMScsXG4gKiAgICAgICAgICB1c2VySWQ6ICcxMjM0NSdcbiAqICAgICAgIH0pO1xuICpcbiAqICAgICAgIC8vIGNyZWF0ZSBhIG5ldyBhc3NldCB1c2luZyBlbmNvZGVkIHRleHRcbiAqICAgICAgIGFhLmNyZWF0ZSgndGVzdC50eHQnLCB7XG4gKiAgICAgICAgICAgZW5jb2Rpbmc6ICdCQVNFXzY0JyxcbiAqICAgICAgICAgICBkYXRhOiAnVkdocGN5QnBjeUJoSUhSbGMzUWdabWxzWlM0PScsXG4gKiAgICAgICAgICAgY29udGVudFR5cGU6ICd0ZXh0L3BsYWluJ1xuICogICAgICAgfSwgeyBzY29wZTogJ3VzZXInIH0pO1xuICpcbiAqICAgICAgIC8vIGFsdGVybmF0aXZlbHksIGNyZWF0ZSBhIG5ldyBhc3NldCB1c2luZyBhIGZpbGUgdXBsb2FkZWQgdGhyb3VnaCBhIGZvcm1cbiAqICAgICAgIC8vIHRoaXMgc2FtcGxlIGNvZGUgZ29lcyB3aXRoIGFuIGh0bWwgZm9ybSB0aGF0IGxvb2tzIGxpa2UgdGhpczpcbiAqICAgICAgIC8vXG4gKiAgICAgICAvLyA8Zm9ybSBpZD1cInVwbG9hZC1maWxlXCI+XG4gKiAgICAgICAvLyAgIDxpbnB1dCBpZD1cImZpbGVcIiB0eXBlPVwiZmlsZVwiPlxuICogICAgICAgLy8gICA8aW5wdXQgaWQ9XCJmaWxlbmFtZVwiIHR5cGU9XCJ0ZXh0XCIgdmFsdWU9XCJteUZpbGUudHh0XCI+XG4gKiAgICAgICAvLyAgIDxidXR0b24gdHlwZT1cInN1Ym1pdFwiPlVwbG9hZCBteUZpbGU8L2J1dHRvbj5cbiAqICAgICAgIC8vIDwvZm9ybT5cbiAqICAgICAgIC8vXG4gKiAgICAgICAkKCcjdXBsb2FkLWZpbGUnKS5vbignc3VibWl0JywgZnVuY3Rpb24gKGUpIHtcbiAqICAgICAgICAgIGUucHJldmVudERlZmF1bHQoKTtcbiAqICAgICAgICAgIHZhciBmaWxlbmFtZSA9ICQoJyNmaWxlbmFtZScpLnZhbCgpO1xuICogICAgICAgICAgdmFyIGRhdGEgPSBuZXcgRm9ybURhdGEoKTtcbiAqICAgICAgICAgIHZhciBpbnB1dENvbnRyb2wgPSAkKCcjZmlsZScpWzBdO1xuICogICAgICAgICAgZGF0YS5hcHBlbmQoJ2ZpbGUnLCBpbnB1dENvbnRyb2wuZmlsZXNbMF0sIGZpbGVuYW1lKTtcbiAqXG4gKiAgICAgICAgICBhYS5jcmVhdGUoZmlsZW5hbWUsIGRhdGEsIHsgc2NvcGU6ICd1c2VyJyB9KTtcbiAqICAgICAgIH0pO1xuICpcbiAqL1xuXG4ndXNlIHN0cmljdCc7XG5cbnZhciBDb25maWdTZXJ2aWNlID0gcmVxdWlyZSgnLi9jb25maWd1cmF0aW9uLXNlcnZpY2UnKTtcbnZhciBUcmFuc3BvcnRGYWN0b3J5ID0gcmVxdWlyZSgnLi4vdHJhbnNwb3J0L2h0dHAtdHJhbnNwb3J0LWZhY3RvcnknKTtcbnZhciBfcGljayA9IHJlcXVpcmUoJy4uL3V0aWwvb2JqZWN0LXV0aWwnKS5fcGljaztcbnZhciBTZXNzaW9uTWFuYWdlciA9IHJlcXVpcmUoJy4uL3N0b3JlL3Nlc3Npb24tbWFuYWdlcicpO1xuXG52YXIgYXBpRW5kcG9pbnQgPSAnYXNzZXQnO1xuXG5tb2R1bGUuZXhwb3J0cyA9IGZ1bmN0aW9uIChjb25maWcpIHtcbiAgICB2YXIgZGVmYXVsdHMgPSB7XG4gICAgICAgIC8qKlxuICAgICAgICAgKiBGb3IgcHJvamVjdHMgdGhhdCByZXF1aXJlIGF1dGhlbnRpY2F0aW9uLCBwYXNzIGluIHRoZSB1c2VyIGFjY2VzcyB0b2tlbiAoZGVmYXVsdHMgdG8gZW1wdHkgc3RyaW5nKS4gSWYgdGhlIHVzZXIgaXMgYWxyZWFkeSBsb2dnZWQgaW4gdG8gRXBpY2VudGVyLCB0aGUgdXNlciBhY2Nlc3MgdG9rZW4gaXMgYWxyZWFkeSBzZXQgaW4gYSBjb29raWUgYW5kIGF1dG9tYXRpY2FsbHkgbG9hZGVkIGZyb20gdGhlcmUuIChTZWUgW21vcmUgYmFja2dyb3VuZCBvbiBhY2Nlc3MgdG9rZW5zXSguLi8uLi8uLi9wcm9qZWN0X2FjY2Vzcy8pKS5cbiAgICAgICAgICogQHNlZSBbQXV0aGVudGljYXRpb24gQVBJIFNlcnZpY2VdKC4uL2F1dGgtYXBpLXNlcnZpY2UvKSBmb3IgZ2V0dGluZyB0b2tlbnMuXG4gICAgICAgICAqIEB0eXBlIHtTdHJpbmd9XG4gICAgICAgICAqL1xuICAgICAgICB0b2tlbjogdW5kZWZpbmVkLFxuICAgICAgICAvKipcbiAgICAgICAgICogVGhlIGFjY291bnQgaWQuIEluIHRoZSBFcGljZW50ZXIgVUksIHRoaXMgaXMgdGhlICoqVGVhbSBJRCoqIChmb3IgdGVhbSBwcm9qZWN0cykuIElmIGxlZnQgdW5kZWZpbmVkLCB0YWtlbiBmcm9tIHRoZSBVUkwuXG4gICAgICAgICAqIEB0eXBlIHtTdHJpbmd9XG4gICAgICAgICAqL1xuICAgICAgICBhY2NvdW50OiB1bmRlZmluZWQsXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBUaGUgcHJvamVjdCBpZC4gSWYgbGVmdCB1bmRlZmluZWQsIHRha2VuIGZyb20gdGhlIFVSTC5cbiAgICAgICAgICogQHR5cGUge1N0cmluZ31cbiAgICAgICAgICovXG4gICAgICAgIHByb2plY3Q6IHVuZGVmaW5lZCxcbiAgICAgICAgLyoqXG4gICAgICAgICAqIFRoZSBncm91cCBuYW1lLiBEZWZhdWx0cyB0byBzZXNzaW9uJ3MgYGdyb3VwTmFtZWAuXG4gICAgICAgICAqIEB0eXBlIHtTdHJpbmd9XG4gICAgICAgICAqL1xuICAgICAgICBncm91cDogdW5kZWZpbmVkLFxuICAgICAgICAvKipcbiAgICAgICAgICogVGhlIHVzZXIgaWQuIERlZmF1bHRzIHRvIHNlc3Npb24ncyBgdXNlcklkYC5cbiAgICAgICAgICogQHR5cGUge1N0cmluZ31cbiAgICAgICAgICovXG4gICAgICAgIHVzZXJJZDogdW5kZWZpbmVkLFxuICAgICAgICAvKipcbiAgICAgICAgICogVGhlIHNjb3BlIGZvciB0aGUgYXNzZXQuIFZhbGlkIHZhbHVlcyBhcmU6IGB1c2VyYCwgYGdyb3VwYCwgYW5kIGBwcm9qZWN0YC4gU2VlIGFib3ZlIGZvciB0aGUgcmVxdWlyZWQgcGVybWlzc2lvbnMgdG8gd3JpdGUgdG8gZWFjaCBzY29wZS4gRGVmYXVsdHMgdG8gYHVzZXJgLCBtZWFuaW5nIHRoZSBjdXJyZW50IGVuZCB1c2VyIG9yIGEgZmFjaWxpdGF0b3IgaW4gdGhlIGVuZCB1c2VyJ3MgZ3JvdXAgY2FuIGVkaXQgdGhlIGFzc2V0LlxuICAgICAgICAgKiBAdHlwZSB7U3RyaW5nfVxuICAgICAgICAgKi9cbiAgICAgICAgc2NvcGU6ICd1c2VyJyxcbiAgICAgICAgLyoqXG4gICAgICAgICAqIERldGVybWluZXMgaWYgYSByZXF1ZXN0IHRvIGxpc3QgdGhlIGFzc2V0cyBpbiBhIHNjb3BlIGluY2x1ZGVzIHRoZSBjb21wbGV0ZSBVUkwgZm9yIGVhY2ggYXNzZXQgKGB0cnVlYCksIG9yIG9ubHkgdGhlIGZpbGUgbmFtZXMgb2YgdGhlIGFzc2V0cyAoYGZhbHNlYCkuIERlZmF1bHRzIHRvIGB0cnVlYC5cbiAgICAgICAgICogQHR5cGUge2Jvb2xlYW59XG4gICAgICAgICAqL1xuICAgICAgICBmdWxsVXJsOiB0cnVlLFxuICAgICAgICAvKipcbiAgICAgICAgICogVGhlIHRyYW5zcG9ydCBvYmplY3QgY29udGFpbnMgdGhlIG9wdGlvbnMgcGFzc2VkIHRvIHRoZSBYSFIgcmVxdWVzdC5cbiAgICAgICAgICogQHR5cGUge29iamVjdH1cbiAgICAgICAgICovXG4gICAgICAgIHRyYW5zcG9ydDoge1xuICAgICAgICAgICAgcHJvY2Vzc0RhdGE6IGZhbHNlXG4gICAgICAgIH1cbiAgICB9O1xuICAgIHRoaXMuc2Vzc2lvbk1hbmFnZXIgPSBuZXcgU2Vzc2lvbk1hbmFnZXIoKTtcbiAgICB2YXIgc2VydmljZU9wdGlvbnMgPSB0aGlzLnNlc3Npb25NYW5hZ2VyLmdldE1lcmdlZE9wdGlvbnMoZGVmYXVsdHMsIGNvbmZpZyk7XG4gICAgdmFyIHVybENvbmZpZyA9IG5ldyBDb25maWdTZXJ2aWNlKHNlcnZpY2VPcHRpb25zKS5nZXQoJ3NlcnZlcicpO1xuXG4gICAgaWYgKCFzZXJ2aWNlT3B0aW9ucy5hY2NvdW50KSB7XG4gICAgICAgIHNlcnZpY2VPcHRpb25zLmFjY291bnQgPSB1cmxDb25maWcuYWNjb3VudFBhdGg7XG4gICAgfVxuXG4gICAgaWYgKCFzZXJ2aWNlT3B0aW9ucy5wcm9qZWN0KSB7XG4gICAgICAgIHNlcnZpY2VPcHRpb25zLnByb2plY3QgPSB1cmxDb25maWcucHJvamVjdFBhdGg7XG4gICAgfVxuXG4gICAgdmFyIHRyYW5zcG9ydE9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSwgc2VydmljZU9wdGlvbnMudHJhbnNwb3J0LCB7XG4gICAgICAgIHVybDogdXJsQ29uZmlnLmdldEFQSVBhdGgoYXBpRW5kcG9pbnQpXG4gICAgfSk7XG5cbiAgICBpZiAoc2VydmljZU9wdGlvbnMudG9rZW4pIHtcbiAgICAgICAgdHJhbnNwb3J0T3B0aW9ucy5oZWFkZXJzID0ge1xuICAgICAgICAgICAgJ0F1dGhvcml6YXRpb24nOiAnQmVhcmVyICcgKyBzZXJ2aWNlT3B0aW9ucy50b2tlblxuICAgICAgICB9O1xuICAgIH1cblxuICAgIHZhciBodHRwID0gbmV3IFRyYW5zcG9ydEZhY3RvcnkodHJhbnNwb3J0T3B0aW9ucyk7XG5cbiAgICB2YXIgYXNzZXRBcGlQYXJhbXMgPSBbJ2VuY29kaW5nJywgJ2RhdGEnLCAnY29udGVudFR5cGUnXTtcbiAgICB2YXIgc2NvcGVDb25maWcgPSB7XG4gICAgICAgIHVzZXI6IFsnc2NvcGUnLCAnYWNjb3VudCcsICdwcm9qZWN0JywgJ2dyb3VwJywgJ3VzZXJJZCddLFxuICAgICAgICBncm91cDogWydzY29wZScsICdhY2NvdW50JywgJ3Byb2plY3QnLCAnZ3JvdXAnXSxcbiAgICAgICAgcHJvamVjdDogWydzY29wZScsICdhY2NvdW50JywgJ3Byb2plY3QnXSxcbiAgICB9O1xuXG4gICAgdmFyIHZhbGlkYXRlRmlsZW5hbWUgPSBmdW5jdGlvbiAoZmlsZW5hbWUpIHtcbiAgICAgICAgaWYgKCFmaWxlbmFtZSkge1xuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdmaWxlbmFtZSBpcyBuZWVkZWQuJyk7XG4gICAgICAgIH1cbiAgICB9O1xuXG4gICAgdmFyIHZhbGlkYXRlVXJsUGFyYW1zID0gZnVuY3Rpb24gKG9wdGlvbnMpIHtcbiAgICAgICAgdmFyIHBhcnRLZXlzID0gc2NvcGVDb25maWdbb3B0aW9ucy5zY29wZV07XG4gICAgICAgIGlmICghcGFydEtleXMpIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcignc2NvcGUgcGFyYW1ldGVyIGlzIG5lZWRlZC4nKTtcbiAgICAgICAgfVxuXG4gICAgICAgICQuZWFjaChwYXJ0S2V5cywgZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgaWYgKCFvcHRpb25zW3RoaXNdKSB7XG4gICAgICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKHRoaXMgKyAnIHBhcmFtZXRlciBpcyBuZWVkZWQuJyk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH0pO1xuICAgIH07XG5cbiAgICB2YXIgYnVpbGRVcmwgPSBmdW5jdGlvbiAoZmlsZW5hbWUsIG9wdGlvbnMpIHtcbiAgICAgICAgdmFsaWRhdGVVcmxQYXJhbXMob3B0aW9ucyk7XG4gICAgICAgIHZhciBwYXJ0S2V5cyA9IHNjb3BlQ29uZmlnW29wdGlvbnMuc2NvcGVdO1xuICAgICAgICB2YXIgcGFydHMgPSAkLm1hcChwYXJ0S2V5cywgZnVuY3Rpb24gKGtleSkge1xuICAgICAgICAgICAgcmV0dXJuIG9wdGlvbnNba2V5XTtcbiAgICAgICAgfSk7XG4gICAgICAgIGlmIChmaWxlbmFtZSkge1xuICAgICAgICAgICAgLy8gVGhpcyBwcmV2ZW50cyBhZGRpbmcgYSB0cmFpbGluZyAvIGluIHRoZSBVUkwgYXMgdGhlIEFzc2V0IEFQSVxuICAgICAgICAgICAgLy8gZG9lcyBub3Qgd29yayBjb3JyZWN0bHkgd2l0aCBpdFxuICAgICAgICAgICAgZmlsZW5hbWUgPSAnLycgKyBmaWxlbmFtZTtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gdXJsQ29uZmlnLmdldEFQSVBhdGgoYXBpRW5kcG9pbnQpICsgcGFydHMuam9pbignLycpICsgZmlsZW5hbWU7XG4gICAgfTtcblxuICAgIC8vIFByaXZhdGUgZnVuY3Rpb24sIGFsbCByZXF1ZXN0cyBmb2xsb3cgYSBtb3JlIG9yIGxlc3Mgc2FtZSBhcHByb2FjaCB0b1xuICAgIC8vIHVzZSB0aGUgQXNzZXQgQVBJIGFuZCB0aGUgZGlmZmVyZW5jZSBpcyB0aGUgSFRUUCB2ZXJiXG4gICAgLy9cbiAgICAvLyBAcGFyYW0ge3N0cmluZ30gYG1ldGhvZGAgKFJlcXVpcmVkKSBIVFRQIHZlcmJcbiAgICAvLyBAcGFyYW0ge3N0cmluZ30gYGZpbGVuYW1lYCAoUmVxdWlyZWQpIE5hbWUgb2YgdGhlIGZpbGUgdG8gZGVsZXRlL3JlcGxhY2UvY3JlYXRlXG4gICAgLy8gQHBhcmFtIHtvYmplY3R9IGBwYXJhbXNgIChPcHRpb25hbCkgQm9keSBwYXJhbWV0ZXJzIHRvIHNlbmQgdG8gdGhlIEFzc2V0IEFQSVxuICAgIC8vIEBwYXJhbSB7b2JqZWN0fSBgb3B0aW9uc2AgKE9wdGlvbmFsKSBPcHRpb25zIG9iamVjdCB0byBvdmVycmlkZSBnbG9iYWwgb3B0aW9ucy5cbiAgICB2YXIgdXBsb2FkID0gZnVuY3Rpb24gKG1ldGhvZCwgZmlsZW5hbWUsIHBhcmFtcywgb3B0aW9ucykge1xuICAgICAgICB2YWxpZGF0ZUZpbGVuYW1lKGZpbGVuYW1lKTtcbiAgICAgICAgLy8gbWFrZSBzdXJlIHRoZSBwYXJhbWV0ZXIgaXMgY2xlYW5cbiAgICAgICAgbWV0aG9kID0gbWV0aG9kLnRvTG93ZXJDYXNlKCk7XG4gICAgICAgIHZhciBjb250ZW50VHlwZSA9IHBhcmFtcyBpbnN0YW5jZW9mIEZvcm1EYXRhID09PSB0cnVlID8gZmFsc2UgOiAnYXBwbGljYXRpb24vanNvbic7XG4gICAgICAgIGlmIChjb250ZW50VHlwZSA9PT0gJ2FwcGxpY2F0aW9uL2pzb24nKSB7XG4gICAgICAgICAgICAvLyB3aGl0ZWxpc3QgdGhlIGZpZWxkcyB0aGF0IHdlIGFjdHVhbGx5IGNhbiBzZW5kIHRvIHRoZSBhcGlcbiAgICAgICAgICAgIHBhcmFtcyA9IF9waWNrKHBhcmFtcywgYXNzZXRBcGlQYXJhbXMpO1xuICAgICAgICB9IGVsc2UgeyAvLyBlbHNlIHdlJ3JlIHNlbmRpbmcgZm9ybSBkYXRhIHdoaWNoIGdvZXMgZGlyZWN0bHkgaW4gcmVxdWVzdCBib2R5XG4gICAgICAgICAgICAvLyBGb3IgbXVsdGlwYXJ0L2Zvcm0tZGF0YSB1cGxvYWRzIHRoZSBmaWxlbmFtZSBpcyBub3Qgc2V0IGluIHRoZSBVUkwsXG4gICAgICAgICAgICAvLyBpdCdzIGdldHRpbmcgcGlja2VkIGJ5IHRoZSBGb3JtRGF0YSBmaWVsZCBmaWxlbmFtZS5cbiAgICAgICAgICAgIGZpbGVuYW1lID0gbWV0aG9kID09PSAncG9zdCcgfHwgbWV0aG9kID09PSAncHV0JyA/ICcnIDogZmlsZW5hbWU7XG4gICAgICAgIH1cbiAgICAgICAgdmFyIHVybE9wdGlvbnMgPSAkLmV4dGVuZCh7fSwgc2VydmljZU9wdGlvbnMsIG9wdGlvbnMpO1xuICAgICAgICB2YXIgdXJsID0gYnVpbGRVcmwoZmlsZW5hbWUsIHVybE9wdGlvbnMpO1xuICAgICAgICB2YXIgY3JlYXRlT3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LCB1cmxPcHRpb25zLCB7IHVybDogdXJsLCBjb250ZW50VHlwZTogY29udGVudFR5cGUgfSk7XG5cbiAgICAgICAgcmV0dXJuIGh0dHBbbWV0aG9kXShwYXJhbXMsIGNyZWF0ZU9wdGlvbnMpO1xuICAgIH07XG5cbiAgICB2YXIgcHVibGljQVBJID0ge1xuICAgICAgICAvKipcbiAgICAgICAgKiBDcmVhdGVzIGEgZmlsZSBpbiB0aGUgQXNzZXQgQVBJLiBUaGUgc2VydmVyIHJldHVybnMgYW4gZXJyb3IgKHN0YXR1cyBjb2RlIGA0MDlgLCBjb25mbGljdCkgaWYgdGhlIGZpbGUgYWxyZWFkeSBleGlzdHMsIHNvXG4gICAgICAgICogY2hlY2sgZmlyc3Qgd2l0aCBhIGBsaXN0KClgIG9yIGEgYGdldCgpYC5cbiAgICAgICAgKlxuICAgICAgICAqICAqKkV4YW1wbGUqKlxuICAgICAgICAqXG4gICAgICAgICogICAgICAgdmFyIGFhID0gbmV3IEYuc2VydmljZS5Bc3NldCh7XG4gICAgICAgICogICAgICAgICAgYWNjb3VudDogJ2FjbWUtc2ltdWxhdGlvbnMnLFxuICAgICAgICAqICAgICAgICAgIHByb2plY3Q6ICdzdXBwbHktY2hhaW4tZ2FtZScsXG4gICAgICAgICogICAgICAgICAgZ3JvdXA6ICd0ZWFtMScsXG4gICAgICAgICogICAgICAgICAgdXNlcklkOiAnJ1xuICAgICAgICAqICAgICAgIH0pO1xuICAgICAgICAqXG4gICAgICAgICogICAgICAgLy8gY3JlYXRlIGEgbmV3IGFzc2V0IHVzaW5nIGVuY29kZWQgdGV4dFxuICAgICAgICAqICAgICAgIGFhLmNyZWF0ZSgndGVzdC50eHQnLCB7XG4gICAgICAgICogICAgICAgICAgIGVuY29kaW5nOiAnQkFTRV82NCcsXG4gICAgICAgICogICAgICAgICAgIGRhdGE6ICdWR2hwY3lCcGN5QmhJSFJsYzNRZ1ptbHNaUzQ9JyxcbiAgICAgICAgKiAgICAgICAgICAgY29udGVudFR5cGU6ICd0ZXh0L3BsYWluJ1xuICAgICAgICAqICAgICAgIH0sIHsgc2NvcGU6ICd1c2VyJyB9KTtcbiAgICAgICAgKlxuICAgICAgICAqICAgICAgIC8vIGFsdGVybmF0aXZlbHksIGNyZWF0ZSBhIG5ldyBhc3NldCB1c2luZyBhIGZpbGUgdXBsb2FkZWQgdGhyb3VnaCBhIGZvcm1cbiAgICAgICAgKiAgICAgICAvLyB0aGlzIHNhbXBsZSBjb2RlIGdvZXMgd2l0aCBhbiBodG1sIGZvcm0gdGhhdCBsb29rcyBsaWtlIHRoaXM6XG4gICAgICAgICogICAgICAgLy9cbiAgICAgICAgKiAgICAgICAvLyA8Zm9ybSBpZD1cInVwbG9hZC1maWxlXCI+XG4gICAgICAgICogICAgICAgLy8gICA8aW5wdXQgaWQ9XCJmaWxlXCIgdHlwZT1cImZpbGVcIj5cbiAgICAgICAgKiAgICAgICAvLyAgIDxpbnB1dCBpZD1cImZpbGVuYW1lXCIgdHlwZT1cInRleHRcIiB2YWx1ZT1cIm15RmlsZS50eHRcIj5cbiAgICAgICAgKiAgICAgICAvLyAgIDxidXR0b24gdHlwZT1cInN1Ym1pdFwiPlVwbG9hZCBteUZpbGU8L2J1dHRvbj5cbiAgICAgICAgKiAgICAgICAvLyA8L2Zvcm0+XG4gICAgICAgICogICAgICAgLy9cbiAgICAgICAgKiAgICAgICAkKCcjdXBsb2FkLWZpbGUnKS5vbignc3VibWl0JywgZnVuY3Rpb24gKGUpIHtcbiAgICAgICAgKiAgICAgICAgICBlLnByZXZlbnREZWZhdWx0KCk7XG4gICAgICAgICogICAgICAgICAgdmFyIGZpbGVuYW1lID0gJCgnI2ZpbGVuYW1lJykudmFsKCk7XG4gICAgICAgICogICAgICAgICAgdmFyIGRhdGEgPSBuZXcgRm9ybURhdGEoKTtcbiAgICAgICAgKiAgICAgICAgICB2YXIgaW5wdXRDb250cm9sID0gJCgnI2ZpbGUnKVswXTtcbiAgICAgICAgKiAgICAgICAgICBkYXRhLmFwcGVuZCgnZmlsZScsIGlucHV0Q29udHJvbC5maWxlc1swXSwgZmlsZW5hbWUpO1xuICAgICAgICAqXG4gICAgICAgICogICAgICAgICAgYWEuY3JlYXRlKGZpbGVuYW1lLCBkYXRhLCB7IHNjb3BlOiAndXNlcicgfSk7XG4gICAgICAgICogICAgICAgfSk7XG4gICAgICAgICpcbiAgICAgICAgKlxuICAgICAgICAqICAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAqIEBwYXJhbSB7c3RyaW5nfSBgZmlsZW5hbWVgIChSZXF1aXJlZCkgTmFtZSBvZiB0aGUgZmlsZSB0byBjcmVhdGUuXG4gICAgICAgICogQHBhcmFtIHtvYmplY3R9IGBwYXJhbXNgIChPcHRpb25hbCkgQm9keSBwYXJhbWV0ZXJzIHRvIHNlbmQgdG8gdGhlIEFzc2V0IEFQSS4gUmVxdWlyZWQgaWYgdGhlIGBvcHRpb25zLnRyYW5zcG9ydC5jb250ZW50VHlwZWAgaXMgYGFwcGxpY2F0aW9uL2pzb25gLCBvdGhlcndpc2UgaWdub3JlZC5cbiAgICAgICAgKiBAcGFyYW0ge3N0cmluZ30gYHBhcmFtcy5lbmNvZGluZ2AgRWl0aGVyIGBIRVhgIG9yIGBCQVNFXzY0YC4gUmVxdWlyZWQgaWYgYG9wdGlvbnMudHJhbnNwb3J0LmNvbnRlbnRUeXBlYCBpcyBgYXBwbGljYXRpb24vanNvbmAuXG4gICAgICAgICogQHBhcmFtIHtzdHJpbmd9IGBwYXJhbXMuZGF0YWAgVGhlIGVuY29kZWQgZGF0YSBmb3IgdGhlIGZpbGUuIFJlcXVpcmVkIGlmIGBvcHRpb25zLnRyYW5zcG9ydC5jb250ZW50VHlwZWAgaXMgYGFwcGxpY2F0aW9uL2pzb25gLlxuICAgICAgICAqIEBwYXJhbSB7c3RyaW5nfSBgcGFyYW1zLmNvbnRlbnRUeXBlYCBUaGUgbWltZSB0eXBlIG9mIHRoZSBmaWxlLiBPcHRpb25hbC5cbiAgICAgICAgKiBAcGFyYW0ge29iamVjdH0gYG9wdGlvbnNgIChPcHRpb25hbCkgT3B0aW9ucyBvYmplY3QgdG8gb3ZlcnJpZGUgZ2xvYmFsIG9wdGlvbnMuXG4gICAgICAgICpcbiAgICAgICAgKi9cbiAgICAgICAgY3JlYXRlOiBmdW5jdGlvbiAoZmlsZW5hbWUsIHBhcmFtcywgb3B0aW9ucykge1xuICAgICAgICAgICAgcmV0dXJuIHVwbG9hZCgncG9zdCcsIGZpbGVuYW1lLCBwYXJhbXMsIG9wdGlvbnMpO1xuICAgICAgICB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAqIEdldHMgYSBmaWxlIGZyb20gdGhlIEFzc2V0IEFQSSwgZmV0Y2hpbmcgdGhlIGFzc2V0IGNvbnRlbnQuIChUbyBnZXQgYSBsaXN0XG4gICAgICAgICogb2YgdGhlIGFzc2V0cyBpbiBhIHNjb3BlLCB1c2UgYGxpc3QoKWAuKVxuICAgICAgICAqXG4gICAgICAgICogICoqUGFyYW1ldGVycyoqXG4gICAgICAgICogQHBhcmFtIHtzdHJpbmd9IGBmaWxlbmFtZWAgKFJlcXVpcmVkKSBOYW1lIG9mIHRoZSBmaWxlIHRvIHJldHJpZXZlLlxuICAgICAgICAqIEBwYXJhbSB7b2JqZWN0fSBgb3B0aW9uc2AgKE9wdGlvbmFsKSBPcHRpb25zIG9iamVjdCB0byBvdmVycmlkZSBnbG9iYWwgb3B0aW9ucy5cbiAgICAgICAgKlxuICAgICAgICAqL1xuICAgICAgICBnZXQ6IGZ1bmN0aW9uIChmaWxlbmFtZSwgb3B0aW9ucykge1xuICAgICAgICAgICAgdmFyIGdldFNlcnZpY2VPcHRpb25zID0gX3BpY2soc2VydmljZU9wdGlvbnMsIFsnc2NvcGUnLCAnYWNjb3VudCcsICdwcm9qZWN0JywgJ2dyb3VwJywgJ3VzZXJJZCddKTtcbiAgICAgICAgICAgIHZhciB1cmxPcHRpb25zID0gJC5leHRlbmQoe30sIGdldFNlcnZpY2VPcHRpb25zLCBvcHRpb25zKTtcbiAgICAgICAgICAgIHZhciB1cmwgPSBidWlsZFVybChmaWxlbmFtZSwgdXJsT3B0aW9ucyk7XG4gICAgICAgICAgICB2YXIgZ2V0T3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LCB1cmxPcHRpb25zLCB7IHVybDogdXJsIH0pO1xuXG4gICAgICAgICAgICByZXR1cm4gaHR0cC5nZXQoe30sIGdldE9wdGlvbnMpO1xuICAgICAgICB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAqIEdldHMgdGhlIGxpc3Qgb2YgdGhlIGFzc2V0cyBpbiBhIHNjb3BlLlxuICAgICAgICAqXG4gICAgICAgICogKipFeGFtcGxlKipcbiAgICAgICAgKlxuICAgICAgICAqICAgICAgIGFhLmxpc3QoeyBmdWxsVXJsOiB0cnVlIH0pLnRoZW4oZnVuY3Rpb24oZmlsZUxpc3Qpe1xuICAgICAgICAqICAgICAgICAgICBjb25zb2xlLmxvZygnYXJyYXkgb2YgZmlsZXMgPSAnLCBmaWxlTGlzdCk7XG4gICAgICAgICogICAgICAgfSk7XG4gICAgICAgICpcbiAgICAgICAgKiAgKipQYXJhbWV0ZXJzKipcbiAgICAgICAgKiBAcGFyYW0ge29iamVjdH0gYG9wdGlvbnNgIChPcHRpb25hbCkgT3B0aW9ucyBvYmplY3QgdG8gb3ZlcnJpZGUgZ2xvYmFsIG9wdGlvbnMuXG4gICAgICAgICogQHBhcmFtIHtzdHJpbmd9IGBvcHRpb25zLnNjb3BlYCAoT3B0aW9uYWwpIFRoZSBzY29wZSAoYHVzZXJgLCBgZ3JvdXBgLCBgcHJvamVjdGApLlxuICAgICAgICAqIEBwYXJhbSB7Ym9vbGVhbn0gYG9wdGlvbnMuZnVsbFVybGAgKE9wdGlvbmFsKSBEZXRlcm1pbmVzIGlmIHRoZSBsaXN0IG9mIGFzc2V0cyBpbiBhIHNjb3BlIGluY2x1ZGVzIHRoZSBjb21wbGV0ZSBVUkwgZm9yIGVhY2ggYXNzZXQgKGB0cnVlYCksIG9yIG9ubHkgdGhlIGZpbGUgbmFtZXMgb2YgdGhlIGFzc2V0cyAoYGZhbHNlYCkuXG4gICAgICAgICpcbiAgICAgICAgKi9cbiAgICAgICAgbGlzdDogZnVuY3Rpb24gKG9wdGlvbnMpIHtcbiAgICAgICAgICAgIHZhciBkdGQgPSAkLkRlZmVycmVkKCk7XG4gICAgICAgICAgICB2YXIgbWUgPSB0aGlzO1xuICAgICAgICAgICAgdmFyIHVybE9wdGlvbnMgPSAkLmV4dGVuZCh7fSwgc2VydmljZU9wdGlvbnMsIG9wdGlvbnMpO1xuICAgICAgICAgICAgdmFyIHVybCA9IGJ1aWxkVXJsKCcnLCB1cmxPcHRpb25zKTtcbiAgICAgICAgICAgIHZhciBnZXRPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sIHVybE9wdGlvbnMsIHsgdXJsOiB1cmwgfSk7XG4gICAgICAgICAgICB2YXIgZnVsbFVybCA9IGdldE9wdGlvbnMuZnVsbFVybDtcblxuICAgICAgICAgICAgaWYgKCFmdWxsVXJsKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIGh0dHAuZ2V0KHt9LCBnZXRPcHRpb25zKTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgaHR0cC5nZXQoe30sIGdldE9wdGlvbnMpXG4gICAgICAgICAgICAgICAgLnRoZW4oZnVuY3Rpb24gKGZpbGVzKSB7XG4gICAgICAgICAgICAgICAgICAgIHZhciBmdWxsUGF0aEZpbGVzID0gJC5tYXAoZmlsZXMsIGZ1bmN0aW9uIChmaWxlKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICByZXR1cm4gYnVpbGRVcmwoZmlsZSwgdXJsT3B0aW9ucyk7XG4gICAgICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICAgICAgICBkdGQucmVzb2x2ZShmdWxsUGF0aEZpbGVzLCBtZSk7XG4gICAgICAgICAgICAgICAgfSlcbiAgICAgICAgICAgICAgICAuZmFpbChkdGQucmVqZWN0KTtcblxuICAgICAgICAgICAgcmV0dXJuIGR0ZC5wcm9taXNlKCk7XG4gICAgICAgIH0sXG5cbiAgICAgICAgLyoqXG4gICAgICAgICogUmVwbGFjZXMgYW4gZXhpc3RpbmcgZmlsZSBpbiB0aGUgQXNzZXQgQVBJLlxuICAgICAgICAqXG4gICAgICAgICogKipFeGFtcGxlKipcbiAgICAgICAgKlxuICAgICAgICAqICAgICAgIC8vIHJlcGxhY2UgYW4gYXNzZXQgdXNpbmcgZW5jb2RlZCB0ZXh0XG4gICAgICAgICogICAgICAgYWEucmVwbGFjZSgndGVzdC50eHQnLCB7XG4gICAgICAgICogICAgICAgICAgIGVuY29kaW5nOiAnQkFTRV82NCcsXG4gICAgICAgICogICAgICAgICAgIGRhdGE6ICdWR2hwY3lCcGN5QmhJSE5sWTI5dVpDQjBaWE4wSUdacGJHVXUnLFxuICAgICAgICAqICAgICAgICAgICBjb250ZW50VHlwZTogJ3RleHQvcGxhaW4nXG4gICAgICAgICogICAgICAgfSwgeyBzY29wZTogJ3VzZXInIH0pO1xuICAgICAgICAqXG4gICAgICAgICogICAgICAgLy8gYWx0ZXJuYXRpdmVseSwgcmVwbGFjZSBhbiBhc3NldCB1c2luZyBhIGZpbGUgdXBsb2FkZWQgdGhyb3VnaCBhIGZvcm1cbiAgICAgICAgKiAgICAgICAvLyB0aGlzIHNhbXBsZSBjb2RlIGdvZXMgd2l0aCBhbiBodG1sIGZvcm0gdGhhdCBsb29rcyBsaWtlIHRoaXM6XG4gICAgICAgICogICAgICAgLy9cbiAgICAgICAgKiAgICAgICAvLyA8Zm9ybSBpZD1cInJlcGxhY2UtZmlsZVwiPlxuICAgICAgICAqICAgICAgIC8vICAgPGlucHV0IGlkPVwiZmlsZVwiIHR5cGU9XCJmaWxlXCI+XG4gICAgICAgICogICAgICAgLy8gICA8aW5wdXQgaWQ9XCJyZXBsYWNlLWZpbGVuYW1lXCIgdHlwZT1cInRleHRcIiB2YWx1ZT1cIm15RmlsZS50eHRcIj5cbiAgICAgICAgKiAgICAgICAvLyAgIDxidXR0b24gdHlwZT1cInN1Ym1pdFwiPlJlcGxhY2UgbXlGaWxlPC9idXR0b24+XG4gICAgICAgICogICAgICAgLy8gPC9mb3JtPlxuICAgICAgICAqICAgICAgIC8vXG4gICAgICAgICogICAgICAgJCgnI3JlcGxhY2UtZmlsZScpLm9uKCdzdWJtaXQnLCBmdW5jdGlvbiAoZSkge1xuICAgICAgICAqICAgICAgICAgIGUucHJldmVudERlZmF1bHQoKTtcbiAgICAgICAgKiAgICAgICAgICB2YXIgZmlsZW5hbWUgPSAkKCcjcmVwbGFjZS1maWxlbmFtZScpLnZhbCgpO1xuICAgICAgICAqICAgICAgICAgIHZhciBkYXRhID0gbmV3IEZvcm1EYXRhKCk7XG4gICAgICAgICogICAgICAgICAgdmFyIGlucHV0Q29udHJvbCA9ICQoJyNmaWxlJylbMF07XG4gICAgICAgICogICAgICAgICAgZGF0YS5hcHBlbmQoJ2ZpbGUnLCBpbnB1dENvbnRyb2wuZmlsZXNbMF0sIGZpbGVuYW1lKTtcbiAgICAgICAgKlxuICAgICAgICAqICAgICAgICAgIGFhLnJlcGxhY2UoZmlsZW5hbWUsIGRhdGEsIHsgc2NvcGU6ICd1c2VyJyB9KTtcbiAgICAgICAgKiAgICAgICB9KTtcbiAgICAgICAgKlxuICAgICAgICAqICAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAqIEBwYXJhbSB7c3RyaW5nfSBgZmlsZW5hbWVgIChSZXF1aXJlZCkgTmFtZSBvZiB0aGUgZmlsZSBiZWluZyByZXBsYWNlZC5cbiAgICAgICAgKiBAcGFyYW0ge29iamVjdH0gYHBhcmFtc2AgKE9wdGlvbmFsKSBCb2R5IHBhcmFtZXRlcnMgdG8gc2VuZCB0byB0aGUgQXNzZXQgQVBJLiBSZXF1aXJlZCBpZiB0aGUgYG9wdGlvbnMudHJhbnNwb3J0LmNvbnRlbnRUeXBlYCBpcyBgYXBwbGljYXRpb24vanNvbmAsIG90aGVyd2lzZSBpZ25vcmVkLlxuICAgICAgICAqIEBwYXJhbSB7c3RyaW5nfSBgcGFyYW1zLmVuY29kaW5nYCBFaXRoZXIgYEhFWGAgb3IgYEJBU0VfNjRgLiBSZXF1aXJlZCBpZiBgb3B0aW9ucy50cmFuc3BvcnQuY29udGVudFR5cGVgIGlzIGBhcHBsaWNhdGlvbi9qc29uYC5cbiAgICAgICAgKiBAcGFyYW0ge3N0cmluZ30gYHBhcmFtcy5kYXRhYCBUaGUgZW5jb2RlZCBkYXRhIGZvciB0aGUgZmlsZS4gUmVxdWlyZWQgaWYgYG9wdGlvbnMudHJhbnNwb3J0LmNvbnRlbnRUeXBlYCBpcyBgYXBwbGljYXRpb24vanNvbmAuXG4gICAgICAgICogQHBhcmFtIHtzdHJpbmd9IGBwYXJhbXMuY29udGVudFR5cGVgIFRoZSBtaW1lIHR5cGUgb2YgdGhlIGZpbGUuIE9wdGlvbmFsLlxuICAgICAgICAqIEBwYXJhbSB7b2JqZWN0fSBgb3B0aW9uc2AgKE9wdGlvbmFsKSBPcHRpb25zIG9iamVjdCB0byBvdmVycmlkZSBnbG9iYWwgb3B0aW9ucy5cbiAgICAgICAgKlxuICAgICAgICAqL1xuICAgICAgICByZXBsYWNlOiBmdW5jdGlvbiAoZmlsZW5hbWUsIHBhcmFtcywgb3B0aW9ucykge1xuICAgICAgICAgICAgcmV0dXJuIHVwbG9hZCgncHV0JywgZmlsZW5hbWUsIHBhcmFtcywgb3B0aW9ucyk7XG4gICAgICAgIH0sXG5cbiAgICAgICAgLyoqXG4gICAgICAgICogRGVsZXRlcyBhIGZpbGUgZnJvbSB0aGUgQXNzZXQgQVBJLlxuICAgICAgICAqXG4gICAgICAgICogKipFeGFtcGxlKipcbiAgICAgICAgKlxuICAgICAgICAqICAgICAgIGFhLmRlbGV0ZShzYW1wbGVGaWxlTmFtZSk7XG4gICAgICAgICpcbiAgICAgICAgKiAgKipQYXJhbWV0ZXJzKipcbiAgICAgICAgKiBAcGFyYW0ge3N0cmluZ30gYGZpbGVuYW1lYCAoUmVxdWlyZWQpIE5hbWUgb2YgdGhlIGZpbGUgdG8gZGVsZXRlLlxuICAgICAgICAqIEBwYXJhbSB7b2JqZWN0fSBgb3B0aW9uc2AgKE9wdGlvbmFsKSBPcHRpb25zIG9iamVjdCB0byBvdmVycmlkZSBnbG9iYWwgb3B0aW9ucy5cbiAgICAgICAgKlxuICAgICAgICAqL1xuICAgICAgICBkZWxldGU6IGZ1bmN0aW9uIChmaWxlbmFtZSwgb3B0aW9ucykge1xuICAgICAgICAgICAgcmV0dXJuIHVwbG9hZCgnZGVsZXRlJywgZmlsZW5hbWUsIHt9LCBvcHRpb25zKTtcbiAgICAgICAgfSxcblxuICAgICAgICBhc3NldFVybDogZnVuY3Rpb24gKGZpbGVuYW1lLCBvcHRpb25zKSB7XG4gICAgICAgICAgICB2YXIgdXJsT3B0aW9ucyA9ICQuZXh0ZW5kKHt9LCBzZXJ2aWNlT3B0aW9ucywgb3B0aW9ucyk7XG4gICAgICAgICAgICByZXR1cm4gYnVpbGRVcmwoZmlsZW5hbWUsIHVybE9wdGlvbnMpO1xuICAgICAgICB9XG4gICAgfTtcbiAgICAkLmV4dGVuZCh0aGlzLCBwdWJsaWNBUEkpO1xufTtcbiIsIi8qKlxuICpcbiAqICMjIEF1dGhlbnRpY2F0aW9uIEFQSSBTZXJ2aWNlXG4gKlxuICogVGhlIEF1dGhlbnRpY2F0aW9uIEFQSSBTZXJ2aWNlIHByb3ZpZGVzIGEgbWV0aG9kIGZvciBsb2dnaW5nIGluLCB3aGljaCBjcmVhdGVzIGFuZCByZXR1cm5zIGEgdXNlciBhY2Nlc3MgdG9rZW4uXG4gKlxuICogVXNlciBhY2Nlc3MgdG9rZW5zIGFyZSByZXF1aXJlZCBmb3IgZWFjaCBjYWxsIHRvIEVwaWNlbnRlci4gKFNlZSBbUHJvamVjdCBBY2Nlc3NdKC4uLy4uLy4uL3Byb2plY3RfYWNjZXNzLykgZm9yIG1vcmUgaW5mb3JtYXRpb24uKVxuICpcbiAqIElmIHlvdSBuZWVkIGFkZGl0aW9uYWwgZnVuY3Rpb25hbGl0eSAtLSBzdWNoIGFzIHRyYWNraW5nIHNlc3Npb24gaW5mb3JtYXRpb24sIGVhc2lseSByZXRyaWV2aW5nIHRoZSB1c2VyIHRva2VuLCBvciBnZXR0aW5nIHRoZSBncm91cHMgdG8gd2hpY2ggYW4gZW5kIHVzZXIgYmVsb25ncyAtLSBjb25zaWRlciB1c2luZyB0aGUgW0F1dGhvcml6YXRpb24gTWFuYWdlcl0oLi4vYXV0aC1tYW5hZ2VyLykgaW5zdGVhZC5cbiAqXG4gKiAgICAgIHZhciBhdXRoID0gbmV3IEYuc2VydmljZS5BdXRoKCk7XG4gKiAgICAgIGF1dGgubG9naW4oeyB1c2VyTmFtZTogJ2pzbWl0aEBhY21lc2ltdWxhdGlvbnMuY29tJyxcbiAqICAgICAgICAgICAgICAgICAgcGFzc3dvcmQ6ICdwYXNzdzByZCcgfSk7XG4gKi9cblxuJ3VzZSBzdHJpY3QnO1xuXG52YXIgQ29uZmlnU2VydmljZSA9IHJlcXVpcmUoJy4vY29uZmlndXJhdGlvbi1zZXJ2aWNlJyk7XG52YXIgVHJhbnNwb3J0RmFjdG9yeSA9IHJlcXVpcmUoJy4uL3RyYW5zcG9ydC9odHRwLXRyYW5zcG9ydC1mYWN0b3J5Jyk7XG5cbm1vZHVsZS5leHBvcnRzID0gZnVuY3Rpb24gKGNvbmZpZykge1xuICAgIHZhciBkZWZhdWx0cyA9IHtcbiAgICAgICAgLyoqXG4gICAgICAgICAqIEVtYWlsIG9yIHVzZXJuYW1lIHRvIHVzZSBmb3IgbG9nZ2luZyBpbi4gRGVmYXVsdHMgdG8gZW1wdHkgc3RyaW5nLlxuICAgICAgICAgKiBAdHlwZSB7U3RyaW5nfVxuICAgICAgICAgKi9cbiAgICAgICAgdXNlck5hbWU6ICcnLFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBQYXNzd29yZCBmb3Igc3BlY2lmaWVkIGB1c2VyTmFtZWAuIERlZmF1bHRzIHRvIGVtcHR5IHN0cmluZy5cbiAgICAgICAgICogQHR5cGUge1N0cmluZ31cbiAgICAgICAgICovXG4gICAgICAgIHBhc3N3b3JkOiAnJyxcblxuICAgICAgICAvKipcbiAgICAgICAgICogVGhlIGFjY291bnQgaWQgZm9yIHRoaXMgYHVzZXJOYW1lYC4gSW4gdGhlIEVwaWNlbnRlciBVSSwgdGhpcyBpcyB0aGUgKipUZWFtIElEKiogKGZvciB0ZWFtIHByb2plY3RzKSBvciB0aGUgKipVc2VyIElEKiogKGZvciBwZXJzb25hbCBwcm9qZWN0cykuIFJlcXVpcmVkIGlmIHRoZSBgdXNlck5hbWVgIGlzIGZvciBhbiBbZW5kIHVzZXJdKC4uLy4uLy4uL2dsb3NzYXJ5LyN1c2VycykuIERlZmF1bHRzIHRvIGVtcHR5IHN0cmluZy5cbiAgICAgICAgICogQHR5cGUge1N0cmluZ31cbiAgICAgICAgICovXG4gICAgICAgIGFjY291bnQ6ICcnLFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBPcHRpb25zIHRvIHBhc3Mgb24gdG8gdGhlIHVuZGVybHlpbmcgdHJhbnNwb3J0IGxheWVyLiBBbGwganF1ZXJ5LmFqYXggb3B0aW9ucyBhdCBodHRwOi8vYXBpLmpxdWVyeS5jb20valF1ZXJ5LmFqYXgvIGFyZSBhdmFpbGFibGUuIERlZmF1bHRzIHRvIGVtcHR5IG9iamVjdC5cbiAgICAgICAgICogQHR5cGUge09iamVjdH1cbiAgICAgICAgICovXG4gICAgICAgIHRyYW5zcG9ydDoge31cbiAgICB9O1xuICAgIHZhciBzZXJ2aWNlT3B0aW9ucyA9ICQuZXh0ZW5kKHt9LCBkZWZhdWx0cywgY29uZmlnKTtcbiAgICB2YXIgdXJsQ29uZmlnID0gbmV3IENvbmZpZ1NlcnZpY2Uoc2VydmljZU9wdGlvbnMpLmdldCgnc2VydmVyJyk7XG5cbiAgICB2YXIgdHJhbnNwb3J0T3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LCBzZXJ2aWNlT3B0aW9ucy50cmFuc3BvcnQsIHtcbiAgICAgICAgdXJsOiB1cmxDb25maWcuZ2V0QVBJUGF0aCgnYXV0aGVudGljYXRpb24nKVxuICAgIH0pO1xuICAgIHZhciBodHRwID0gbmV3IFRyYW5zcG9ydEZhY3RvcnkodHJhbnNwb3J0T3B0aW9ucyk7XG5cbiAgICB2YXIgcHVibGljQVBJID0ge1xuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBMb2dzIHVzZXIgaW4sIHJldHVybmluZyB0aGUgdXNlciBhY2Nlc3MgdG9rZW4uXG4gICAgICAgICAqXG4gICAgICAgICAqIElmIG5vIGB1c2VyTmFtZWAgb3IgYHBhc3N3b3JkYCB3ZXJlIHByb3ZpZGVkIGluIHRoZSBpbml0aWFsIGNvbmZpZ3VyYXRpb24gb3B0aW9ucywgdGhleSBhcmUgcmVxdWlyZWQgaW4gdGhlIGBvcHRpb25zYCBoZXJlLiBJZiBubyBgYWNjb3VudGAgd2FzIHByb3ZpZGVkIGluIHRoZSBpbml0aWFsIGNvbmZpZ3VyYXRpb24gb3B0aW9ucyBhbmQgdGhlIGB1c2VyTmFtZWAgaXMgZm9yIGFuIFtlbmQgdXNlcl0oLi4vLi4vLi4vZ2xvc3NhcnkvI3VzZXJzKSwgdGhlIGBhY2NvdW50YCBpcyByZXF1aXJlZCBhcyB3ZWxsLlxuICAgICAgICAgKlxuICAgICAgICAgKiAqKkV4YW1wbGUqKlxuICAgICAgICAgKlxuICAgICAgICAgKiAgICAgIGF1dGgubG9naW4oe1xuICAgICAgICAgKiAgICAgICAgICB1c2VyTmFtZTogJ2pzbWl0aCcsXG4gICAgICAgICAqICAgICAgICAgIHBhc3N3b3JkOiAncGFzc3cwcmQnLFxuICAgICAgICAgKiAgICAgICAgICBhY2NvdW50OiAnYWNtZS1zaW11bGF0aW9ucycgfSlcbiAgICAgICAgICogICAgICAudGhlbihmdW5jdGlvbiAodG9rZW4pIHtcbiAgICAgICAgICogICAgICAgICAgY29uc29sZS5sb2coXCJ1c2VyIGFjY2VzcyB0b2tlbiBpczogXCIsIHRva2VuLmFjY2Vzc190b2tlbik7XG4gICAgICAgICAqICAgICAgfSk7XG4gICAgICAgICAqXG4gICAgICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICAgICAqIEBwYXJhbSB7T2JqZWN0fSBgb3B0aW9uc2AgKE9wdGlvbmFsKSBPdmVycmlkZXMgZm9yIGNvbmZpZ3VyYXRpb24gb3B0aW9ucy5cbiAgICAgICAgICovXG4gICAgICAgIGxvZ2luOiBmdW5jdGlvbiAob3B0aW9ucykge1xuICAgICAgICAgICAgdmFyIGh0dHBPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwgeyBzdWNjZXNzOiAkLm5vb3AgfSwgc2VydmljZU9wdGlvbnMsIG9wdGlvbnMpO1xuICAgICAgICAgICAgaWYgKCFodHRwT3B0aW9ucy51c2VyTmFtZSB8fCAhaHR0cE9wdGlvbnMucGFzc3dvcmQpIHtcbiAgICAgICAgICAgICAgICB2YXIgcmVzcCA9IHsgc3RhdHVzOiA0MDEsIHN0YXR1c01lc3NhZ2U6ICdObyB1c2VybmFtZSBvciBwYXNzd29yZCBzcGVjaWZpZWQuJyB9O1xuICAgICAgICAgICAgICAgIGlmIChvcHRpb25zLmVycm9yKSB7XG4gICAgICAgICAgICAgICAgICAgIG9wdGlvbnMuZXJyb3IuY2FsbCh0aGlzLCByZXNwKTtcbiAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICByZXR1cm4gJC5EZWZlcnJlZCgpLnJlamVjdChyZXNwKS5wcm9taXNlKCk7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIHZhciBwb3N0UGFyYW1zID0ge1xuICAgICAgICAgICAgICAgIHVzZXJOYW1lOiBodHRwT3B0aW9ucy51c2VyTmFtZSxcbiAgICAgICAgICAgICAgICBwYXNzd29yZDogaHR0cE9wdGlvbnMucGFzc3dvcmQsXG4gICAgICAgICAgICB9O1xuICAgICAgICAgICAgaWYgKGh0dHBPcHRpb25zLmFjY291bnQpIHtcbiAgICAgICAgICAgICAgICAvL3Bhc3MgaW4gbnVsbCBmb3IgYWNjb3VudCB1bmRlciBvcHRpb25zIGlmIHlvdSBkb24ndCB3YW50IGl0IHRvIGJlIHNlbnRcbiAgICAgICAgICAgICAgICBwb3N0UGFyYW1zLmFjY291bnQgPSBodHRwT3B0aW9ucy5hY2NvdW50O1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICByZXR1cm4gaHR0cC5wb3N0KHBvc3RQYXJhbXMsIGh0dHBPcHRpb25zKTtcbiAgICAgICAgfSxcblxuICAgICAgICAvLyAocmVwbGFjZSB3aXRoIC8qICovIGNvbW1lbnQgYmxvY2ssIHRvIG1ha2UgdmlzaWJsZSBpbiBkb2NzLCBvbmNlIHRoaXMgaXMgbW9yZSB0aGFuIGEgbm9vcClcbiAgICAgICAgLy9cbiAgICAgICAgLy8gTG9ncyB1c2VyIG91dCBmcm9tIHNwZWNpZmllZCBhY2NvdW50cy5cbiAgICAgICAgLy9cbiAgICAgICAgLy8gRXBpY2VudGVyIGxvZ291dCBpcyBub3QgaW1wbGVtZW50ZWQgeWV0LCBzbyBmb3Igbm93IHRoaXMgaXMgYSBkdW1teSBwcm9taXNlIHRoYXQgZ2V0cyBhdXRvbWF0aWNhbGx5IHJlc29sdmVkLlxuICAgICAgICAvL1xuICAgICAgICAvLyAqKkV4YW1wbGUqKlxuICAgICAgICAvL1xuICAgICAgICAvLyAgICAgIGF1dGgubG9nb3V0KCk7XG4gICAgICAgIC8vXG4gICAgICAgIC8vICoqUGFyYW1ldGVycyoqXG4gICAgICAgIC8vIEBwYXJhbSB7T2JqZWN0fSBgb3B0aW9uc2AgKE9wdGlvbmFsKSBPdmVycmlkZXMgZm9yIGNvbmZpZ3VyYXRpb24gb3B0aW9ucy5cbiAgICAgICAgLy9cbiAgICAgICAgbG9nb3V0OiBmdW5jdGlvbiAob3B0aW9ucykge1xuICAgICAgICAgICAgdmFyIGR0ZCA9ICQuRGVmZXJyZWQoKTtcbiAgICAgICAgICAgIGR0ZC5yZXNvbHZlKCk7XG4gICAgICAgICAgICByZXR1cm4gZHRkLnByb21pc2UoKTtcbiAgICAgICAgfVxuICAgIH07XG5cbiAgICAkLmV4dGVuZCh0aGlzLCBwdWJsaWNBUEkpO1xufTtcbiIsIid1c2Ugc3RyaWN0JztcblxuLyoqXG4gKiAjIyBDaGFubmVsIFNlcnZpY2VcbiAqXG4gKiBUaGUgRXBpY2VudGVyIHBsYXRmb3JtIHByb3ZpZGVzIGEgcHVzaCBjaGFubmVsLCB3aGljaCBhbGxvd3MgeW91IHRvIHB1Ymxpc2ggYW5kIHN1YnNjcmliZSB0byBtZXNzYWdlcyB3aXRoaW4gYSBbcHJvamVjdF0oLi4vLi4vLi4vZ2xvc3NhcnkvI3Byb2plY3RzKSwgW2dyb3VwXSguLi8uLi8uLi9nbG9zc2FyeS8jZ3JvdXBzKSwgb3IgW211bHRpcGxheWVyIHdvcmxkXSguLi8uLi8uLi9nbG9zc2FyeS8jd29ybGQpLiBUaGVyZSBhcmUgdHdvIG1haW4gdXNlIGNhc2VzIGZvciB0aGUgY2hhbm5lbDogZXZlbnQgbm90aWZpY2F0aW9ucyBhbmQgY2hhdCBtZXNzYWdlcy5cbiAqXG4gKiBUaGUgQ2hhbm5lbCBTZXJ2aWNlIGlzIGEgYnVpbGRpbmcgYmxvY2sgZm9yIHRoaXMgZnVuY3Rpb25hbGl0eS4gSXQgY3JlYXRlcyBhIHB1Ymxpc2gtc3Vic2NyaWJlIG9iamVjdCwgYWxsb3dpbmcgeW91IHRvIHB1Ymxpc2ggbWVzc2FnZXMsIHN1YnNjcmliZSB0byBtZXNzYWdlcywgb3IgdW5zdWJzY3JpYmUgZnJvbSBtZXNzYWdlcyBmb3IgYSBnaXZlbiAndG9waWMnIG9uIGEgYCQuY29tZXRkYCB0cmFuc3BvcnQgaW5zdGFuY2UuXG4gKlxuICogVHlwaWNhbGx5LCB5b3UgdXNlIHRoZSBbRXBpY2VudGVyIENoYW5uZWwgTWFuYWdlcl0oLi4vZXBpY2VudGVyLWNoYW5uZWwtbWFuYWdlci8pIHRvIGNyZWF0ZSBvciByZXRyaWV2ZSBjaGFubmVscywgdGhlbiB1c2UgdGhlIENoYW5uZWwgU2VydmljZSBgc3Vic2NyaWJlKClgIGFuZCBgcHVibGlzaCgpYCBtZXRob2RzIHRvIGxpc3RlbiB0byBvciB1cGRhdGUgZGF0YS4gKEZvciBhZGRpdGlvbmFsIGJhY2tncm91bmQgb24gRXBpY2VudGVyJ3MgcHVzaCBjaGFubmVsLCBzZWUgdGhlIGludHJvZHVjdG9yeSBub3RlcyBvbiB0aGUgW1B1c2ggQ2hhbm5lbCBBUEldKC4uLy4uLy4uL3Jlc3RfYXBpcy9tdWx0aXBsYXllci9jaGFubmVsLykgcGFnZS4pXG4gKlxuICogWW91J2xsIG5lZWQgdG8gaW5jbHVkZSB0aGUgYGVwaWNlbnRlci1tdWx0aXBsYXllci1kZXBlbmRlbmNpZXMuanNgIGxpYnJhcnkgaW4gYWRkaXRpb24gdG8gdGhlIGBlcGljZW50ZXIuanNgIGxpYnJhcnkgaW4geW91ciBwcm9qZWN0IHRvIHVzZSB0aGUgQ2hhbm5lbCBTZXJ2aWNlLiBTZWUgW0luY2x1ZGluZyBFcGljZW50ZXIuanNdKC4uLy4uLyNpbmNsdWRlKS5cbiAqXG4gKiBUbyB1c2UgdGhlIENoYW5uZWwgU2VydmljZSwgaW5zdGFudGlhdGUgaXQsIHRoZW4gbWFrZSBjYWxscyB0byBhbnkgb2YgdGhlIG1ldGhvZHMgeW91IG5lZWQuXG4gKlxuICogICAgICAgIHZhciBjcyA9IG5ldyBGLnNlcnZpY2UuQ2hhbm5lbCgpO1xuICogICAgICAgIGNzLnB1Ymxpc2goJy9hY21lLXNpbXVsYXRpb25zL3N1cHBseS1jaGFpbi1nYW1lL2ZhbGwtc2VtaW5hci9ydW4vdmFyaWFibGVzJywgeyBwcmljZTogNTAgfSk7XG4gKlxuICogVGhlIHBhcmFtZXRlcnMgZm9yIGluc3RhbnRpYXRpbmcgYSBDaGFubmVsIFNlcnZpY2UgaW5jbHVkZTpcbiAqXG4gKiAqIGBvcHRpb25zYCBUaGUgb3B0aW9ucyBvYmplY3QgdG8gY29uZmlndXJlIHRoZSBDaGFubmVsIFNlcnZpY2UuXG4gKiAqIGBvcHRpb25zLmJhc2VgIFRoZSBiYXNlIHRvcGljLiBUaGlzIGlzIGFkZGVkIGFzIGEgcHJlZml4IHRvIGFsbCBmdXJ0aGVyIHRvcGljcyB5b3UgcHVibGlzaCBvciBzdWJzY3JpYmUgdG8gd2hpbGUgd29ya2luZyB3aXRoIHRoaXMgQ2hhbm5lbCBTZXJ2aWNlLlxuICogKiBgb3B0aW9ucy50b3BpY1Jlc29sdmVyYCBBIGZ1bmN0aW9uIHRoYXQgcHJvY2Vzc2VzIGFsbCAndG9waWNzJyBwYXNzZWQgaW50byB0aGUgYHB1Ymxpc2hgIGFuZCBgc3Vic2NyaWJlYCBtZXRob2RzLiBUaGlzIGlzIHVzZWZ1bCBpZiB5b3Ugd2FudCB0byBpbXBsZW1lbnQgeW91ciBvd24gc2VyaWFsaXplIGZ1bmN0aW9ucyBmb3IgY29udmVydGluZyBjdXN0b20gb2JqZWN0cyB0byB0b3BpYyBuYW1lcy4gUmV0dXJucyBhIFN0cmluZy4gQnkgZGVmYXVsdCwgaXQganVzdCBlY2hvZXMgdGhlIHRvcGljLlxuICogKiBgb3B0aW9ucy50cmFuc3BvcnRgIFRoZSBpbnN0YW5jZSBvZiBgJC5jb21ldGRgIHRvIGhvb2sgb250by4gU2VlIGh0dHA6Ly9kb2NzLmNvbWV0ZC5vcmcvcmVmZXJlbmNlL2phdmFzY3JpcHQuaHRtbCBmb3IgYWRkaXRpb25hbCBiYWNrZ3JvdW5kIG9uIGNvbWV0ZC5cbiAqL1xudmFyIENoYW5uZWwgPSBmdW5jdGlvbiAob3B0aW9ucykge1xuICAgIHZhciBkZWZhdWx0cyA9IHtcblxuICAgICAgICAvKipcbiAgICAgICAgICogVGhlIGJhc2UgdG9waWMuIFRoaXMgaXMgYWRkZWQgYXMgYSBwcmVmaXggdG8gYWxsIGZ1cnRoZXIgdG9waWNzIHlvdSBwdWJsaXNoIG9yIHN1YnNjcmliZSB0byB3aGlsZSB3b3JraW5nIHdpdGggdGhpcyBDaGFubmVsIFNlcnZpY2UuXG4gICAgICAgICAqIEB0eXBlIHtzdHJpbmd9XG4gICAgICAgICAqL1xuICAgICAgICBiYXNlOiAnJyxcblxuICAgICAgICAvKipcbiAgICAgICAgICogQSBmdW5jdGlvbiB0aGF0IHByb2Nlc3NlcyBhbGwgJ3RvcGljcycgcGFzc2VkIGludG8gdGhlIGBwdWJsaXNoYCBhbmQgYHN1YnNjcmliZWAgbWV0aG9kcy4gVGhpcyBpcyB1c2VmdWwgaWYgeW91IHdhbnQgdG8gaW1wbGVtZW50IHlvdXIgb3duIHNlcmlhbGl6ZSBmdW5jdGlvbnMgZm9yIGNvbnZlcnRpbmcgY3VzdG9tIG9iamVjdHMgdG8gdG9waWMgbmFtZXMuIEJ5IGRlZmF1bHQsIGl0IGp1c3QgZWNob2VzIHRoZSB0b3BpYy5cbiAgICAgICAgICpcbiAgICAgICAgICogKipQYXJhbWV0ZXJzKipcbiAgICAgICAgICpcbiAgICAgICAgICogKiBgdG9waWNgIFRvcGljIHRvIHBhcnNlLlxuICAgICAgICAgKlxuICAgICAgICAgKiAqKlJldHVybiBWYWx1ZSoqXG4gICAgICAgICAqXG4gICAgICAgICAqICogKlN0cmluZyo6IFRoaXMgZnVuY3Rpb24gc2hvdWxkIHJldHVybiBhIHN0cmluZyB0b3BpYy5cbiAgICAgICAgICpcbiAgICAgICAgICogQHR5cGUge2Z1bmN0aW9ufVxuICAgICAgICAgKi9cbiAgICAgICAgdG9waWNSZXNvbHZlcjogZnVuY3Rpb24gKHRvcGljKSB7XG4gICAgICAgICAgICByZXR1cm4gdG9waWM7XG4gICAgICAgIH0sXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIFRoZSBpbnN0YW5jZSBvZiBgJC5jb21ldGRgIHRvIGhvb2sgb250by5cbiAgICAgICAgICogQHR5cGUge29iamVjdH1cbiAgICAgICAgICovXG4gICAgICAgIHRyYW5zcG9ydDogbnVsbFxuICAgIH07XG4gICAgdGhpcy5jaGFubmVsT3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LCBkZWZhdWx0cywgb3B0aW9ucyk7XG59O1xuXG52YXIgbWFrZU5hbWUgPSBmdW5jdGlvbiAoY2hhbm5lbE5hbWUsIHRvcGljKSB7XG4gICAgLy9SZXBsYWNlIHRyYWlsaW5nL2RvdWJsZSBzbGFzaGVzXG4gICAgdmFyIG5ld05hbWUgPSAoY2hhbm5lbE5hbWUgPyAoY2hhbm5lbE5hbWUgKyAnLycgKyB0b3BpYykgOiB0b3BpYykucmVwbGFjZSgvXFwvXFwvL2csICcvJykucmVwbGFjZSgvXFwvJC8sJycpO1xuICAgIHJldHVybiBuZXdOYW1lO1xufTtcblxuXG5DaGFubmVsLnByb3RvdHlwZSA9ICQuZXh0ZW5kKENoYW5uZWwucHJvdG90eXBlLCB7XG5cbiAgICAvLyBmdXR1cmUgZnVuY3Rpb25hbGl0eTpcbiAgICAvLyAgICAgIC8vIFNldCB0aGUgY29udGV4dCBmb3IgdGhlIGNhbGxiYWNrXG4gICAgLy8gICAgICBjcy5zdWJzY3JpYmUoJ3J1bicsIGZ1bmN0aW9uICgpIHsgdGhpcy5pbm5lckhUTUwgPSAnVHJpZ2dlcmVkJ30sIGRvY3VtZW50LmJvZHkpO1xuICAgICAvL1xuICAgICAvLyAgICAgIC8vIENvbnRyb2wgdGhlIG9yZGVyIG9mIG9wZXJhdGlvbnMgYnkgc2V0dGluZyB0aGUgYHByaW9yaXR5YFxuICAgICAvLyAgICAgIGNzLnN1YnNjcmliZSgncnVuJywgY2IsIHRoaXMsIHtwcmlvcml0eTogOX0pO1xuICAgICAvL1xuICAgICAvLyAgICAgIC8vIE9ubHkgZXhlY3V0ZSB0aGUgY2FsbGJhY2ssIGBjYmAsIGlmIHRoZSB2YWx1ZSBvZiB0aGUgYHByaWNlYCB2YXJpYWJsZSBpcyA1MFxuICAgICAvLyAgICAgIGNzLnN1YnNjcmliZSgncnVuL3ZhcmlhYmxlcy9wcmljZScsIGNiLCB0aGlzLCB7cHJpb3JpdHk6IDMwLCB2YWx1ZTogNTB9KTtcbiAgICAgLy9cbiAgICAgLy8gICAgICAvLyBPbmx5IGV4ZWN1dGUgdGhlIGNhbGxiYWNrLCBgY2JgLCBpZiB0aGUgdmFsdWUgb2YgdGhlIGBwcmljZWAgdmFyaWFibGUgaXMgZ3JlYXRlciB0aGFuIDUwXG4gICAgIC8vICAgICAgc3Vic2NyaWJlKCdydW4vdmFyaWFibGVzL3ByaWNlJywgY2IsIHRoaXMsIHtwcmlvcml0eTogMzAsIHZhbHVlOiAnPjUwJ30pO1xuICAgICAvL1xuICAgICAvLyAgICAgIC8vIE9ubHkgZXhlY3V0ZSB0aGUgY2FsbGJhY2ssIGBjYmAsIGlmIHRoZSB2YWx1ZSBvZiB0aGUgYHByaWNlYCB2YXJpYWJsZSBpcyBldmVuXG4gICAgIC8vICAgICAgc3Vic2NyaWJlKCdydW4vdmFyaWFibGVzL3ByaWNlJywgY2IsIHRoaXMsIHtwcmlvcml0eTogMzAsIHZhbHVlOiBmdW5jdGlvbiAodmFsKSB7cmV0dXJuIHZhbCAlIDIgPT09IDB9fSk7XG5cblxuICAgIC8qKlxuICAgICAqIFN1YnNjcmliZSB0byBjaGFuZ2VzIG9uIGEgdG9waWMuXG4gICAgICpcbiAgICAgKiBUaGUgdG9waWMgc2hvdWxkIGluY2x1ZGUgdGhlIGZ1bGwgcGF0aCBvZiB0aGUgYWNjb3VudCBpZCAoKipUZWFtIElEKiogZm9yIHRlYW0gcHJvamVjdHMpLCBwcm9qZWN0IGlkLCBhbmQgZ3JvdXAgbmFtZS4gKEluIG1vc3QgY2FzZXMsIGl0IGlzIHNpbXBsZXIgdG8gdXNlIHRoZSBbRXBpY2VudGVyIENoYW5uZWwgTWFuYWdlcl0oLi4vZXBpY2VudGVyLWNoYW5uZWwtbWFuYWdlci8pIGluc3RlYWQsIGluIHdoaWNoIGNhc2UgdGhpcyBpcyBjb25maWd1cmVkIGZvciB5b3UuKVxuICAgICAqXG4gICAgICogICoqRXhhbXBsZXMqKlxuICAgICAqXG4gICAgICogICAgICB2YXIgY2IgPSBmdW5jdGlvbih2YWwpIHsgY29uc29sZS5sb2codmFsLmRhdGEpOyB9O1xuICAgICAqXG4gICAgICogICAgICAvLyBTdWJzY3JpYmUgdG8gY2hhbmdlcyBvbiBhIHRvcC1sZXZlbCAncnVuJyB0b3BpY1xuICAgICAqICAgICAgY3Muc3Vic2NyaWJlKCcvYWNtZS1zaW11bGF0aW9ucy9zdXBwbHktY2hhaW4tZ2FtZS9mYWxsLXNlbWluYXIvcnVuJywgY2IpO1xuICAgICAqXG4gICAgICogICAgICAvLyBTdWJzY3JpYmUgdG8gY2hhbmdlcyBvbiBjaGlsZHJlbiBvZiB0aGUgJ3J1bicgdG9waWMuIE5vdGUgdGhpcyB3aWxsIGFsc28gYmUgdHJpZ2dlcmVkIGZvciBjaGFuZ2VzIHRvIHJ1bi54Lnkuei5cbiAgICAgKiAgICAgIGNzLnN1YnNjcmliZSgnL2FjbWUtc2ltdWxhdGlvbnMvc3VwcGx5LWNoYWluLWdhbWUvZmFsbC1zZW1pbmFyL3J1bi8qJywgY2IpO1xuICAgICAqXG4gICAgICogICAgICAvLyBTdWJzY3JpYmUgdG8gY2hhbmdlcyBvbiBib3RoIHRoZSB0b3AtbGV2ZWwgJ3J1bicgdG9waWMgYW5kIGl0cyBjaGlsZHJlblxuICAgICAqICAgICAgY3Muc3Vic2NyaWJlKFsnL2FjbWUtc2ltdWxhdGlvbnMvc3VwcGx5LWNoYWluLWdhbWUvZmFsbC1zZW1pbmFyL3J1bicsXG4gICAgICogICAgICAgICAgJy9hY21lLXNpbXVsYXRpb25zL3N1cHBseS1jaGFpbi1nYW1lL2ZhbGwtc2VtaW5hci9ydW4vKiddLCBjYik7XG4gICAgICpcbiAgICAgKiAgICAgIC8vIFN1YnNjcmliZSB0byBjaGFuZ2VzIG9uIGEgcGFydGljdWxhciB2YXJpYWJsZVxuICAgICAqICAgICAgc3Vic2NyaWJlKCcvYWNtZS1zaW11bGF0aW9ucy9zdXBwbHktY2hhaW4tZ2FtZS9mYWxsLXNlbWluYXIvcnVuL3ZhcmlhYmxlcy9wcmljZScsIGNiKTtcbiAgICAgKlxuICAgICAqXG4gICAgICogKipSZXR1cm4gVmFsdWUqKlxuICAgICAqXG4gICAgICogKiAqU3RyaW5nKiBSZXR1cm5zIGEgdG9rZW4geW91IGNhbiBsYXRlciB1c2UgdG8gdW5zdWJzY3JpYmUuXG4gICAgICpcbiAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAqIEBwYXJhbSAge1N0cmluZ3xBcnJheX0gICBgdG9waWNgICAgIExpc3Qgb2YgdG9waWNzIHRvIGxpc3RlbiBmb3IgY2hhbmdlcyBvbi5cbiAgICAgKiBAcGFyYW0gIHtGdW5jdGlvbn0gYGNhbGxiYWNrYCBDYWxsYmFjayBmdW5jdGlvbiB0byBleGVjdXRlLiBDYWxsYmFjayBpcyBjYWxsZWQgd2l0aCBzaWduYXR1cmUgYChldnQsIHBheWxvYWQsIG1ldGFkYXRhKWAuXG4gICAgICogQHBhcmFtICB7T2JqZWN0fSAgIGBjb250ZXh0YCAgQ29udGV4dCBpbiB3aGljaCB0aGUgYGNhbGxiYWNrYCBpcyBleGVjdXRlZC5cbiAgICAgKiBAcGFyYW0gIHtPYmplY3R9ICAgYG9wdGlvbnNgICAoT3B0aW9uYWwpIE92ZXJyaWRlcyBmb3IgY29uZmlndXJhdGlvbiBvcHRpb25zLlxuICAgICAqIEBwYXJhbSAge051bWJlcn0gICBgb3B0aW9ucy5wcmlvcml0eWAgIFVzZWQgdG8gY29udHJvbCBvcmRlciBvZiBvcGVyYXRpb25zLiBEZWZhdWx0cyB0byAwLiBDYW4gYmUgYW55ICt2ZSBvciAtdmUgbnVtYmVyLlxuICAgICAqIEBwYXJhbSAge1N0cmluZ3xOdW1iZXJ8RnVuY3Rpb259ICAgYG9wdGlvbnMudmFsdWVgIFRoZSBgY2FsbGJhY2tgIGlzIG9ubHkgdHJpZ2dlcmVkIGlmIHRoaXMgY29uZGl0aW9uIG1hdGNoZXMuIFNlZSBleGFtcGxlcyBmb3IgZGV0YWlscy5cbiAgICAgKlxuICAgICAqL1xuICAgIHN1YnNjcmliZTogZnVuY3Rpb24gKHRvcGljLCBjYWxsYmFjaywgY29udGV4dCwgb3B0aW9ucykge1xuXG4gICAgICAgIHZhciB0b3BpY3MgPSBbXS5jb25jYXQodG9waWMpO1xuICAgICAgICB2YXIgbWUgPSB0aGlzO1xuICAgICAgICB2YXIgc3Vic2NyaXB0aW9uSWRzID0gW107XG4gICAgICAgIHZhciBvcHRzID0gbWUuY2hhbm5lbE9wdGlvbnM7XG5cbiAgICAgICAgb3B0cy50cmFuc3BvcnQuYmF0Y2goZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgJC5lYWNoKHRvcGljcywgZnVuY3Rpb24gKGluZGV4LCB0b3BpYykge1xuICAgICAgICAgICAgICAgIHRvcGljID0gbWFrZU5hbWUob3B0cy5iYXNlLCBvcHRzLnRvcGljUmVzb2x2ZXIodG9waWMpKTtcbiAgICAgICAgICAgICAgICBzdWJzY3JpcHRpb25JZHMucHVzaChvcHRzLnRyYW5zcG9ydC5zdWJzY3JpYmUodG9waWMsIGNhbGxiYWNrKSk7XG4gICAgICAgICAgICB9KTtcbiAgICAgICAgfSk7XG4gICAgICAgIHJldHVybiAoc3Vic2NyaXB0aW9uSWRzWzFdID8gc3Vic2NyaXB0aW9uSWRzIDogc3Vic2NyaXB0aW9uSWRzWzBdKTtcbiAgICB9LFxuXG4gICAgLyoqXG4gICAgICogUHVibGlzaCBkYXRhIHRvIGEgdG9waWMuXG4gICAgICpcbiAgICAgKiAqKkV4YW1wbGVzKipcbiAgICAgKlxuICAgICAqICAgICAgLy8gU2VuZCBkYXRhIHRvIGFsbCBzdWJzY3JpYmVycyBvZiB0aGUgJ3J1bicgdG9waWNcbiAgICAgKiAgICAgIGNzLnB1Ymxpc2goJy9hY21lLXNpbXVsYXRpb25zL3N1cHBseS1jaGFpbi1nYW1lL2ZhbGwtc2VtaW5hci9ydW4nLCB7IGNvbXBsZXRlZDogZmFsc2UgfSk7XG4gICAgICpcbiAgICAgKiAgICAgIC8vIFNlbmQgZGF0YSB0byBhbGwgc3Vic2NyaWJlcnMgb2YgdGhlICdydW4vdmFyaWFibGVzJyB0b3BpY1xuICAgICAqICAgICAgY3MucHVibGlzaCgnL2FjbWUtc2ltdWxhdGlvbnMvc3VwcGx5LWNoYWluLWdhbWUvZmFsbC1zZW1pbmFyL3J1bi92YXJpYWJsZXMnLCB7IHByaWNlOiA1MCB9KTtcbiAgICAgKlxuICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICpcbiAgICAgKiBAcGFyYW0gIHtTdHJpbmd9IGB0b3BpY2AgVG9waWMgdG8gcHVibGlzaCB0by5cbiAgICAgKiBAcGFyYW0gIHsqfSBgZGF0YWAgIERhdGEgdG8gcHVibGlzaCB0byB0b3BpYy5cbiAgICAgKlxuICAgICAqL1xuICAgIHB1Ymxpc2g6IGZ1bmN0aW9uICh0b3BpYywgZGF0YSkge1xuICAgICAgICB2YXIgdG9waWNzID0gW10uY29uY2F0KHRvcGljKTtcbiAgICAgICAgdmFyIG1lID0gdGhpcztcbiAgICAgICAgdmFyIHJldHVybk9ianMgPSBbXTtcbiAgICAgICAgdmFyIG9wdHMgPSBtZS5jaGFubmVsT3B0aW9ucztcblxuXG4gICAgICAgIG9wdHMudHJhbnNwb3J0LmJhdGNoKGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgICQuZWFjaCh0b3BpY3MsIGZ1bmN0aW9uIChpbmRleCwgdG9waWMpIHtcbiAgICAgICAgICAgICAgICB0b3BpYyA9IG1ha2VOYW1lKG9wdHMuYmFzZSwgb3B0cy50b3BpY1Jlc29sdmVyKHRvcGljKSk7XG4gICAgICAgICAgICAgICAgaWYgKHRvcGljLmNoYXJBdCh0b3BpYy5sZW5ndGggLSAxKSA9PT0gJyonKSB7XG4gICAgICAgICAgICAgICAgICAgIHRvcGljID0gdG9waWMucmVwbGFjZSgvXFwqKyQvLCAnJyk7XG4gICAgICAgICAgICAgICAgICAgIGNvbnNvbGUud2FybignWW91IGNhbiBjYW5ub3QgcHVibGlzaCB0byBjaGFubmVscyB3aXRoIHdpbGRjYXJkcy4gUHVibGlzaGluZyB0byAnLCB0b3BpYywgJ2luc3RlYWQnKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgcmV0dXJuT2Jqcy5wdXNoKG9wdHMudHJhbnNwb3J0LnB1Ymxpc2godG9waWMsIGRhdGEpKTtcbiAgICAgICAgICAgIH0pO1xuICAgICAgICB9KTtcbiAgICAgICAgcmV0dXJuIChyZXR1cm5PYmpzWzFdID8gcmV0dXJuT2JqcyA6IHJldHVybk9ianNbMF0pO1xuICAgIH0sXG5cbiAgICAvKipcbiAgICAgKiBVbnN1YnNjcmliZSBmcm9tIGNoYW5nZXMgdG8gYSB0b3BpYy5cbiAgICAgKlxuICAgICAqICoqRXhhbXBsZSoqXG4gICAgICpcbiAgICAgKiAgICAgIGNzLnVuc3Vic2NyaWJlKCdzYW1wbGVUb2tlbicpO1xuICAgICAqXG4gICAgICogKipQYXJhbWV0ZXJzKipcbiAgICAgKiBAcGFyYW0gIHtTdHJpbmd9IGB0b2tlbmAgVGhlIHRva2VuIGZvciB0b3BpYyBpcyByZXR1cm5lZCB3aGVuIHlvdSBpbml0aWFsbHkgc3Vic2NyaWJlLiBQYXNzIGl0IGhlcmUgdG8gdW5zdWJzY3JpYmUgZnJvbSB0aGF0IHRvcGljLlxuICAgICAqL1xuICAgIHVuc3Vic2NyaWJlOiBmdW5jdGlvbiAodG9rZW4pIHtcbiAgICAgICAgdGhpcy5jaGFubmVsT3B0aW9ucy50cmFuc3BvcnQudW5zdWJzY3JpYmUodG9rZW4pO1xuICAgICAgICByZXR1cm4gdG9rZW47XG4gICAgfSxcblxuICAgIC8qKlxuICAgICAqIFN0YXJ0IGxpc3RlbmluZyBmb3IgZXZlbnRzIG9uIHRoaXMgaW5zdGFuY2UuIFNpZ25hdHVyZSBpcyBzYW1lIGFzIGZvciBqUXVlcnkgRXZlbnRzOiBodHRwOi8vYXBpLmpxdWVyeS5jb20vb24vLlxuICAgICAqXG4gICAgICogU3VwcG9ydGVkIGV2ZW50cyBhcmU6IGBjb25uZWN0YCwgYGRpc2Nvbm5lY3RgLCBgc3Vic2NyaWJlYCwgYHVuc3Vic2NyaWJlYCwgYHB1Ymxpc2hgLCBgZXJyb3JgLlxuICAgICAqXG4gICAgICogKipQYXJhbWV0ZXJzKipcbiAgICAgKlxuICAgICAqIEBwYXJhbSB7c3RyaW5nfSBgZXZlbnRgIFRoZSBldmVudCB0eXBlLiBTZWUgbW9yZSBkZXRhaWwgYXQgalF1ZXJ5IEV2ZW50czogaHR0cDovL2FwaS5qcXVlcnkuY29tL29uLy5cbiAgICAgKi9cbiAgICBvbjogZnVuY3Rpb24gKGV2ZW50KSB7XG4gICAgICAgICQodGhpcykub24uYXBwbHkoJCh0aGlzKSwgYXJndW1lbnRzKTtcbiAgICB9LFxuXG4gICAgLyoqXG4gICAgICogU3RvcCBsaXN0ZW5pbmcgZm9yIGV2ZW50cyBvbiB0aGlzIGluc3RhbmNlLiBTaWduYXR1cmUgaXMgc2FtZSBhcyBmb3IgalF1ZXJ5IEV2ZW50czogaHR0cDovL2FwaS5qcXVlcnkuY29tL29mZi8uXG4gICAgICpcbiAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAqXG4gICAgICogQHBhcmFtIHtzdHJpbmd9IGBldmVudGAgVGhlIGV2ZW50IHR5cGUuIFNlZSBtb3JlIGRldGFpbCBhdCBqUXVlcnkgRXZlbnRzOiBodHRwOi8vYXBpLmpxdWVyeS5jb20vb2ZmLy5cbiAgICAgKi9cbiAgICBvZmY6IGZ1bmN0aW9uIChldmVudCkge1xuICAgICAgICAkKHRoaXMpLm9mZi5hcHBseSgkKHRoaXMpLCBhcmd1bWVudHMpO1xuICAgIH0sXG5cbiAgICAvKipcbiAgICAgKiBUcmlnZ2VyIGV2ZW50cyBhbmQgZXhlY3V0ZSBoYW5kbGVycy4gU2lnbmF0dXJlIGlzIHNhbWUgYXMgZm9yIGpRdWVyeSBFdmVudHM6IGh0dHA6Ly9hcGkuanF1ZXJ5LmNvbS90cmlnZ2VyLy5cbiAgICAgKlxuICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICpcbiAgICAgKiBAcGFyYW0ge3N0cmluZ30gYGV2ZW50YCBUaGUgZXZlbnQgdHlwZS4gU2VlIG1vcmUgZGV0YWlsIGF0IGpRdWVyeSBFdmVudHM6IGh0dHA6Ly9hcGkuanF1ZXJ5LmNvbS90cmlnZ2VyLy5cbiAgICAgKi9cbiAgICB0cmlnZ2VyOiBmdW5jdGlvbiAoZXZlbnQpIHtcbiAgICAgICAgJCh0aGlzKS50cmlnZ2VyLmFwcGx5KCQodGhpcyksIGFyZ3VtZW50cyk7XG4gICAgfVxuXG59KTtcblxubW9kdWxlLmV4cG9ydHMgPSBDaGFubmVsO1xuIiwiLyoqXG4gKiBAY2xhc3MgQ29uZmlndXJhdGlvblNlcnZpY2VcbiAqXG4gKiBBbGwgc2VydmljZXMgdGFrZSBpbiBhIGNvbmZpZ3VyYXRpb24gc2V0dGluZ3Mgb2JqZWN0IHRvIGNvbmZpZ3VyZSB0aGVtc2VsdmVzLiBBIEpTIGhhc2gge30gaXMgYSB2YWxpZCBjb25maWd1cmF0aW9uIG9iamVjdCwgYnV0IG9wdGlvbmFsbHkgeW91IGNhbiB1c2UgdGhlIGNvbmZpZ3VyYXRpb24gc2VydmljZSB0byB0b2dnbGUgY29uZmlncyBiYXNlZCBvbiB0aGUgZW52aXJvbm1lbnRcbiAqXG4gKiBAZXhhbXBsZVxuICogICAgIHZhciBjcyA9IHJlcXVpcmUoJ2NvbmZpZ3VyYXRpb24tc2VydmljZScpKHtcbiAqICAgICAgICAgIGRldjogeyAvL2Vudmlyb25tZW50XG4gICAgICAgICAgICAgICAgcG9ydDogMzAwMCxcbiAgICAgICAgICAgICAgICBob3N0OiAnbG9jYWxob3N0JyxcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICBwcm9kOiB7XG4gICAgICAgICAgICAgICAgcG9ydDogODA4MCxcbiAgICAgICAgICAgICAgICBob3N0OiAnYXBpLmZvcmlvLmNvbScsXG4gICAgICAgICAgICAgICAgbG9nTGV2ZWw6ICdub25lJ1xuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIGxvZ0xldmVsOiAnREVCVUcnIC8vZ2xvYmFsXG4gKiAgICAgfSk7XG4gKlxuICogICAgICBjcy5nZXQoJ2xvZ0xldmVsJyk7IC8vcmV0dXJucyAnREVCVUcnXG4gKlxuICogICAgICBjcy5zZXRFbnYoJ2RldicpO1xuICogICAgICBjcy5nZXQoJ2xvZ0xldmVsJyk7IC8vcmV0dXJucyAnREVCVUcnXG4gKlxuICogICAgICBjcy5zZXRFbnYoJ3Byb2QnKTtcbiAqICAgICAgY3MuZ2V0KCdsb2dMZXZlbCcpOyAvL3JldHVybnMgJ25vbmUnXG4gKlxuICovXG5cbid1c2Ugc3RyaWN0JztcbnZhciB1cmxTZXJ2aWNlID0gcmVxdWlyZSgnLi91cmwtY29uZmlnLXNlcnZpY2UnKTtcblxubW9kdWxlLmV4cG9ydHMgPSBmdW5jdGlvbiAoY29uZmlnKSB7XG4gICAgLy9UT0RPOiBFbnZpcm9ubWVudHNcbiAgICB2YXIgZGVmYXVsdHMgPSB7XG4gICAgICAgIGxvZ0xldmVsOiAnTk9ORSdcbiAgICB9O1xuICAgIHZhciBzZXJ2aWNlT3B0aW9ucyA9ICQuZXh0ZW5kKHt9LCBkZWZhdWx0cywgY29uZmlnKTtcbiAgICBzZXJ2aWNlT3B0aW9ucy5zZXJ2ZXIgPSB1cmxTZXJ2aWNlKHNlcnZpY2VPcHRpb25zLnNlcnZlcik7XG5cbiAgICByZXR1cm4ge1xuXG4gICAgICAgIGRhdGE6IHNlcnZpY2VPcHRpb25zLFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBTZXQgdGhlIGVudmlyb25tZW50IGtleSB0byBnZXQgY29uZmlndXJhdGlvbiBvcHRpb25zIGZyb21cbiAgICAgICAgICogQHBhcmFtIHsgc3RyaW5nfSBlbnZcbiAgICAgICAgICovXG4gICAgICAgIHNldEVudjogZnVuY3Rpb24gKGVudikge1xuXG4gICAgICAgIH0sXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIEdldCBjb25maWd1cmF0aW9uLlxuICAgICAgICAgKiBAcGFyYW0gIHsgc3RyaW5nfSBwcm9wZXJ0eSBvcHRpb25hbFxuICAgICAgICAgKiBAcmV0dXJuIHsqfSAgICAgICAgICBWYWx1ZSBvZiBwcm9wZXJ0eSBpZiBzcGVjaWZpZWQsIHRoZSBlbnRpcmUgY29uZmlnIG9iamVjdCBvdGhlcndpc2VcbiAgICAgICAgICovXG4gICAgICAgIGdldDogZnVuY3Rpb24gKHByb3BlcnR5KSB7XG4gICAgICAgICAgICByZXR1cm4gc2VydmljZU9wdGlvbnNbcHJvcGVydHldO1xuICAgICAgICB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBTZXQgY29uZmlndXJhdGlvbi5cbiAgICAgICAgICogQHBhcmFtICB7IHN0cmluZ3xPYmplY3R9IGtleSBpZiBhIGtleSBpcyBwcm92aWRlZCwgc2V0IGEga2V5IHRvIHRoYXQgdmFsdWUuIE90aGVyd2lzZSBtZXJnZSBvYmplY3Qgd2l0aCBjdXJyZW50IGNvbmZpZ1xuICAgICAgICAgKiBAcGFyYW0gIHsqfSB2YWx1ZSAgdmFsdWUgZm9yIHByb3ZpZGVkIGtleVxuICAgICAgICAgKi9cbiAgICAgICAgc2V0OiBmdW5jdGlvbiAoa2V5LCB2YWx1ZSkge1xuICAgICAgICAgICAgc2VydmljZU9wdGlvbnNba2V5XSA9IHZhbHVlO1xuICAgICAgICB9XG4gICAgfTtcbn07XG5cbiIsIi8qKlxuICogIyMgRGF0YSBBUEkgU2VydmljZVxuICpcbiAqIFRoZSBEYXRhIEFQSSBTZXJ2aWNlIGFsbG93cyB5b3UgdG8gY3JlYXRlLCBhY2Nlc3MsIGFuZCBtYW5pcHVsYXRlIGRhdGEgcmVsYXRlZCB0byBhbnkgb2YgeW91ciBwcm9qZWN0cy4gRGF0YSBhcmUgb3JnYW5pemVkIGluIGNvbGxlY3Rpb25zLiBFYWNoIGNvbGxlY3Rpb24gY29udGFpbnMgYSBkb2N1bWVudDsgZWFjaCBlbGVtZW50IG9mIHRoaXMgdG9wLWxldmVsIGRvY3VtZW50IGlzIGEgSlNPTiBvYmplY3QuIChTZWUgYWRkaXRpb25hbCBpbmZvcm1hdGlvbiBvbiB0aGUgdW5kZXJseWluZyBbRGF0YSBBUEldKC4uLy4uLy4uL3Jlc3RfYXBpcy9kYXRhX2FwaS8pLilcbiAqXG4gKiBBbGwgQVBJIGNhbGxzIHRha2UgaW4gYW4gXCJvcHRpb25zXCIgb2JqZWN0IGFzIHRoZSBsYXN0IHBhcmFtZXRlci4gVGhlIG9wdGlvbnMgY2FuIGJlIHVzZWQgdG8gZXh0ZW5kL292ZXJyaWRlIHRoZSBEYXRhIEFQSSBTZXJ2aWNlIGRlZmF1bHRzLiBJbiBwYXJ0aWN1bGFyLCB0aGVyZSBhcmUgdGhyZWUgcmVxdWlyZWQgcGFyYW1ldGVycyB3aGVuIHlvdSBpbnN0YW50aWF0ZSB0aGUgRGF0YSBTZXJ2aWNlOlxuICpcbiAqICogYGFjY291bnRgOiBFcGljZW50ZXIgYWNjb3VudCBpZCAoKipUZWFtIElEKiogZm9yIHRlYW0gcHJvamVjdHMsICoqVXNlciBJRCoqIGZvciBwZXJzb25hbCBwcm9qZWN0cykuXG4gKiAqIGBwcm9qZWN0YDogRXBpY2VudGVyIHByb2plY3QgaWQuXG4gKiAqIGByb290YDogVGhlIHRoZSBuYW1lIG9mIHRoZSBjb2xsZWN0aW9uLiBJZiB5b3UgaGF2ZSBtdWx0aXBsZSBjb2xsZWN0aW9ucyB3aXRoaW4gZWFjaCBvZiB5b3VyIHByb2plY3RzLCB5b3UgY2FuIGFsc28gcGFzcyB0aGUgY29sbGVjdGlvbiBuYW1lIGFzIGFuIG9wdGlvbiBmb3IgZWFjaCBjYWxsLlxuICpcbiAqICAgICAgIHZhciBkcyA9IG5ldyBGLnNlcnZpY2UuRGF0YSh7XG4gKiAgICAgICAgICBhY2NvdW50OiAnYWNtZS1zaW11bGF0aW9ucycsXG4gKiAgICAgICAgICBwcm9qZWN0OiAnc3VwcGx5LWNoYWluLWdhbWUnLFxuICogICAgICAgICAgcm9vdDogJ3N1cnZleS1yZXNwb25zZXMnLFxuICogICAgICAgICAgc2VydmVyOiB7IGhvc3Q6ICdhcGkuZm9yaW8uY29tJyB9XG4gKiAgICAgICB9KTtcbiAqICAgICAgIGRzLnNhdmVBcygndXNlcjEnLFxuICogICAgICAgICAgeyAncXVlc3Rpb24xJzogMiwgJ3F1ZXN0aW9uMic6IDEwLFxuICogICAgICAgICAgJ3F1ZXN0aW9uMyc6IGZhbHNlLCAncXVlc3Rpb240JzogJ3NvbWV0aW1lcycgfSApO1xuICogICAgICAgZHMuc2F2ZUFzKCd1c2VyMicsXG4gKiAgICAgICAgICB7ICdxdWVzdGlvbjEnOiAzLCAncXVlc3Rpb24yJzogOCxcbiAqICAgICAgICAgICdxdWVzdGlvbjMnOiB0cnVlLCAncXVlc3Rpb240JzogJ2Fsd2F5cycgfSApO1xuICogICAgICAgZHMucXVlcnkoJycseyAncXVlc3Rpb24yJzogeyAnJGd0JzogOX0gfSk7XG4gKlxuICogTm90ZSB0aGF0IGluIGFkZGl0aW9uIHRvIHRoZSBgYWNjb3VudGAsIGBwcm9qZWN0YCwgYW5kIGByb290YCwgdGhlIERhdGEgU2VydmljZSBwYXJhbWV0ZXJzIG9wdGlvbmFsbHkgaW5jbHVkZSBhIGBzZXJ2ZXJgIG9iamVjdCwgd2hvc2UgYGhvc3RgIGZpZWxkIGNvbnRhaW5zIHRoZSBVUkkgb2YgdGhlIEZvcmlvIHNlcnZlci4gVGhpcyBpcyBhdXRvbWF0aWNhbGx5IHNldCwgYnV0IHlvdSBjYW4gcGFzcyBpdCBleHBsaWNpdGx5IGlmIGRlc2lyZWQuIEl0IGlzIG1vc3QgY29tbW9ubHkgdXNlZCBmb3IgY2xhcml0eSB3aGVuIHlvdSBhcmUgW2hvc3RpbmcgYW4gRXBpY2VudGVyIHByb2plY3Qgb24geW91ciBvd24gc2VydmVyXSguLi8uLi8uLi9ob3dfdG8vc2VsZl9ob3N0aW5nLykuXG4gKi9cblxuJ3VzZSBzdHJpY3QnO1xuXG52YXIgQ29uZmlnU2VydmljZSA9IHJlcXVpcmUoJy4vY29uZmlndXJhdGlvbi1zZXJ2aWNlJyk7XG52YXIgcXV0aWwgPSByZXF1aXJlKCcuLi91dGlsL3F1ZXJ5LXV0aWwnKTtcbnZhciBUcmFuc3BvcnRGYWN0b3J5ID0gcmVxdWlyZSgnLi4vdHJhbnNwb3J0L2h0dHAtdHJhbnNwb3J0LWZhY3RvcnknKTtcbnZhciBTZXNzaW9uTWFuYWdlciA9IHJlcXVpcmUoJy4uL3N0b3JlL3Nlc3Npb24tbWFuYWdlcicpO1xuXG5tb2R1bGUuZXhwb3J0cyA9IGZ1bmN0aW9uIChjb25maWcpIHtcbiAgICB2YXIgZGVmYXVsdHMgPSB7XG4gICAgICAgIC8qKlxuICAgICAgICAgKiBOYW1lIG9mIGNvbGxlY3Rpb24uIERlZmF1bHRzIHRvIGAvYCwgdGhhdCBpcywgdGhlIHJvb3QgbGV2ZWwgb2YgeW91ciBwcm9qZWN0IGF0IGBmb3Jpby5jb20vYXBwL3lvdXItYWNjb3VudC1pZC95b3VyLXByb2plY3QtaWQvYC4gUmVxdWlyZWQuXG4gICAgICAgICAqIEB0eXBlIHtTdHJpbmd9XG4gICAgICAgICAqL1xuICAgICAgICByb290OiAnLycsXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIFRoZSBhY2NvdW50IGlkLiBJbiB0aGUgRXBpY2VudGVyIFVJLCB0aGlzIGlzIHRoZSAqKlRlYW0gSUQqKiAoZm9yIHRlYW0gcHJvamVjdHMpIG9yICoqVXNlciBJRCoqIChmb3IgcGVyc29uYWwgcHJvamVjdHMpLiBEZWZhdWx0cyB0byBlbXB0eSBzdHJpbmcuIElmIGxlZnQgdW5kZWZpbmVkLCB0YWtlbiBmcm9tIHRoZSBVUkwuXG4gICAgICAgICAqIEB0eXBlIHtTdHJpbmd9XG4gICAgICAgICAqL1xuICAgICAgICBhY2NvdW50OiB1bmRlZmluZWQsXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIFRoZSBwcm9qZWN0IGlkLiBEZWZhdWx0cyB0byBlbXB0eSBzdHJpbmcuIElmIGxlZnQgdW5kZWZpbmVkLCB0YWtlbiBmcm9tIHRoZSBVUkwuXG4gICAgICAgICAqIEB0eXBlIHtTdHJpbmd9XG4gICAgICAgICAqL1xuICAgICAgICBwcm9qZWN0OiB1bmRlZmluZWQsXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIEZvciBvcGVyYXRpb25zIHRoYXQgcmVxdWlyZSBhdXRoZW50aWNhdGlvbiwgcGFzcyBpbiB0aGUgdXNlciBhY2Nlc3MgdG9rZW4gKGRlZmF1bHRzIHRvIGVtcHR5IHN0cmluZykuIElmIHRoZSB1c2VyIGlzIGFscmVhZHkgbG9nZ2VkIGluIHRvIEVwaWNlbnRlciwgdGhlIHVzZXIgYWNjZXNzIHRva2VuIGlzIGFscmVhZHkgc2V0IGluIGEgY29va2llIGFuZCBhdXRvbWF0aWNhbGx5IGxvYWRlZCBmcm9tIHRoZXJlLiAoU2VlIFttb3JlIGJhY2tncm91bmQgb24gYWNjZXNzIHRva2Vuc10oLi4vLi4vLi4vcHJvamVjdF9hY2Nlc3MvKSkuXG4gICAgICAgICAqIEBzZWUgW0F1dGhlbnRpY2F0aW9uIEFQSSBTZXJ2aWNlXSguLi9hdXRoLWFwaS1zZXJ2aWNlLykgZm9yIGdldHRpbmcgdG9rZW5zLlxuICAgICAgICAgKiBAdHlwZSB7U3RyaW5nfVxuICAgICAgICAgKi9cbiAgICAgICAgdG9rZW46IHVuZGVmaW5lZCxcblxuICAgICAgICAvL09wdGlvbnMgdG8gcGFzcyBvbiB0byB0aGUgdW5kZXJseWluZyB0cmFuc3BvcnQgbGF5ZXJcbiAgICAgICAgdHJhbnNwb3J0OiB7fVxuICAgIH07XG4gICAgdGhpcy5zZXNzaW9uTWFuYWdlciA9IG5ldyBTZXNzaW9uTWFuYWdlcigpO1xuICAgIHZhciBzZXJ2aWNlT3B0aW9ucyA9IHRoaXMuc2Vzc2lvbk1hbmFnZXIuZ2V0TWVyZ2VkT3B0aW9ucyhkZWZhdWx0cywgY29uZmlnKTtcblxuICAgIHZhciB1cmxDb25maWcgPSBuZXcgQ29uZmlnU2VydmljZShzZXJ2aWNlT3B0aW9ucykuZ2V0KCdzZXJ2ZXInKTtcbiAgICBpZiAoc2VydmljZU9wdGlvbnMuYWNjb3VudCkge1xuICAgICAgICB1cmxDb25maWcuYWNjb3VudFBhdGggPSBzZXJ2aWNlT3B0aW9ucy5hY2NvdW50O1xuICAgIH1cbiAgICBpZiAoc2VydmljZU9wdGlvbnMucHJvamVjdCkge1xuICAgICAgICB1cmxDb25maWcucHJvamVjdFBhdGggPSBzZXJ2aWNlT3B0aW9ucy5wcm9qZWN0O1xuICAgIH1cblxuICAgIHZhciBnZXRVUkwgPSBmdW5jdGlvbiAoa2V5LCByb290KSB7XG4gICAgICAgIGlmICghcm9vdCkge1xuICAgICAgICAgICAgcm9vdCA9IHNlcnZpY2VPcHRpb25zLnJvb3Q7XG4gICAgICAgIH1cbiAgICAgICAgdmFyIHVybCA9IHVybENvbmZpZy5nZXRBUElQYXRoKCdkYXRhJykgKyBxdXRpbC5hZGRUcmFpbGluZ1NsYXNoKHJvb3QpO1xuICAgICAgICBpZiAoa2V5KSB7XG4gICAgICAgICAgICB1cmwrPSBxdXRpbC5hZGRUcmFpbGluZ1NsYXNoKGtleSk7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIHVybDtcbiAgICB9O1xuXG4gICAgdmFyIGh0dHBPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sIHNlcnZpY2VPcHRpb25zLnRyYW5zcG9ydCwge1xuICAgICAgICB1cmw6IGdldFVSTFxuICAgIH0pO1xuICAgIGlmIChzZXJ2aWNlT3B0aW9ucy50b2tlbikge1xuICAgICAgICBodHRwT3B0aW9ucy5oZWFkZXJzID0ge1xuICAgICAgICAgICAgJ0F1dGhvcml6YXRpb24nOiAnQmVhcmVyICcgKyBzZXJ2aWNlT3B0aW9ucy50b2tlblxuICAgICAgICB9O1xuICAgIH1cbiAgICB2YXIgaHR0cCA9IG5ldyBUcmFuc3BvcnRGYWN0b3J5KGh0dHBPcHRpb25zKTtcblxuICAgIHZhciBwdWJsaWNBUEkgPSB7XG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIFNlYXJjaCBmb3IgZGF0YSB3aXRoaW4gYSBjb2xsZWN0aW9uLlxuICAgICAgICAgKlxuICAgICAgICAgKiBTZWFyY2hpbmcgdXNpbmcgY29tcGFyaXNvbiBvciBsb2dpY2FsIG9wZXJhdG9ycyAoYXMgb3Bwb3NlZCB0byBleGFjdCBtYXRjaGVzKSByZXF1aXJlcyBNb25nb0RCIHN5bnRheC4gU2VlIHRoZSB1bmRlcmx5aW5nIFtEYXRhIEFQSV0oLi4vLi4vLi4vcmVzdF9hcGlzL2RhdGFfYXBpLyNzZWFyY2hpbmcpIGZvciBhZGRpdGlvbmFsIGRldGFpbHMuXG4gICAgICAgICAqXG4gICAgICAgICAqICoqRXhhbXBsZXMqKlxuICAgICAgICAgKlxuICAgICAgICAgKiAgICAgIC8vIHJlcXVlc3QgYWxsIGRhdGEgYXNzb2NpYXRlZCB3aXRoIGRvY3VtZW50ICd1c2VyMSdcbiAgICAgICAgICogICAgICBkcy5xdWVyeSgndXNlcjEnKTtcbiAgICAgICAgICpcbiAgICAgICAgICogICAgICAvLyBleGFjdCBtYXRjaGluZzpcbiAgICAgICAgICogICAgICAvLyByZXF1ZXN0IGFsbCBkb2N1bWVudHMgaW4gY29sbGVjdGlvbiB3aGVyZSAncXVlc3Rpb24yJyBpcyA5XG4gICAgICAgICAqICAgICAgZHMucXVlcnkoJycsIHsgJ3F1ZXN0aW9uMic6IDl9KTtcbiAgICAgICAgICpcbiAgICAgICAgICogICAgICAvLyBjb21wYXJpc29uIG9wZXJhdG9yczpcbiAgICAgICAgICogICAgICAvLyByZXF1ZXN0IGFsbCBkb2N1bWVudHMgaW4gY29sbGVjdGlvblxuICAgICAgICAgKiAgICAgIC8vIHdoZXJlICdxdWVzdGlvbjInIGlzIGdyZWF0ZXIgdGhhbiA5XG4gICAgICAgICAqICAgICAgZHMucXVlcnkoJycsIHsgJ3F1ZXN0aW9uMic6IHsgJyRndCc6IDl9IH0pO1xuICAgICAgICAgKlxuICAgICAgICAgKiAgICAgIC8vIGxvZ2ljYWwgb3BlcmF0b3JzOlxuICAgICAgICAgKiAgICAgIC8vIHJlcXVlc3QgYWxsIGRvY3VtZW50cyBpbiBjb2xsZWN0aW9uXG4gICAgICAgICAqICAgICAgLy8gd2hlcmUgJ3F1ZXN0aW9uMicgaXMgbGVzcyB0aGFuIDEwLCBhbmQgJ3F1ZXN0aW9uMycgaXMgZmFsc2VcbiAgICAgICAgICogICAgICBkcy5xdWVyeSgnJywgeyAnJGFuZCc6IFsgeyAncXVlc3Rpb24yJzogeyAnJGx0JzoxMH0gfSwgeyAncXVlc3Rpb24zJzogZmFsc2UgfV0gfSk7XG4gICAgICAgICAqXG4gICAgICAgICAqICAgICAgLy8gcmVndWxhciBleHByZXNzc2lvbnM6IHVzZSBhbnkgUGVybC1jb21wYXRpYmxlIHJlZ3VsYXIgZXhwcmVzc2lvbnNcbiAgICAgICAgICogICAgICAvLyByZXF1ZXN0IGFsbCBkb2N1bWVudHMgaW4gY29sbGVjdGlvblxuICAgICAgICAgKiAgICAgIC8vIHdoZXJlICdxdWVzdGlvbjUnIGNvbnRhaW5zIHRoZSBzdHJpbmcgJy4qZGF5J1xuICAgICAgICAgKiAgICAgIGRzLnF1ZXJ5KCcnLCB7ICdxdWVzdGlvbjUnOiB7ICckcmVnZXgnOiAnLipkYXknIH0gfSk7XG4gICAgICAgICAqXG4gICAgICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICAgICAqIEBwYXJhbSB7U3RyaW5nfSBga2V5YCBUaGUgbmFtZSBvZiB0aGUgZG9jdW1lbnQgdG8gc2VhcmNoLiBQYXNzIHRoZSBlbXB0eSBzdHJpbmcgKCcnKSB0byBzZWFyY2ggdGhlIGVudGlyZSBjb2xsZWN0aW9uLlxuICAgICAgICAgKiBAcGFyYW0ge09iamVjdH0gYHF1ZXJ5YCBUaGUgcXVlcnkgb2JqZWN0LiBGb3IgZXhhY3QgbWF0Y2hpbmcsIHRoaXMgb2JqZWN0IGNvbnRhaW5zIHRoZSBmaWVsZCBuYW1lIGFuZCBmaWVsZCB2YWx1ZSB0byBtYXRjaC4gRm9yIG1hdGNoaW5nIGJhc2VkIG9uIGNvbXBhcmlzb24sIHRoaXMgb2JqZWN0IGNvbnRhaW5zIHRoZSBmaWVsZCBuYW1lIGFuZCB0aGUgY29tcGFyaXNvbiBleHByZXNzaW9uLiBGb3IgbWF0Y2hpbmcgYmFzZWQgb24gbG9naWNhbCBvcGVyYXRvcnMsIHRoaXMgb2JqZWN0IGNvbnRhaW5zIGFuIGV4cHJlc3Npb24gdXNpbmcgTW9uZ29EQiBzeW50YXguIFNlZSB0aGUgdW5kZXJseWluZyBbRGF0YSBBUEldKC4uLy4uLy4uL3Jlc3RfYXBpcy9kYXRhX2FwaS8jc2VhcmNoaW5nKSBmb3IgYWRkaXRpb25hbCBleGFtcGxlcy5cbiAgICAgICAgICogQHBhcmFtIHtPYmplY3R9IGBvdXRwdXRNb2RpZmllcmAgKE9wdGlvbmFsKSBBdmFpbGFibGUgZmllbGRzIGluY2x1ZGU6IGBzdGFydHJlY29yZGAsIGBlbmRyZWNvcmRgLCBgc29ydGAsIGFuZCBgZGlyZWN0aW9uYCAoYGFzY2Agb3IgYGRlc2NgKS5cbiAgICAgICAgICogQHBhcmFtIHtPYmplY3R9IGBvcHRpb25zYCAoT3B0aW9uYWwpIE92ZXJyaWRlcyBmb3IgY29uZmlndXJhdGlvbiBvcHRpb25zLlxuICAgICAgICAgKlxuICAgICAgICAgKi9cbiAgICAgICAgcXVlcnk6IGZ1bmN0aW9uIChrZXksIHF1ZXJ5LCBvdXRwdXRNb2RpZmllciwgb3B0aW9ucykge1xuICAgICAgICAgICAgdmFyIHBhcmFtcyA9ICQuZXh0ZW5kKHRydWUsIHsgcTogcXVlcnkgfSwgb3V0cHV0TW9kaWZpZXIpO1xuICAgICAgICAgICAgdmFyIGh0dHBPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sIHNlcnZpY2VPcHRpb25zLCBvcHRpb25zKTtcbiAgICAgICAgICAgIGh0dHBPcHRpb25zLnVybCA9IGdldFVSTChrZXksIGh0dHBPcHRpb25zLnJvb3QpO1xuICAgICAgICAgICAgcmV0dXJuIGh0dHAuZ2V0KHBhcmFtcywgaHR0cE9wdGlvbnMpO1xuICAgICAgICB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBTYXZlIGRhdGEgdG8gYW4gYW5vbnltb3VzIGRvY3VtZW50IHdpdGhpbiB0aGUgY29sbGVjdGlvbi5cbiAgICAgICAgICpcbiAgICAgICAgICogKERvY3VtZW50cyBhcmUgdG9wLWxldmVsIGVsZW1lbnRzIHdpdGhpbiBhIGNvbGxlY3Rpb24uIENvbGxlY3Rpb25zIG11c3QgYmUgdW5pcXVlIHdpdGhpbiB0aGlzIGFjY291bnQgKHRlYW0gb3IgcGVyc29uYWwgYWNjb3VudCkgYW5kIHByb2plY3QgYW5kIGFyZSBzZXQgd2l0aCB0aGUgYHJvb3RgIGZpZWxkIGluIHRoZSBgb3B0aW9uYCBwYXJhbWV0ZXIuIFNlZSB0aGUgdW5kZXJseWluZyBbRGF0YSBBUEldKC4uLy4uLy4uL3Jlc3RfYXBpcy9kYXRhX2FwaS8pIGZvciBhZGRpdGlvbmFsIGJhY2tncm91bmQuKVxuICAgICAgICAgKlxuICAgICAgICAgKiAqKkV4YW1wbGUqKlxuICAgICAgICAgKlxuICAgICAgICAgKiAgICAgIGRzLnNhdmUoJ3F1ZXN0aW9uMScsICd5ZXMnKTtcbiAgICAgICAgICogICAgICBkcy5zYXZlKHtxdWVzdGlvbjE6J3llcycsIHF1ZXN0aW9uMjogMzIgfSk7XG4gICAgICAgICAqICAgICAgZHMuc2F2ZSh7IG5hbWU6J0pvaG4nLCBjbGFzc05hbWU6ICdDUzEwMScgfSwgeyByb290OiAnc3R1ZGVudHMnIH0pO1xuICAgICAgICAgKlxuICAgICAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAgKlxuICAgICAgICAgKiBAcGFyYW0ge1N0cmluZ3xPYmplY3R9IGBrZXlgIElmIGBrZXlgIGlzIGEgc3RyaW5nLCBpdCBpcyB0aGUgaWQgb2YgdGhlIGVsZW1lbnQgdG8gc2F2ZSAoY3JlYXRlKSBpbiB0aGlzIGRvY3VtZW50LiBJZiBga2V5YCBpcyBhbiBvYmplY3QsIHRoZSBvYmplY3QgaXMgdGhlIGRhdGEgdG8gc2F2ZSAoY3JlYXRlKSBpbiB0aGlzIGRvY3VtZW50LiBJbiBib3RoIGNhc2VzLCB0aGUgaWQgZm9yIHRoZSBkb2N1bWVudCBpcyBnZW5lcmF0ZWQgYXV0b21hdGljYWxseS5cbiAgICAgICAgICogQHBhcmFtIHtPYmplY3R9IGB2YWx1ZWAgKE9wdGlvbmFsKSBUaGUgZGF0YSB0byBzYXZlLiBJZiBga2V5YCBpcyBhIHN0cmluZywgdGhpcyBpcyB0aGUgdmFsdWUgdG8gc2F2ZS4gSWYgYGtleWAgaXMgYW4gb2JqZWN0LCB0aGUgdmFsdWUocykgdG8gc2F2ZSBhcmUgYWxyZWFkeSBwYXJ0IG9mIGBrZXlgIGFuZCB0aGlzIGFyZ3VtZW50IGlzIG5vdCByZXF1aXJlZC5cbiAgICAgICAgICogQHBhcmFtIHtPYmplY3R9IGBvcHRpb25zYCAoT3B0aW9uYWwpIE92ZXJyaWRlcyBmb3IgY29uZmlndXJhdGlvbiBvcHRpb25zLlxuICAgICAgICAgKi9cbiAgICAgICAgc2F2ZTogZnVuY3Rpb24gKGtleSwgdmFsdWUsIG9wdGlvbnMpIHtcbiAgICAgICAgICAgIHZhciBhdHRycztcbiAgICAgICAgICAgIGlmICh0eXBlb2Yga2V5ID09PSAnb2JqZWN0Jykge1xuICAgICAgICAgICAgICAgIGF0dHJzID0ga2V5O1xuICAgICAgICAgICAgICAgIG9wdGlvbnMgPSB2YWx1ZTtcbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgKGF0dHJzID0ge30pW2tleV0gPSB2YWx1ZTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHZhciBodHRwT3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LCBzZXJ2aWNlT3B0aW9ucywgb3B0aW9ucyk7XG4gICAgICAgICAgICBodHRwT3B0aW9ucy51cmwgPSBnZXRVUkwoJycsIGh0dHBPcHRpb25zLnJvb3QpO1xuXG4gICAgICAgICAgICByZXR1cm4gaHR0cC5wb3N0KGF0dHJzLCBodHRwT3B0aW9ucyk7XG4gICAgICAgIH0sXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIFNhdmUgZGF0YSB0byBhIG5hbWVkIGRvY3VtZW50IG9yIGVsZW1lbnQgd2l0aGluIHRoZSBjb2xsZWN0aW9uLiBUaGUgYHJvb3RgIG9mIHRoZSBjb2xsZWN0aW9uIG11c3QgYmUgc3BlY2lmaWVkIHNlcGFyYXRlbHkgaW4gY29uZmlndXJhdGlvbiBvcHRpb25zLCBlaXRoZXIgYXMgcGFydCBvZiB0aGUgY2FsbCBvciBhcyBwYXJ0IG9mIHRoZSBpbml0aWFsaXphdGlvbiBvZiBkcy5cbiAgICAgICAgICpcbiAgICAgICAgICogKERvY3VtZW50cyBhcmUgdG9wLWxldmVsIGVsZW1lbnRzIHdpdGhpbiBhIGNvbGxlY3Rpb24uIENvbGxlY3Rpb25zIG11c3QgYmUgdW5pcXVlIHdpdGhpbiB0aGlzIGFjY291bnQgKHRlYW0gb3IgcGVyc29uYWwgYWNjb3VudCkgYW5kIHByb2plY3QgYW5kIGFyZSBzZXQgd2l0aCB0aGUgYHJvb3RgIGZpZWxkIGluIHRoZSBgb3B0aW9uYCBwYXJhbWV0ZXIuIFNlZSB0aGUgdW5kZXJseWluZyBbRGF0YSBBUEldKC4uLy4uLy4uL3Jlc3RfYXBpcy9kYXRhX2FwaS8pIGZvciBhZGRpdGlvbmFsIGJhY2tncm91bmQuKVxuICAgICAgICAgKlxuICAgICAgICAgKiAqKkV4YW1wbGUqKlxuICAgICAgICAgKlxuICAgICAgICAgKiAgICAgIGRzLnNhdmVBcygndXNlcjEnLFxuICAgICAgICAgKiAgICAgICAgICB7ICdxdWVzdGlvbjEnOiAyLCAncXVlc3Rpb24yJzogMTAsXG4gICAgICAgICAqICAgICAgICAgICAncXVlc3Rpb24zJzogZmFsc2UsICdxdWVzdGlvbjQnOiAnc29tZXRpbWVzJyB9ICk7XG4gICAgICAgICAqICAgICAgZHMuc2F2ZUFzKCdzdHVkZW50MScsXG4gICAgICAgICAqICAgICAgICAgIHsgZmlyc3ROYW1lOiAnam9obicsIGxhc3ROYW1lOiAnc21pdGgnIH0sXG4gICAgICAgICAqICAgICAgICAgIHsgcm9vdDogJ3N0dWRlbnRzJyB9KTtcbiAgICAgICAgICogICAgICBkcy5zYXZlQXMoJ21nbXQxMDAvZ3JvdXBCJyxcbiAgICAgICAgICogICAgICAgICAgeyBzY2VuYXJpb1llYXI6ICcyMDE1JyB9LFxuICAgICAgICAgKiAgICAgICAgICB7IHJvb3Q6ICdteWNsYXNzZXMnIH0pO1xuICAgICAgICAgKlxuICAgICAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAgKlxuICAgICAgICAgKiBAcGFyYW0ge1N0cmluZ30gYGtleWAgSWQgb2YgdGhlIGRvY3VtZW50LlxuICAgICAgICAgKiBAcGFyYW0ge09iamVjdH0gYHZhbHVlYCAoT3B0aW9uYWwpIFRoZSBkYXRhIHRvIHNhdmUsIGluIGtleTp2YWx1ZSBwYWlycy5cbiAgICAgICAgICogQHBhcmFtIHtPYmplY3R9IGBvcHRpb25zYCAoT3B0aW9uYWwpIE92ZXJyaWRlcyBmb3IgY29uZmlndXJhdGlvbiBvcHRpb25zLlxuICAgICAgICAgKi9cbiAgICAgICAgc2F2ZUFzOiBmdW5jdGlvbiAoa2V5LCB2YWx1ZSwgb3B0aW9ucykge1xuICAgICAgICAgICAgdmFyIGh0dHBPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sIHNlcnZpY2VPcHRpb25zLCBvcHRpb25zKTtcbiAgICAgICAgICAgIGh0dHBPcHRpb25zLnVybCA9IGdldFVSTChrZXksIGh0dHBPcHRpb25zLnJvb3QpO1xuXG4gICAgICAgICAgICByZXR1cm4gaHR0cC5wdXQodmFsdWUsIGh0dHBPcHRpb25zKTtcbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgICogR2V0IGRhdGEgZm9yIGEgc3BlY2lmaWMgZG9jdW1lbnQgb3IgZmllbGQuXG4gICAgICAgICAqXG4gICAgICAgICAqICoqRXhhbXBsZSoqXG4gICAgICAgICAqXG4gICAgICAgICAqICAgICAgZHMubG9hZCgndXNlcjEnKTtcbiAgICAgICAgICogICAgICBkcy5sb2FkKCd1c2VyMS9xdWVzdGlvbjMnKTtcbiAgICAgICAgICpcbiAgICAgICAgICogKipQYXJhbWV0ZXJzKipcbiAgICAgICAgICogQHBhcmFtICB7U3RyaW5nfE9iamVjdH0gYGtleWAgVGhlIGlkIG9mIHRoZSBkYXRhIHRvIHJldHVybi4gQ2FuIGJlIHRoZSBpZCBvZiBhIGRvY3VtZW50LCBvciBhIHBhdGggdG8gZGF0YSB3aXRoaW4gdGhhdCBkb2N1bWVudC5cbiAgICAgICAgICogQHBhcmFtIHtPYmplY3R9IGBvdXRwdXRNb2RpZmllcmAgKE9wdGlvbmFsKSBBdmFpbGFibGUgZmllbGRzIGluY2x1ZGU6IGBzdGFydHJlY29yZGAsIGBlbmRyZWNvcmRgLCBgc29ydGAsIGFuZCBgZGlyZWN0aW9uYCAoYGFzY2Agb3IgYGRlc2NgKS5cbiAgICAgICAgICogQHBhcmFtIHtPYmplY3R9IGBvcHRpb25zYCBPdmVycmlkZXMgZm9yIGNvbmZpZ3VyYXRpb24gb3B0aW9ucy5cbiAgICAgICAgICovXG4gICAgICAgIGxvYWQ6IGZ1bmN0aW9uIChrZXksIG91dHB1dE1vZGlmaWVyLCBvcHRpb25zKSB7XG4gICAgICAgICAgICB2YXIgaHR0cE9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSwgc2VydmljZU9wdGlvbnMsIG9wdGlvbnMpO1xuICAgICAgICAgICAgaHR0cE9wdGlvbnMudXJsID0gZ2V0VVJMKGtleSwgaHR0cE9wdGlvbnMucm9vdCk7XG4gICAgICAgICAgICByZXR1cm4gaHR0cC5nZXQob3V0cHV0TW9kaWZpZXIsIGh0dHBPcHRpb25zKTtcbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgICogUmVtb3ZlcyBkYXRhIGZyb20gY29sbGVjdGlvbi4gT25seSBkb2N1bWVudHMgKHRvcC1sZXZlbCBlbGVtZW50cyBpbiBlYWNoIGNvbGxlY3Rpb24pIGNhbiBiZSBkZWxldGVkLlxuICAgICAgICAgKlxuICAgICAgICAgKiAqKkV4YW1wbGUqKlxuICAgICAgICAgKlxuICAgICAgICAgKiAgICAgZHMucmVtb3ZlKCd1c2VyMScpO1xuICAgICAgICAgKlxuICAgICAgICAgKlxuICAgICAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAgKlxuICAgICAgICAgKiBAcGFyYW0ge1N0cmluZ3xBcnJheX0gYGtleXNgIFRoZSBpZCBvZiB0aGUgZG9jdW1lbnQgdG8gcmVtb3ZlIGZyb20gdGhpcyBjb2xsZWN0aW9uLCBvciBhbiBhcnJheSBvZiBzdWNoIGlkcy5cbiAgICAgICAgICogQHBhcmFtIHtPYmplY3R9IGBvcHRpb25zYCAoT3B0aW9uYWwpIE92ZXJyaWRlcyBmb3IgY29uZmlndXJhdGlvbiBvcHRpb25zLlxuICAgICAgICAgKi9cbiAgICAgICAgcmVtb3ZlOiBmdW5jdGlvbiAoa2V5cywgb3B0aW9ucykge1xuICAgICAgICAgICAgdmFyIGh0dHBPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sIHNlcnZpY2VPcHRpb25zLCBvcHRpb25zKTtcbiAgICAgICAgICAgIHZhciBwYXJhbXM7XG4gICAgICAgICAgICBpZiAoJC5pc0FycmF5KGtleXMpKSB7XG4gICAgICAgICAgICAgICAgcGFyYW1zID0geyBpZDoga2V5cyB9O1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICBwYXJhbXMgPSAnJztcbiAgICAgICAgICAgICAgICBodHRwT3B0aW9ucy51cmwgPSBnZXRVUkwoa2V5cywgaHR0cE9wdGlvbnMucm9vdCk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICByZXR1cm4gaHR0cC5kZWxldGUocGFyYW1zLCBodHRwT3B0aW9ucyk7XG4gICAgICAgIH1cblxuICAgICAgICAvLyBFcGljZW50ZXIgZG9lc24ndCBhbGxvdyBudWtpbmcgY29sbGVjdGlvbnNcbiAgICAgICAgLy8gICAgIC8qKlxuICAgICAgICAvLyAgICAgICogUmVtb3ZlcyBjb2xsZWN0aW9uIGJlaW5nIHJlZmVyZW5jZWRcbiAgICAgICAgLy8gICAgICAqIEByZXR1cm4gbnVsbFxuICAgICAgICAvLyAgICAgICovXG4gICAgICAgIC8vICAgICBkZXN0cm95OiBmdW5jdGlvbiAob3B0aW9ucykge1xuICAgICAgICAvLyAgICAgICAgIHJldHVybiB0aGlzLnJlbW92ZSgnJywgb3B0aW9ucyk7XG4gICAgICAgIC8vICAgICB9XG4gICAgfTtcblxuICAgICQuZXh0ZW5kKHRoaXMsIHB1YmxpY0FQSSk7XG59O1xuIiwiLyoqXG4gKlxuICogIyMgR3JvdXAgQVBJIEFkYXB0ZXJcbiAqXG4gKiBUaGUgR3JvdXAgQVBJIEFkYXB0ZXIgcHJvdmlkZXMgbWV0aG9kcyB0byBsb29rIHVwLCBjcmVhdGUsIGNoYW5nZSBvciByZW1vdmUgaW5mb3JtYXRpb24gYWJvdXQgZ3JvdXBzIGluIGEgcHJvamVjdC4gSXQgaXMgYmFzZWQgb24gcXVlcnkgY2FwYWJpbGl0aWVzIG9mIHRoZSB1bmRlcmx5aW5nIFJFU1RmdWwgW0dyb3VwIEFQSV0oLi4vLi4vLi4vcmVzdF9hcGlzL3VzZXJfbWFuYWdlbWVudC9ncm91cC8pLlxuICpcbiAqIFRoaXMgaXMgb25seSBuZWVkZWQgZm9yIEF1dGhlbnRpY2F0ZWQgcHJvamVjdHMsIHRoYXQgaXMsIHRlYW0gcHJvamVjdHMgd2l0aCBbZW5kIHVzZXJzIGFuZCBncm91cHNdKC4uLy4uLy4uL2dyb3Vwc19hbmRfZW5kX3VzZXJzLykuXG4gKlxuICogICAgICB2YXIgbWEgPSBuZXcgRi5zZXJ2aWNlLkdyb3VwKHsgdG9rZW46ICd1c2VyLW9yLXByb2plY3QtYWNjZXNzLXRva2VuJyB9KTtcbiAqICAgICAgbWEuZ2V0R3JvdXBzRm9yUHJvamVjdCh7IGFjY291bnQ6ICdhY21lJywgcHJvamVjdDogJ3NhbXBsZScgfSk7XG4gKi9cblxuJ3VzZSBzdHJpY3QnO1xuXG52YXIgc2VydmljZVV0aWxzID0gcmVxdWlyZSgnLi9zZXJ2aWNlLXV0aWxzJyk7XG52YXIgVHJhbnNwb3J0RmFjdG9yeSA9IHJlcXVpcmUoJy4uL3RyYW5zcG9ydC9odHRwLXRyYW5zcG9ydC1mYWN0b3J5Jyk7XG52YXIgb2JqZWN0QXNzaWduID0gcmVxdWlyZSgnb2JqZWN0LWFzc2lnbicpO1xuXG52YXIgYXBpRW5kcG9pbnQgPSAnZ3JvdXAvbG9jYWwnO1xuXG52YXIgR3JvdXBTZXJ2aWNlID0gZnVuY3Rpb24gKGNvbmZpZykge1xuICAgIHZhciBkZWZhdWx0cyA9IHtcbiAgICAgICAgLyoqXG4gICAgICAgICAqIEVwaWNlbnRlciBhY2NvdW50IG5hbWUuIERlZmF1bHRzIHRvIHVuZGVmaW5lZC5cbiAgICAgICAgICogQHR5cGUge3N0cmluZ31cbiAgICAgICAgICovXG4gICAgICAgIGFjY291bnQ6IHVuZGVmaW5lZCxcblxuICAgICAgICAvKipcbiAgICAgICAgICogRXBpY2VudGVyIHByb2plY3QgbmFtZS4gRGVmYXVsdHMgdG8gdW5kZWZpbmVkLlxuICAgICAgICAgKiBAdHlwZSB7c3RyaW5nfVxuICAgICAgICAgKi9cbiAgICAgICAgcHJvamVjdDogdW5kZWZpbmVkLFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBPcHRpb25zIHRvIHBhc3Mgb24gdG8gdGhlIHVuZGVybHlpbmcgdHJhbnNwb3J0IGxheWVyLiBBbGwganF1ZXJ5LmFqYXggb3B0aW9ucyBhdCBodHRwOi8vYXBpLmpxdWVyeS5jb20valF1ZXJ5LmFqYXgvIGFyZSBhdmFpbGFibGUuIERlZmF1bHRzIHRvIGVtcHR5IG9iamVjdC5cbiAgICAgICAgICogQHR5cGUge29iamVjdH1cbiAgICAgICAgICovXG4gICAgICAgIHRyYW5zcG9ydDoge31cbiAgICB9O1xuICAgIHZhciBzZXJ2aWNlT3B0aW9ucyA9IHNlcnZpY2VVdGlscy5nZXREZWZhdWx0T3B0aW9ucyhkZWZhdWx0cywgY29uZmlnLCB7IGFwaUVuZHBvaW50OiBhcGlFbmRwb2ludCB9KTtcbiAgICB2YXIgdHJhbnNwb3J0T3B0aW9ucyA9IHNlcnZpY2VPcHRpb25zLnRyYW5zcG9ydDtcbiAgICBkZWxldGUgc2VydmljZU9wdGlvbnMudHJhbnNwb3J0O1xuICAgIHZhciBodHRwID0gbmV3IFRyYW5zcG9ydEZhY3RvcnkodHJhbnNwb3J0T3B0aW9ucywgc2VydmljZU9wdGlvbnMpO1xuICAgIHZhciBwdWJsaWNBUEkgPSB7XG4gICAgICAgIC8qXG4gICAgICAgICogR2V0cyBpbmZvcm1hdGlvbiBmb3IgYSBncm91cCBvciBtdWx0aXBsZSBncm91cHMuXG4gICAgICAgICogQHBhcmFtIHtzdHJpbmd9IGBwYXJhbXNgIHRoZSBncm91cElkIG9mIHRoZSB0YXJnZXQgZ3JvdXBcbiAgICAgICAgKiBAcGFyYW0ge09iamVjdH0gYHBhcmFtc2Agb2JqZWN0IHdpdGggcXVlcnkgcGFyYW1ldGVyc1xuICAgICAgICAqIEBwYXRhbSB7c3RyaW5nfSBgcGFyYW1zLnFgIHBhcnRpYWwgbWF0Y2ggZm9yIG5hbWUsIG9yZ2FuaXphdGlvbiBvciBldmVudC5cbiAgICAgICAgKiBAcGF0YW0ge3N0cmluZ30gYHBhcmFtcy5hY2NvdW50YCBFcGljZW50ZXIncyBUZWFtIElEXG4gICAgICAgICogQHBhdGFtIHtzdHJpbmd9IGBwYXJhbXMucHJvamVjdGAgRXBpY2VudGVyJ3MgUHJvamVjdCBJRFxuICAgICAgICAqIEBwYXRhbSB7c3RyaW5nfSBgcGFyYW1zLm5hbWVgIEVwaWNlbnRlcidzIEdyb3VwIE5hbWVcbiAgICAgICAgKiBAcGFyYW0ge09iamVjdH0gYG9wdGlvbnNgIChPcHRpb25hbCkgT3ZlcnJpZGVzIGZvciBjb25maWd1cmF0aW9uIG9wdGlvbnMuXG4gICAgICAgICovXG4gICAgICAgIGdldEdyb3VwczogZnVuY3Rpb24gKHBhcmFtcywgb3B0aW9ucykge1xuICAgICAgICAgICAgLy9ncm91cElEIGlzIHBhcnQgb2YgdGhlIFVSTFxuICAgICAgICAgICAgLy9xLCBhY2NvdW50IGFuZCBwcm9qZWN0IGFyZSBwYXJ0IG9mIHRoZSBxdWVyeSBzdHJpbmdcbiAgICAgICAgICAgIHZhciBmaW5hbE9wdHMgPSBvYmplY3RBc3NpZ24oe30sIHNlcnZpY2VPcHRpb25zLCBvcHRpb25zKTtcbiAgICAgICAgICAgIHZhciBmaW5hbFBhcmFtcztcbiAgICAgICAgICAgIGlmICh0eXBlb2YgcGFyYW1zID09PSAnc3RyaW5nJykge1xuICAgICAgICAgICAgICAgIGZpbmFsT3B0cy51cmwgPSBzZXJ2aWNlVXRpbHMuZ2V0QXBpVXJsKGFwaUVuZHBvaW50ICsgJy8nICsgcGFyYW1zLCBmaW5hbE9wdHMpO1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICBmaW5hbFBhcmFtcyA9IHBhcmFtcztcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHJldHVybiBodHRwLmdldChmaW5hbFBhcmFtcywgZmluYWxPcHRzKTtcbiAgICAgICAgfVxuICAgIH07XG4gICAgb2JqZWN0QXNzaWduKHRoaXMsIHB1YmxpY0FQSSk7XG59O1xuXG5tb2R1bGUuZXhwb3J0cyA9IEdyb3VwU2VydmljZTtcbiIsIi8qKlxuICpcbiAqICMjIE1lbWJlciBBUEkgQWRhcHRlclxuICpcbiAqIFRoZSBNZW1iZXIgQVBJIEFkYXB0ZXIgcHJvdmlkZXMgbWV0aG9kcyB0byBsb29rIHVwIGluZm9ybWF0aW9uIGFib3V0IGVuZCB1c2VycyBmb3IgeW91ciBwcm9qZWN0IGFuZCBob3cgdGhleSBhcmUgZGl2aWRlZCBhY3Jvc3MgZ3JvdXBzLiBJdCBpcyBiYXNlZCBvbiBxdWVyeSBjYXBhYmlsaXRpZXMgb2YgdGhlIHVuZGVybHlpbmcgUkVTVGZ1bCBbTWVtYmVyIEFQSV0oLi4vLi4vLi4vcmVzdF9hcGlzL3VzZXJfbWFuYWdlbWVudC9tZW1iZXIvKS5cbiAqXG4gKiBUaGlzIGlzIG9ubHkgbmVlZGVkIGZvciBBdXRoZW50aWNhdGVkIHByb2plY3RzLCB0aGF0IGlzLCB0ZWFtIHByb2plY3RzIHdpdGggW2VuZCB1c2VycyBhbmQgZ3JvdXBzXSguLi8uLi8uLi9ncm91cHNfYW5kX2VuZF91c2Vycy8pLiBGb3IgZXhhbXBsZSwgaWYgc29tZSBvZiB5b3VyIGVuZCB1c2VycyBhcmUgZmFjaWxpdGF0b3JzLCBvciBpZiB5b3VyIGVuZCB1c2VycyBzaG91bGQgYmUgdHJlYXRlZCBkaWZmZXJlbnRseSBiYXNlZCBvbiB3aGljaCBncm91cCB0aGV5IGFyZSBpbiwgdXNlIHRoZSBNZW1iZXIgQVBJIHRvIGZpbmQgdGhhdCBpbmZvcm1hdGlvbi5cbiAqXG4gKiAgICAgIHZhciBtYSA9IG5ldyBGLnNlcnZpY2UuTWVtYmVyKHsgdG9rZW46ICd1c2VyLW9yLXByb2plY3QtYWNjZXNzLXRva2VuJyB9KTtcbiAqICAgICAgbWEuZ2V0R3JvdXBzRm9yVXNlcih7IHVzZXJJZDogJ2I2YjMxM2EzLWFiODQtNDc5Yy1iYWVhLTIwNmY2YmZmMzM3JyB9KTtcbiAqICAgICAgbWEuZ2V0R3JvdXBEZXRhaWxzKHsgZ3JvdXBJZDogJzAwYjUzMzA4LTk4MzMtNDdmMi1iMjFlLTEyNzhjMDdkNTNiOCcgfSk7XG4gKi9cblxuJ3VzZSBzdHJpY3QnO1xuXG52YXIgQ29uZmlnU2VydmljZSA9IHJlcXVpcmUoJy4vY29uZmlndXJhdGlvbi1zZXJ2aWNlJyk7XG52YXIgVHJhbnNwb3J0RmFjdG9yeSA9IHJlcXVpcmUoJy4uL3RyYW5zcG9ydC9odHRwLXRyYW5zcG9ydC1mYWN0b3J5Jyk7XG52YXIgU2Vzc2lvbk1hbmFnZXIgPSByZXF1aXJlKCcuLi9zdG9yZS9zZXNzaW9uLW1hbmFnZXInKTtcbnZhciBfcGljayA9IHJlcXVpcmUoJy4uL3V0aWwvb2JqZWN0LXV0aWwnKS5fcGljaztcbnZhciBhcGlFbmRwb2ludCA9ICdtZW1iZXIvbG9jYWwnO1xuXG5tb2R1bGUuZXhwb3J0cyA9IGZ1bmN0aW9uIChjb25maWcpIHtcbiAgICB2YXIgZGVmYXVsdHMgPSB7XG4gICAgICAgIC8qKlxuICAgICAgICAgKiBFcGljZW50ZXIgdXNlciBpZC4gRGVmYXVsdHMgdG8gYSBibGFuayBzdHJpbmcuXG4gICAgICAgICAqIEB0eXBlIHtzdHJpbmd9XG4gICAgICAgICAqL1xuICAgICAgICB1c2VySWQ6IHVuZGVmaW5lZCxcblxuICAgICAgICAvKipcbiAgICAgICAgICogRXBpY2VudGVyIGdyb3VwIGlkLiBEZWZhdWx0cyB0byBhIGJsYW5rIHN0cmluZy4gTm90ZSB0aGF0IHRoaXMgaXMgdGhlIGdyb3VwICppZCosIG5vdCB0aGUgZ3JvdXAgKm5hbWUqLlxuICAgICAgICAgKiBAdHlwZSB7c3RyaW5nfVxuICAgICAgICAgKi9cbiAgICAgICAgZ3JvdXBJZDogdW5kZWZpbmVkLFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBPcHRpb25zIHRvIHBhc3Mgb24gdG8gdGhlIHVuZGVybHlpbmcgdHJhbnNwb3J0IGxheWVyLiBBbGwganF1ZXJ5LmFqYXggb3B0aW9ucyBhdCBodHRwOi8vYXBpLmpxdWVyeS5jb20valF1ZXJ5LmFqYXgvIGFyZSBhdmFpbGFibGUuIERlZmF1bHRzIHRvIGVtcHR5IG9iamVjdC5cbiAgICAgICAgICogQHR5cGUge29iamVjdH1cbiAgICAgICAgICovXG4gICAgICAgIHRyYW5zcG9ydDoge31cbiAgICB9O1xuICAgIHRoaXMuc2Vzc2lvbk1hbmFnZXIgPSBuZXcgU2Vzc2lvbk1hbmFnZXIoKTtcbiAgICB2YXIgc2VydmljZU9wdGlvbnMgPSB0aGlzLnNlc3Npb25NYW5hZ2VyLmdldE1lcmdlZE9wdGlvbnMoZGVmYXVsdHMsIGNvbmZpZyk7XG4gICAgdmFyIHVybENvbmZpZyA9IG5ldyBDb25maWdTZXJ2aWNlKHNlcnZpY2VPcHRpb25zKS5nZXQoJ3NlcnZlcicpO1xuXG4gICAgdmFyIHRyYW5zcG9ydE9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSwgc2VydmljZU9wdGlvbnMudHJhbnNwb3J0LCB7XG4gICAgICAgIHVybDogdXJsQ29uZmlnLmdldEFQSVBhdGgoYXBpRW5kcG9pbnQpXG4gICAgfSk7XG5cbiAgICBpZiAoc2VydmljZU9wdGlvbnMudG9rZW4pIHtcbiAgICAgICAgdHJhbnNwb3J0T3B0aW9ucy5oZWFkZXJzID0ge1xuICAgICAgICAgICAgJ0F1dGhvcml6YXRpb24nOiAnQmVhcmVyICcgKyBzZXJ2aWNlT3B0aW9ucy50b2tlblxuICAgICAgICB9O1xuICAgIH1cbiAgICB2YXIgaHR0cCA9IG5ldyBUcmFuc3BvcnRGYWN0b3J5KHRyYW5zcG9ydE9wdGlvbnMsIHNlcnZpY2VPcHRpb25zKTtcblxuICAgIHZhciBnZXRGaW5hbFBhcmFtcyA9IGZ1bmN0aW9uIChwYXJhbXMpIHtcbiAgICAgICAgaWYgKHR5cGVvZiBwYXJhbXMgPT09ICdvYmplY3QnKSB7XG4gICAgICAgICAgICByZXR1cm4gJC5leHRlbmQodHJ1ZSwgc2VydmljZU9wdGlvbnMsIHBhcmFtcyk7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIHNlcnZpY2VPcHRpb25zO1xuICAgIH07XG5cbiAgICB2YXIgcGF0Y2hVc2VyQWN0aXZlRmllbGQgPSBmdW5jdGlvbiAocGFyYW1zLCBhY3RpdmUsIG9wdGlvbnMpIHtcbiAgICAgICAgdmFyIGh0dHBPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwgc2VydmljZU9wdGlvbnMsIG9wdGlvbnMsIHtcbiAgICAgICAgICAgIHVybDogdXJsQ29uZmlnLmdldEFQSVBhdGgoYXBpRW5kcG9pbnQpICsgcGFyYW1zLmdyb3VwSWQgKyAnLycgKyBwYXJhbXMudXNlcklkXG4gICAgICAgIH0pO1xuXG4gICAgICAgIHJldHVybiBodHRwLnBhdGNoKHsgYWN0aXZlOiBhY3RpdmUgfSwgaHR0cE9wdGlvbnMpO1xuICAgIH07XG5cbiAgICB2YXIgcHVibGljQVBJID0ge1xuXG4gICAgICAgIC8qKlxuICAgICAgICAqIFJldHJpZXZlIGRldGFpbHMgYWJvdXQgYWxsIG9mIHRoZSBncm91cCBtZW1iZXJzaGlwcyBmb3Igb25lIGVuZCB1c2VyLiBUaGUgbWVtYmVyc2hpcCBkZXRhaWxzIGFyZSByZXR1cm5lZCBpbiBhbiBhcnJheSwgd2l0aCBvbmUgZWxlbWVudCAoZ3JvdXAgcmVjb3JkKSBmb3IgZWFjaCBncm91cCB0byB3aGljaCB0aGUgZW5kIHVzZXIgYmVsb25ncy5cbiAgICAgICAgKlxuICAgICAgICAqIEluIHRoZSBtZW1iZXJzaGlwIGFycmF5LCBlYWNoIGdyb3VwIHJlY29yZCBpbmNsdWRlcyB0aGUgZ3JvdXAgaWQsIHByb2plY3QgaWQsIGFjY291bnQgKHRlYW0pIGlkLCBhbmQgYW4gYXJyYXkgb2YgbWVtYmVycy4gSG93ZXZlciwgb25seSB0aGUgdXNlciB3aG9zZSB1c2VySWQgaXMgaW5jbHVkZWQgaW4gdGhlIGNhbGwgaXMgbGlzdGVkIGluIHRoZSBtZW1iZXJzIGFycmF5IChyZWdhcmRsZXNzIG9mIHdoZXRoZXIgdGhlcmUgYXJlIG90aGVyIG1lbWJlcnMgaW4gdGhpcyBncm91cCkuXG4gICAgICAgICpcbiAgICAgICAgKiAqKkV4YW1wbGUqKlxuICAgICAgICAqXG4gICAgICAgICogICAgICAgdmFyIG1hID0gbmV3IEYuc2VydmljZS5NZW1iZXIoeyB0b2tlbjogJ3VzZXItb3ItcHJvamVjdC1hY2Nlc3MtdG9rZW4nIH0pO1xuICAgICAgICAqICAgICAgIG1hLmdldEdyb3Vwc0ZvclVzZXIoJzQyODM2ZDRiLTViNjEtNGZlNC04MGViLTMxMzZlOTU2ZWU1YycpXG4gICAgICAgICogICAgICAgICAgIC50aGVuKGZ1bmN0aW9uKG1lbWJlcnNoaXBzKXtcbiAgICAgICAgKiAgICAgICAgICAgICAgIGZvciAodmFyIGk9MDsgaTxtZW1iZXJzaGlwcy5sZW5ndGg7IGkrKykge1xuICAgICAgICAqICAgICAgICAgICAgICAgICAgIGNvbnNvbGUubG9nKG1lbWJlcnNoaXBzW2ldLmdyb3VwSWQpO1xuICAgICAgICAqICAgICAgICAgICAgICAgfVxuICAgICAgICAqICAgICAgICAgICB9KTtcbiAgICAgICAgKlxuICAgICAgICAqICAgICAgIG1hLmdldEdyb3Vwc0ZvclVzZXIoeyB1c2VySWQ6ICc0MjgzNmQ0Yi01YjYxLTRmZTQtODBlYi0zMTM2ZTk1NmVlNWMnIH0pO1xuICAgICAgICAqXG4gICAgICAgICogKipQYXJhbWV0ZXJzKipcbiAgICAgICAgKiBAcGFyYW0ge3N0cmluZ3xvYmplY3R9IGBwYXJhbXNgIFRoZSB1c2VyIGlkIGZvciB0aGUgZW5kIHVzZXIuIEFsdGVybmF0aXZlbHksIGFuIG9iamVjdCB3aXRoIGZpZWxkIGB1c2VySWRgIGFuZCB2YWx1ZSB0aGUgdXNlciBpZC5cbiAgICAgICAgKiBAcGFyYW0ge29iamVjdH0gYG9wdGlvbnNgIChPcHRpb25hbCkgT3ZlcnJpZGVzIGZvciBjb25maWd1cmF0aW9uIG9wdGlvbnMuXG4gICAgICAgICovXG5cbiAgICAgICAgZ2V0R3JvdXBzRm9yVXNlcjogZnVuY3Rpb24gKHBhcmFtcywgb3B0aW9ucykge1xuICAgICAgICAgICAgb3B0aW9ucyA9IG9wdGlvbnMgfHwge307XG4gICAgICAgICAgICB2YXIgaHR0cE9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCBzZXJ2aWNlT3B0aW9ucywgb3B0aW9ucyk7XG4gICAgICAgICAgICB2YXIgaXNTdHJpbmcgPSB0eXBlb2YgcGFyYW1zID09PSAnc3RyaW5nJztcbiAgICAgICAgICAgIHZhciBvYmpQYXJhbXMgPSBnZXRGaW5hbFBhcmFtcyhwYXJhbXMpO1xuICAgICAgICAgICAgaWYgKCFpc1N0cmluZyAmJiAhb2JqUGFyYW1zLnVzZXJJZCkge1xuICAgICAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcignTm8gdXNlcklkIHNwZWNpZmllZC4nKTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgdmFyIGdldFBhcm1zID0gaXNTdHJpbmcgPyB7IHVzZXJJZDogcGFyYW1zIH0gOiBfcGljayhvYmpQYXJhbXMsICd1c2VySWQnKTtcbiAgICAgICAgICAgIHJldHVybiBodHRwLmdldChnZXRQYXJtcywgaHR0cE9wdGlvbnMpO1xuICAgICAgICB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAqIFJldHJpZXZlIGRldGFpbHMgYWJvdXQgb25lIGdyb3VwLCBpbmNsdWRpbmcgYW4gYXJyYXkgb2YgYWxsIGl0cyBtZW1iZXJzLlxuICAgICAgICAqXG4gICAgICAgICogKipFeGFtcGxlKipcbiAgICAgICAgKlxuICAgICAgICAqICAgICAgIHZhciBtYSA9IG5ldyBGLnNlcnZpY2UuTWVtYmVyKHsgdG9rZW46ICd1c2VyLW9yLXByb2plY3QtYWNjZXNzLXRva2VuJyB9KTtcbiAgICAgICAgKiAgICAgICBtYS5nZXRHcm91cERldGFpbHMoJzgwMjU3YTI1LWFhMTAtNDk1OS05NjhiLWZkMDUzOTAxZjcyZicpXG4gICAgICAgICogICAgICAgICAgIC50aGVuKGZ1bmN0aW9uKGdyb3VwKXtcbiAgICAgICAgKiAgICAgICAgICAgICAgIGZvciAodmFyIGk9MDsgaTxncm91cC5tZW1iZXJzLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgICogICAgICAgICAgICAgICAgICAgY29uc29sZS5sb2coZ3JvdXAubWVtYmVyc1tpXS51c2VyTmFtZSk7XG4gICAgICAgICogICAgICAgICAgICAgICB9XG4gICAgICAgICogICAgICAgICAgIH0pO1xuICAgICAgICAqXG4gICAgICAgICogICAgICAgbWEuZ2V0R3JvdXBEZXRhaWxzKHsgZ3JvdXBJZDogJzgwMjU3YTI1LWFhMTAtNDk1OS05NjhiLWZkMDUzOTAxZjcyZicgfSk7XG4gICAgICAgICpcbiAgICAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAqIEBwYXJhbSB7c3RyaW5nfG9iamVjdH0gYHBhcmFtc2AgVGhlIGdyb3VwIGlkLiBBbHRlcm5hdGl2ZWx5LCBhbiBvYmplY3Qgd2l0aCBmaWVsZCBgZ3JvdXBJZGAgYW5kIHZhbHVlIHRoZSBncm91cCBpZC5cbiAgICAgICAgKiBAcGFyYW0ge29iamVjdH0gYG9wdGlvbnNgIChPcHRpb25hbCkgT3ZlcnJpZGVzIGZvciBjb25maWd1cmF0aW9uIG9wdGlvbnMuXG4gICAgICAgICovXG4gICAgICAgIGdldEdyb3VwRGV0YWlsczogZnVuY3Rpb24gKHBhcmFtcywgb3B0aW9ucykge1xuICAgICAgICAgICAgb3B0aW9ucyA9IG9wdGlvbnMgfHwge307XG4gICAgICAgICAgICB2YXIgaXNTdHJpbmcgPSB0eXBlb2YgcGFyYW1zID09PSAnc3RyaW5nJztcbiAgICAgICAgICAgIHZhciBvYmpQYXJhbXMgPSBnZXRGaW5hbFBhcmFtcyhwYXJhbXMpO1xuICAgICAgICAgICAgaWYgKCFpc1N0cmluZyAmJiAhb2JqUGFyYW1zLmdyb3VwSWQpIHtcbiAgICAgICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ05vIGdyb3VwSWQgc3BlY2lmaWVkLicpO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICB2YXIgZ3JvdXBJZCA9IGlzU3RyaW5nID8gcGFyYW1zIDogb2JqUGFyYW1zLmdyb3VwSWQ7XG4gICAgICAgICAgICB2YXIgaHR0cE9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCBzZXJ2aWNlT3B0aW9ucyxcbiAgICAgICAgICAgICAgICBvcHRpb25zLFxuICAgICAgICAgICAgICAgIHsgdXJsOiB1cmxDb25maWcuZ2V0QVBJUGF0aChhcGlFbmRwb2ludCkgKyBncm91cElkIH1cbiAgICAgICAgICAgICk7XG5cbiAgICAgICAgICAgIHJldHVybiBodHRwLmdldCh7fSwgaHR0cE9wdGlvbnMpO1xuICAgICAgICB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAqIFNldCBhIHBhcnRpY3VsYXIgZW5kIHVzZXIgYXMgYGFjdGl2ZWAuIEFjdGl2ZSBlbmQgdXNlcnMgY2FuIGJlIGFzc2lnbmVkIHRvIFt3b3JsZHNdKC4uL3dvcmxkLW1hbmFnZXIvKSBpbiBtdWx0aXBsYXllciBnYW1lcyBkdXJpbmcgYXV0b21hdGljIGFzc2lnbm1lbnQuXG4gICAgICAgICpcbiAgICAgICAgKiAqKkV4YW1wbGUqKlxuICAgICAgICAqXG4gICAgICAgICogICAgICAgdmFyIG1hID0gbmV3IEYuc2VydmljZS5NZW1iZXIoeyB0b2tlbjogJ3VzZXItb3ItcHJvamVjdC1hY2Nlc3MtdG9rZW4nIH0pO1xuICAgICAgICAqICAgICAgIG1hLm1ha2VVc2VyQWN0aXZlKHsgdXNlcklkOiAnNDI4MzZkNGItNWI2MS00ZmU0LTgwZWItMzEzNmU5NTZlZTVjJyxcbiAgICAgICAgKiAgICAgICAgICAgICAgICAgICAgICAgICAgIGdyb3VwSWQ6ICc4MDI1N2EyNS1hYTEwLTQ5NTktOTY4Yi1mZDA1MzkwMWY3MmYnIH0pO1xuICAgICAgICAqXG4gICAgICAgICogKipQYXJhbWV0ZXJzKipcbiAgICAgICAgKiBAcGFyYW0ge29iamVjdH0gYHBhcmFtc2AgVGhlIGVuZCB1c2VyIGFuZCBncm91cCBpbmZvcm1hdGlvbi5cbiAgICAgICAgKiBAcGFyYW0ge3N0cmluZ30gYHBhcmFtcy51c2VySWRgIFRoZSBpZCBvZiB0aGUgZW5kIHVzZXIgdG8gbWFrZSBhY3RpdmUuXG4gICAgICAgICogQHBhcmFtIHtzdHJpbmd9IGBwYXJhbXMuZ3JvdXBJZGAgVGhlIGlkIG9mIHRoZSBncm91cCB0byB3aGljaCB0aGlzIGVuZCB1c2VyIGJlbG9uZ3MsIGFuZCBpbiB3aGljaCB0aGUgZW5kIHVzZXIgc2hvdWxkIGJlY29tZSBhY3RpdmUuXG4gICAgICAgICogQHBhcmFtIHtvYmplY3R9IGBvcHRpb25zYCAoT3B0aW9uYWwpIE92ZXJyaWRlcyBmb3IgY29uZmlndXJhdGlvbiBvcHRpb25zLlxuICAgICAgICAqL1xuICAgICAgICBtYWtlVXNlckFjdGl2ZTogZnVuY3Rpb24gKHBhcmFtcywgb3B0aW9ucykge1xuICAgICAgICAgICAgcmV0dXJuIHBhdGNoVXNlckFjdGl2ZUZpZWxkKHBhcmFtcywgdHJ1ZSwgb3B0aW9ucyk7XG4gICAgICAgIH0sXG5cbiAgICAgICAgLyoqXG4gICAgICAgICogU2V0IGEgcGFydGljdWxhciBlbmQgdXNlciBhcyBgaW5hY3RpdmVgLiBJbmFjdGl2ZSBlbmQgdXNlcnMgYXJlIG5vdCBhc3NpZ25lZCB0byBbd29ybGRzXSguLi93b3JsZC1tYW5hZ2VyLykgaW4gbXVsdGlwbGF5ZXIgZ2FtZXMgZHVyaW5nIGF1dG9tYXRpYyBhc3NpZ25tZW50LlxuICAgICAgICAqXG4gICAgICAgICogKipFeGFtcGxlKipcbiAgICAgICAgKlxuICAgICAgICAqICAgICAgIHZhciBtYSA9IG5ldyBGLnNlcnZpY2UuTWVtYmVyKHsgdG9rZW46ICd1c2VyLW9yLXByb2plY3QtYWNjZXNzLXRva2VuJyB9KTtcbiAgICAgICAgKiAgICAgICBtYS5tYWtlVXNlckluYWN0aXZlKHsgdXNlcklkOiAnNDI4MzZkNGItNWI2MS00ZmU0LTgwZWItMzEzNmU5NTZlZTVjJyxcbiAgICAgICAgKiAgICAgICAgICAgICAgICAgICAgICAgICAgIGdyb3VwSWQ6ICc4MDI1N2EyNS1hYTEwLTQ5NTktOTY4Yi1mZDA1MzkwMWY3MmYnIH0pO1xuICAgICAgICAqXG4gICAgICAgICogKipQYXJhbWV0ZXJzKipcbiAgICAgICAgKiBAcGFyYW0ge29iamVjdH0gYHBhcmFtc2AgVGhlIGVuZCB1c2VyIGFuZCBncm91cCBpbmZvcm1hdGlvbi5cbiAgICAgICAgKiBAcGFyYW0ge3N0cmluZ30gYHBhcmFtcy51c2VySWRgIFRoZSBpZCBvZiB0aGUgZW5kIHVzZXIgdG8gbWFrZSBpbmFjdGl2ZS5cbiAgICAgICAgKiBAcGFyYW0ge3N0cmluZ30gYHBhcmFtcy5ncm91cElkYCBUaGUgaWQgb2YgdGhlIGdyb3VwIHRvIHdoaWNoIHRoaXMgZW5kIHVzZXIgYmVsb25ncywgYW5kIGluIHdoaWNoIHRoZSBlbmQgdXNlciBzaG91bGQgYmVjb21lIGluYWN0aXZlLlxuICAgICAgICAqIEBwYXJhbSB7b2JqZWN0fSBgb3B0aW9uc2AgKE9wdGlvbmFsKSBPdmVycmlkZXMgZm9yIGNvbmZpZ3VyYXRpb24gb3B0aW9ucy5cbiAgICAgICAgKi9cbiAgICAgICAgbWFrZVVzZXJJbmFjdGl2ZTogZnVuY3Rpb24gKHBhcmFtcywgb3B0aW9ucykge1xuICAgICAgICAgICAgcmV0dXJuIHBhdGNoVXNlckFjdGl2ZUZpZWxkKHBhcmFtcywgZmFsc2UsIG9wdGlvbnMpO1xuICAgICAgICB9XG4gICAgfTtcblxuICAgICQuZXh0ZW5kKHRoaXMsIHB1YmxpY0FQSSk7XG59O1xuIiwiLyoqXG4gKlxuICogIyMgUnVuIEFQSSBTZXJ2aWNlXG4gKlxuICogVGhlIFJ1biBBUEkgU2VydmljZSBhbGxvd3MgeW91IHRvIHBlcmZvcm0gY29tbW9uIHRhc2tzIGFyb3VuZCBjcmVhdGluZyBhbmQgdXBkYXRpbmcgcnVucywgdmFyaWFibGVzLCBhbmQgZGF0YS5cbiAqXG4gKiBXaGVuIGJ1aWxkaW5nIGludGVyZmFjZXMgdG8gc2hvdyBydW4gb25lIGF0IGEgdGltZSAoYXMgZm9yIHN0YW5kYXJkIGVuZCB1c2VycyksIHR5cGljYWxseSB5b3UgZmlyc3QgaW5zdGFudGlhdGUgYSBbUnVuIE1hbmFnZXJdKC4uL3J1bi1tYW5hZ2VyLykgYW5kIHRoZW4gYWNjZXNzIHRoZSBSdW4gU2VydmljZSB0aGF0IGlzIGF1dG9tYXRpY2FsbHkgcGFydCBvZiB0aGUgbWFuYWdlciwgcmF0aGVyIHRoYW4gaW5zdGFudGlhdGluZyB0aGUgUnVuIFNlcnZpY2UgZGlyZWN0bHkuIFRoaXMgaXMgYmVjYXVzZSB0aGUgUnVuIE1hbmFnZXIgZ2l2ZXMgeW91IGNvbnRyb2wgb3ZlciBydW4gY3JlYXRpb24gZGVwZW5kaW5nIG9uIHJ1biBzdGF0ZXMuXG4gKlxuICogSG93ZXZlciwgbWFueSBvZiB0aGUgRXBpY2VudGVyIHNhbXBsZSBwcm9qZWN0cyB1c2UgYSBSdW4gU2VydmljZSwgYmVjYXVzZSBnZW5lcmFsbHkgdGhlIHNhbXBsZSBwcm9qZWN0cyBhcmUgcGxheWVkIGluIG9uZSBlbmQgdXNlciBzZXNzaW9uIGFuZCBkb24ndCBjYXJlIGFib3V0IHJ1biBzdGF0ZXMgb3IgW3J1biBzdHJhdGVnaWVzXSguLi8uLi9zdHJhdGVneS8pLiBUaGUgUnVuIEFQSSBTZXJ2aWNlIGlzIGFsc28gdXNlZnVsIGZvciBidWlsZGluZyBhbiBpbnRlcmZhY2UgZm9yIGEgZmFjaWxpdGF0b3IsIGJlY2F1c2UgaXQgbWFrZXMgaXQgZWFzeSB0byBsaXN0IGRhdGEgYWNyb3NzIG11bHRpcGxlIHJ1bnMgKHVzaW5nIHRoZSBgZmlsdGVyKClgIGFuZCBgcXVlcnkoKWAgbWV0aG9kcykuXG4gKlxuICogVG8gdXNlIHRoZSBSdW4gQVBJIFNlcnZpY2UsIGluc3RhbnRpYXRlIGl0IGJ5IHBhc3NpbmcgaW46XG4gKlxuICogKiBgYWNjb3VudGA6IEVwaWNlbnRlciBhY2NvdW50IGlkICgqKlRlYW0gSUQqKiBmb3IgdGVhbSBwcm9qZWN0cywgKipVc2VyIElEKiogZm9yIHBlcnNvbmFsIHByb2plY3RzKS5cbiAqICogYHByb2plY3RgOiBFcGljZW50ZXIgcHJvamVjdCBpZC5cbiAqXG4gKiBGb3IgZXhhbXBsZSxcbiAqXG4gKiAgICAgICB2YXIgcnMgPSBuZXcgRi5zZXJ2aWNlLlJ1bih7XG4gKiAgICAgICAgICAgIGFjY291bnQ6ICdhY21lLXNpbXVsYXRpb25zJyxcbiAqICAgICAgICAgICAgcHJvamVjdDogJ3N1cHBseS1jaGFpbi1nYW1lJyxcbiAqICAgICAgfSk7XG4gKiAgICAgIHJzLmNyZWF0ZSgnc3VwcGx5X2NoYWluX2dhbWUucHknKS50aGVuKGZ1bmN0aW9uKHJ1bikge1xuICogICAgICAgICAgICAgcnMuZG8oJ3NvbWVPcGVyYXRpb24nKTtcbiAqICAgICAgfSk7XG4gKlxuICpcbiAqIEFkZGl0aW9uYWxseSwgYWxsIEFQSSBjYWxscyB0YWtlIGluIGFuIFwib3B0aW9uc1wiIG9iamVjdCBhcyB0aGUgbGFzdCBwYXJhbWV0ZXIuIFRoZSBvcHRpb25zIGNhbiBiZSB1c2VkIHRvIGV4dGVuZC9vdmVycmlkZSB0aGUgUnVuIEFQSSBTZXJ2aWNlIGRlZmF1bHRzIGxpc3RlZCBiZWxvdy5cbiAqXG4gKiBOb3RlIHRoYXQgaW4gYWRkaXRpb24gdG8gdGhlIGBhY2NvdW50YCwgYHByb2plY3RgLCBhbmQgYG1vZGVsYCwgdGhlIFJ1biBTZXJ2aWNlIHBhcmFtZXRlcnMgb3B0aW9uYWxseSBpbmNsdWRlIGEgYHNlcnZlcmAgb2JqZWN0LCB3aG9zZSBgaG9zdGAgZmllbGQgY29udGFpbnMgdGhlIFVSSSBvZiB0aGUgRm9yaW8gc2VydmVyLiBUaGlzIGlzIGF1dG9tYXRpY2FsbHkgc2V0LCBidXQgeW91IGNhbiBwYXNzIGl0IGV4cGxpY2l0bHkgaWYgZGVzaXJlZC4gSXQgaXMgbW9zdCBjb21tb25seSB1c2VkIGZvciBjbGFyaXR5IHdoZW4geW91IGFyZSBbaG9zdGluZyBhbiBFcGljZW50ZXIgcHJvamVjdCBvbiB5b3VyIG93biBzZXJ2ZXJdKC4uLy4uLy4uL2hvd190by9zZWxmX2hvc3RpbmcvKS5cbiAqXG4gKiAgICAgICB2YXIgcm0gPSBuZXcgRi5tYW5hZ2VyLlJ1bk1hbmFnZXIoe1xuICogICAgICAgICAgIHJ1bjoge1xuICogICAgICAgICAgICAgICBhY2NvdW50OiAnYWNtZS1zaW11bGF0aW9ucycsXG4gKiAgICAgICAgICAgICAgIHByb2plY3Q6ICdzdXBwbHktY2hhaW4tZ2FtZScsXG4gKiAgICAgICAgICAgICAgIG1vZGVsOiAnc3VwcGx5X2NoYWluX2dhbWUucHknLFxuICogICAgICAgICAgICAgICBzZXJ2ZXI6IHsgaG9zdDogJ2FwaS5mb3Jpby5jb20nIH1cbiAqICAgICAgICAgICB9XG4gKiAgICAgICB9KTtcbiAqICAgICAgIHJtLmdldFJ1bigpXG4gKiAgICAgICAgICAgLnRoZW4oZnVuY3Rpb24ocnVuKSB7XG4gKiAgICAgICAgICAgICAgIC8vIHRoZSBSdW5NYW5hZ2VyLnJ1biBjb250YWlucyB0aGUgaW5zdGFudGlhdGVkIFJ1biBTZXJ2aWNlLFxuICogICAgICAgICAgICAgICAvLyBzbyBhbnkgUnVuIFNlcnZpY2UgbWV0aG9kIGlzIHZhbGlkIGhlcmVcbiAqICAgICAgICAgICAgICAgdmFyIHJzID0gcm0ucnVuO1xuICogICAgICAgICAgICAgICBycy5kbygnc29tZU9wZXJhdGlvbicpO1xuICogICAgICAgfSlcbiAqXG4gKi9cblxuJ3VzZSBzdHJpY3QnO1xuXG52YXIgQ29uZmlnU2VydmljZSA9IHJlcXVpcmUoJy4vY29uZmlndXJhdGlvbi1zZXJ2aWNlJyk7XG52YXIgcXV0aWwgPSByZXF1aXJlKCcuLi91dGlsL3F1ZXJ5LXV0aWwnKTtcbnZhciBydXRpbCA9IHJlcXVpcmUoJy4uL3V0aWwvcnVuLXV0aWwnKTtcbnZhciBfcGljayA9IHJlcXVpcmUoJy4uL3V0aWwvb2JqZWN0LXV0aWwnKS5fcGljaztcbnZhciBUcmFuc3BvcnRGYWN0b3J5ID0gcmVxdWlyZSgnLi4vdHJhbnNwb3J0L2h0dHAtdHJhbnNwb3J0LWZhY3RvcnknKTtcbnZhciBWYXJpYWJsZXNTZXJ2aWNlID0gcmVxdWlyZSgnLi92YXJpYWJsZXMtYXBpLXNlcnZpY2UnKTtcbnZhciBTZXNzaW9uTWFuYWdlciA9IHJlcXVpcmUoJy4uL3N0b3JlL3Nlc3Npb24tbWFuYWdlcicpO1xuXG5tb2R1bGUuZXhwb3J0cyA9IGZ1bmN0aW9uIChjb25maWcpIHtcbiAgICB2YXIgZGVmYXVsdHMgPSB7XG4gICAgICAgIC8qKlxuICAgICAgICAgKiBGb3IgcHJvamVjdHMgdGhhdCByZXF1aXJlIGF1dGhlbnRpY2F0aW9uLCBwYXNzIGluIHRoZSB1c2VyIGFjY2VzcyB0b2tlbiAoZGVmYXVsdHMgdG8gZW1wdHkgc3RyaW5nKS4gSWYgdGhlIHVzZXIgaXMgYWxyZWFkeSBsb2dnZWQgaW4gdG8gRXBpY2VudGVyLCB0aGUgdXNlciBhY2Nlc3MgdG9rZW4gaXMgYWxyZWFkeSBzZXQgaW4gYSBjb29raWUgYW5kIGF1dG9tYXRpY2FsbHkgbG9hZGVkIGZyb20gdGhlcmUuIChTZWUgW21vcmUgYmFja2dyb3VuZCBvbiBhY2Nlc3MgdG9rZW5zXSguLi8uLi8uLi9wcm9qZWN0X2FjY2Vzcy8pKS5cbiAgICAgICAgICogQHNlZSBbQXV0aGVudGljYXRpb24gQVBJIFNlcnZpY2VdKC4uL2F1dGgtYXBpLXNlcnZpY2UvKSBmb3IgZ2V0dGluZyB0b2tlbnMuXG4gICAgICAgICAqIEB0eXBlIHtTdHJpbmd9XG4gICAgICAgICAqL1xuICAgICAgICB0b2tlbjogdW5kZWZpbmVkLFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBUaGUgYWNjb3VudCBpZC4gSW4gdGhlIEVwaWNlbnRlciBVSSwgdGhpcyBpcyB0aGUgKipUZWFtIElEKiogKGZvciB0ZWFtIHByb2plY3RzKSBvciAqKlVzZXIgSUQqKiAoZm9yIHBlcnNvbmFsIHByb2plY3RzKS4gRGVmYXVsdHMgdG8gZW1wdHkgc3RyaW5nLiBJZiBsZWZ0IHVuZGVmaW5lZCwgdGFrZW4gZnJvbSB0aGUgVVJMLlxuICAgICAgICAgKiBAdHlwZSB7U3RyaW5nfVxuICAgICAgICAgKi9cbiAgICAgICAgYWNjb3VudDogdW5kZWZpbmVkLFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBUaGUgcHJvamVjdCBpZC4gRGVmYXVsdHMgdG8gZW1wdHkgc3RyaW5nLiBJZiBsZWZ0IHVuZGVmaW5lZCwgdGFrZW4gZnJvbSB0aGUgVVJMLlxuICAgICAgICAgKiBAdHlwZSB7U3RyaW5nfVxuICAgICAgICAgKi9cbiAgICAgICAgcHJvamVjdDogdW5kZWZpbmVkLFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBDcml0ZXJpYSBieSB3aGljaCB0byBmaWx0ZXIgcnVucy4gRGVmYXVsdHMgdG8gZW1wdHkgc3RyaW5nLlxuICAgICAgICAgKiBAdHlwZSB7U3RyaW5nfVxuICAgICAgICAgKi9cbiAgICAgICAgZmlsdGVyOiAnJyxcblxuICAgICAgICAvKipcbiAgICAgICAgICogQ29udmVuaWVuY2UgYWxpYXMgZm9yIGZpbHRlci5cbiAgICAgICAgICogQHR5cGUge1N0cmluZ31cbiAgICAgICAgICovXG4gICAgICAgIGlkOiAnJyxcblxuICAgICAgICAvKipcbiAgICAgICAgICogRmxhZyBkZXRlcm1pbmVzIGlmIGBYLUF1dG9SZXN0b3JlOiB0cnVlYCBoZWFkZXIgaXMgc2VudCB0byBFcGljZW50ZXIuIERlZmF1bHRzIHRvIGB0cnVlYC5cbiAgICAgICAgICogQHR5cGUge2Jvb2xlYW59XG4gICAgICAgICAqL1xuICAgICAgICBhdXRvUmVzdG9yZTogdHJ1ZSxcblxuICAgICAgICAvKipcbiAgICAgICAgICogQ2FsbGVkIHdoZW4gdGhlIGNhbGwgY29tcGxldGVzIHN1Y2Nlc3NmdWxseS4gRGVmYXVsdHMgdG8gYCQubm9vcGAuXG4gICAgICAgICAqIEB0eXBlIHtmdW5jdGlvbn1cbiAgICAgICAgICovXG4gICAgICAgIHN1Y2Nlc3M6ICQubm9vcCxcblxuICAgICAgICAvKipcbiAgICAgICAgICogQ2FsbGVkIHdoZW4gdGhlIGNhbGwgZmFpbHMuIERlZmF1bHRzIHRvIGAkLm5vb3BgLlxuICAgICAgICAgKiBAdHlwZSB7ZnVuY3Rpb259XG4gICAgICAgICAqL1xuICAgICAgICBlcnJvcjogJC5ub29wLFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBPcHRpb25zIHRvIHBhc3Mgb24gdG8gdGhlIHVuZGVybHlpbmcgdHJhbnNwb3J0IGxheWVyLiBBbGwganF1ZXJ5LmFqYXggb3B0aW9ucyBhdCBodHRwOi8vYXBpLmpxdWVyeS5jb20valF1ZXJ5LmFqYXgvIGFyZSBhdmFpbGFibGUuIERlZmF1bHRzIHRvIGVtcHR5IG9iamVjdC5cbiAgICAgICAgICogQHR5cGUge09iamVjdH1cbiAgICAgICAgICovXG4gICAgICAgIHRyYW5zcG9ydDoge31cbiAgICB9O1xuXG4gICAgdGhpcy5zZXNzaW9uTWFuYWdlciA9IG5ldyBTZXNzaW9uTWFuYWdlcigpO1xuICAgIHZhciBzZXJ2aWNlT3B0aW9ucyA9IHRoaXMuc2Vzc2lvbk1hbmFnZXIuZ2V0TWVyZ2VkT3B0aW9ucyhkZWZhdWx0cywgY29uZmlnKTtcbiAgICBpZiAoc2VydmljZU9wdGlvbnMuaWQpIHtcbiAgICAgICAgc2VydmljZU9wdGlvbnMuZmlsdGVyID0gc2VydmljZU9wdGlvbnMuaWQ7XG4gICAgfVxuXG4gICAgdmFyIHVybENvbmZpZyA9IG5ldyBDb25maWdTZXJ2aWNlKHNlcnZpY2VPcHRpb25zKS5nZXQoJ3NlcnZlcicpO1xuICAgIGlmIChzZXJ2aWNlT3B0aW9ucy5hY2NvdW50KSB7XG4gICAgICAgIHVybENvbmZpZy5hY2NvdW50UGF0aCA9IHNlcnZpY2VPcHRpb25zLmFjY291bnQ7XG4gICAgfVxuICAgIGlmIChzZXJ2aWNlT3B0aW9ucy5wcm9qZWN0KSB7XG4gICAgICAgIHVybENvbmZpZy5wcm9qZWN0UGF0aCA9IHNlcnZpY2VPcHRpb25zLnByb2plY3Q7XG4gICAgfVxuXG4gICAgdXJsQ29uZmlnLmZpbHRlciA9ICc7JztcbiAgICB1cmxDb25maWcuZ2V0RmlsdGVyVVJMID0gZnVuY3Rpb24gKCkge1xuICAgICAgICB2YXIgdXJsID0gdXJsQ29uZmlnLmdldEFQSVBhdGgoJ3J1bicpO1xuICAgICAgICB2YXIgZmlsdGVyID0gcXV0aWwudG9NYXRyaXhGb3JtYXQoc2VydmljZU9wdGlvbnMuZmlsdGVyKTtcblxuICAgICAgICBpZiAoZmlsdGVyKSB7XG4gICAgICAgICAgICB1cmwgKz0gZmlsdGVyICsgJy8nO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiB1cmw7XG4gICAgfTtcblxuICAgIHVybENvbmZpZy5hZGRBdXRvUmVzdG9yZUhlYWRlciA9IGZ1bmN0aW9uIChvcHRpb25zKSB7XG4gICAgICAgIHZhciBmaWx0ZXIgPSBzZXJ2aWNlT3B0aW9ucy5maWx0ZXI7XG4gICAgICAgIC8vIFRoZSBzZW1pY29sb24gc2VwYXJhdGVkIGZpbHRlciBpcyB1c2VkIHdoZW4gZmlsdGVyIGlzIGFuIG9iamVjdFxuICAgICAgICB2YXIgaXNGaWx0ZXJSdW5JZCA9IGZpbHRlciAmJiAkLnR5cGUoZmlsdGVyKSA9PT0gJ3N0cmluZyc7XG4gICAgICAgIGlmIChzZXJ2aWNlT3B0aW9ucy5hdXRvUmVzdG9yZSAmJiBpc0ZpbHRlclJ1bklkKSB7XG4gICAgICAgICAgICAvLyBCeSBkZWZhdWx0IGF1dG9yZXBsYXkgdGhlIHJ1biBieSBzZW5kaW5nIHRoaXMgaGVhZGVyIHRvIGVwaWNlbnRlclxuICAgICAgICAgICAgLy8gaHR0cHM6Ly9mb3Jpby5jb20vZXBpY2VudGVyL2RvY3MvcHVibGljL3Jlc3RfYXBpcy9hZ2dyZWdhdGVfcnVuX2FwaS8jcmV0cmlldmluZ1xuICAgICAgICAgICAgdmFyIGF1dG9yZXN0b3JlT3B0cyA9IHtcbiAgICAgICAgICAgICAgICBoZWFkZXJzOiB7XG4gICAgICAgICAgICAgICAgICAgICdYLUF1dG9SZXN0b3JlJzogdHJ1ZVxuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH07XG4gICAgICAgICAgICByZXR1cm4gJC5leHRlbmQodHJ1ZSwgYXV0b3Jlc3RvcmVPcHRzLCBvcHRpb25zKTtcbiAgICAgICAgfVxuXG4gICAgICAgIHJldHVybiBvcHRpb25zO1xuICAgIH07XG5cbiAgICB2YXIgaHR0cE9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSwgc2VydmljZU9wdGlvbnMudHJhbnNwb3J0LCB7XG4gICAgICAgIHVybDogdXJsQ29uZmlnLmdldEZpbHRlclVSTFxuICAgIH0pO1xuXG4gICAgaWYgKHNlcnZpY2VPcHRpb25zLnRva2VuKSB7XG4gICAgICAgIGh0dHBPcHRpb25zLmhlYWRlcnMgPSB7XG4gICAgICAgICAgICAnQXV0aG9yaXphdGlvbic6ICdCZWFyZXIgJyArIHNlcnZpY2VPcHRpb25zLnRva2VuXG4gICAgICAgIH07XG4gICAgfVxuICAgIHZhciBodHRwID0gbmV3IFRyYW5zcG9ydEZhY3RvcnkoaHR0cE9wdGlvbnMpO1xuICAgIGh0dHAuc3BsaXRHZXQgPSBydXRpbC5zcGxpdEdldEZhY3RvcnkoaHR0cE9wdGlvbnMpO1xuXG4gICAgdmFyIHNldEZpbHRlck9yVGhyb3dFcnJvciA9IGZ1bmN0aW9uIChvcHRpb25zKSB7XG4gICAgICAgIGlmIChvcHRpb25zLmlkKSB7XG4gICAgICAgICAgICBzZXJ2aWNlT3B0aW9ucy5maWx0ZXIgPSBvcHRpb25zLmlkO1xuICAgICAgICB9XG4gICAgICAgIGlmIChvcHRpb25zLmZpbHRlcikge1xuICAgICAgICAgICAgc2VydmljZU9wdGlvbnMuZmlsdGVyID0gb3B0aW9ucy5maWx0ZXI7XG4gICAgICAgIH1cbiAgICAgICAgaWYgKCFzZXJ2aWNlT3B0aW9ucy5maWx0ZXIpIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcignTm8gZmlsdGVyIHNwZWNpZmllZCB0byBhcHBseSBvcGVyYXRpb25zIGFnYWluc3QnKTtcbiAgICAgICAgfVxuICAgIH07XG5cbiAgICB2YXIgcHVibGljQXN5bmNBUEkgPSB7XG4gICAgICAgIHVybENvbmZpZzogdXJsQ29uZmlnLFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBDcmVhdGUgYSBuZXcgcnVuLlxuICAgICAgICAgKlxuICAgICAgICAgKiBOT1RFOiBUeXBpY2FsbHkgdGhpcyBpcyBub3QgdXNlZCEgVXNlIGBSdW5NYW5hZ2VyLmdldFJ1bigpYCB3aXRoIGEgYHN0cmF0ZWd5YCBvZiBgYWx3YXlzLW5ld2AsIG9yIHVzZSBgUnVuTWFuYWdlci5yZXNldCgpYC4gU2VlIFtSdW4gTWFuYWdlcl0oLi4vcnVuLW1hbmFnZXIvKSBmb3IgbW9yZSBkZXRhaWxzLlxuICAgICAgICAgKlxuICAgICAgICAgKiAgKipFeGFtcGxlKipcbiAgICAgICAgICpcbiAgICAgICAgICogICAgICBycy5jcmVhdGUoJ2hlbGxvX3dvcmxkLmpsJyk7XG4gICAgICAgICAqXG4gICAgICAgICAqICAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAgKiBAcGFyYW0ge1N0cmluZ3xPYmplY3R9IGBwYXJhbXNgIElmIGEgc3RyaW5nLCB0aGUgbmFtZSBvZiB0aGUgcHJpbWFyeSBbbW9kZWwgZmlsZV0oLi4vLi4vLi4vd3JpdGluZ195b3VyX21vZGVsLykuIFRoaXMgaXMgdGhlIG9uZSBmaWxlIGluIHRoZSBwcm9qZWN0IHRoYXQgZXhwbGljaXRseSBleHBvc2VzIHZhcmlhYmxlcyBhbmQgbWV0aG9kcywgYW5kIGl0IG11c3QgYmUgc3RvcmVkIGluIHRoZSBNb2RlbCBmb2xkZXIgb2YgeW91ciBFcGljZW50ZXIgcHJvamVjdC4gSWYgYW4gb2JqZWN0LCBtYXkgaW5jbHVkZSBgbW9kZWxgLCBgc2NvcGVgLCBhbmQgYGZpbGVzYC4gKFNlZSB0aGUgW1J1biBNYW5hZ2VyXSguLi9ydW5fbWFuYWdlci8pIGZvciBtb3JlIGluZm9ybWF0aW9uIG9uIGBzY29wZWAgYW5kIGBmaWxlc2AuKVxuICAgICAgICAgKiBAcGFyYW0ge09iamVjdH0gYG9wdGlvbnNgIChPcHRpb25hbCkgT3ZlcnJpZGVzIGZvciBjb25maWd1cmF0aW9uIG9wdGlvbnMuXG4gICAgICAgICAqXG4gICAgICAgICAqL1xuICAgICAgICBjcmVhdGU6IGZ1bmN0aW9uIChwYXJhbXMsIG9wdGlvbnMpIHtcbiAgICAgICAgICAgIHZhciBjcmVhdGVPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sIHNlcnZpY2VPcHRpb25zLCBvcHRpb25zLCB7IHVybDogdXJsQ29uZmlnLmdldEFQSVBhdGgoJ3J1bicpIH0pO1xuICAgICAgICAgICAgdmFyIHJ1bkFwaVBhcmFtcyA9IFsnbW9kZWwnLCAnc2NvcGUnLCAnZmlsZXMnXTtcbiAgICAgICAgICAgIGlmICh0eXBlb2YgcGFyYW1zID09PSAnc3RyaW5nJykge1xuICAgICAgICAgICAgICAgIC8vIHRoaXMgaXMganVzdCB0aGUgbW9kZWwgbmFtZVxuICAgICAgICAgICAgICAgIHBhcmFtcyA9IHsgbW9kZWw6IHBhcmFtcyB9O1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICAvLyB3aGl0ZWxpc3QgdGhlIGZpZWxkcyB0aGF0IHdlIGFjdHVhbGx5IGNhbiBzZW5kIHRvIHRoZSBhcGlcbiAgICAgICAgICAgICAgICBwYXJhbXMgPSBfcGljayhwYXJhbXMsIHJ1bkFwaVBhcmFtcyk7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIHZhciBvbGRTdWNjZXNzID0gY3JlYXRlT3B0aW9ucy5zdWNjZXNzO1xuICAgICAgICAgICAgY3JlYXRlT3B0aW9ucy5zdWNjZXNzID0gZnVuY3Rpb24gKHJlc3BvbnNlKSB7XG4gICAgICAgICAgICAgICAgc2VydmljZU9wdGlvbnMuZmlsdGVyID0gcmVzcG9uc2UuaWQ7IC8vYWxsIGZ1dHVyZSBjaGFpbmVkIGNhbGxzIHRvIG9wZXJhdGUgb24gdGhpcyBpZFxuICAgICAgICAgICAgICAgIHJldHVybiBvbGRTdWNjZXNzLmFwcGx5KHRoaXMsIGFyZ3VtZW50cyk7XG4gICAgICAgICAgICB9O1xuXG4gICAgICAgICAgICByZXR1cm4gaHR0cC5wb3N0KHBhcmFtcywgY3JlYXRlT3B0aW9ucyk7XG4gICAgICAgIH0sXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIFJldHVybnMgcGFydGljdWxhciBydW5zLCBiYXNlZCBvbiBjb25kaXRpb25zIHNwZWNpZmllZCBpbiB0aGUgYHFzYCBvYmplY3QuXG4gICAgICAgICAqXG4gICAgICAgICAqIFRoZSBlbGVtZW50cyBvZiB0aGUgYHFzYCBvYmplY3QgYXJlIEFORGVkIHRvZ2V0aGVyIHdpdGhpbiBhIHNpbmdsZSBjYWxsIHRvIGAucXVlcnkoKWAuXG4gICAgICAgICAqXG4gICAgICAgICAqICoqRXhhbXBsZSoqXG4gICAgICAgICAqXG4gICAgICAgICAqICAgICAgLy8gcmV0dXJucyBydW5zIHdpdGggc2F2ZWQgPSB0cnVlIGFuZCB2YXJpYWJsZXMucHJpY2UgPiAxLFxuICAgICAgICAgKiAgICAgIC8vIHdoZXJlIHZhcmlhYmxlcy5wcmljZSBoYXMgYmVlbiBwZXJzaXN0ZWQgKHJlY29yZGVkKVxuICAgICAgICAgKiAgICAgIC8vIGluIHRoZSBtb2RlbC5cbiAgICAgICAgICogICAgIHJzLnF1ZXJ5KHtcbiAgICAgICAgICogICAgICAgICAgJ3NhdmVkJzogJ3RydWUnLFxuICAgICAgICAgKiAgICAgICAgICAnLnByaWNlJzogJz4xJ1xuICAgICAgICAgKiAgICAgICB9LFxuICAgICAgICAgKiAgICAgICB7XG4gICAgICAgICAqICAgICAgICAgIHN0YXJ0cmVjb3JkOiAyLFxuICAgICAgICAgKiAgICAgICAgICBlbmRyZWNvcmQ6IDVcbiAgICAgICAgICogICAgICAgfSk7XG4gICAgICAgICAqXG4gICAgICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICAgICAqIEBwYXJhbSB7T2JqZWN0fSBgcXNgIFF1ZXJ5IG9iamVjdC4gRWFjaCBrZXkgY2FuIGJlIGEgcHJvcGVydHkgb2YgdGhlIHJ1biBvciB0aGUgbmFtZSBvZiB2YXJpYWJsZSB0aGF0IGhhcyBiZWVuIHNhdmVkIGluIHRoZSBydW4gKHByZWZhY2VkIGJ5IGB2YXJpYWJsZXMuYCkuIEVhY2ggdmFsdWUgY2FuIGJlIGEgbGl0ZXJhbCB2YWx1ZSwgb3IgYSBjb21wYXJpc29uIG9wZXJhdG9yIGFuZCB2YWx1ZS4gKFNlZSBbbW9yZSBvbiBmaWx0ZXJpbmddKC4uLy4uLy4uL3Jlc3RfYXBpcy9hZ2dyZWdhdGVfcnVuX2FwaS8jZmlsdGVycykgYWxsb3dlZCBpbiB0aGUgdW5kZXJseWluZyBSdW4gQVBJLikgUXVlcnlpbmcgZm9yIHZhcmlhYmxlcyBpcyBhdmFpbGFibGUgZm9yIHJ1bnMgW2luIG1lbW9yeV0oLi4vLi4vLi4vcnVuX3BlcnNpc3RlbmNlLyNydW5zLWluLW1lbW9yeSkgYW5kIGZvciBydW5zIFtpbiB0aGUgZGF0YWJhc2VdKC4uLy4uLy4uL3J1bl9wZXJzaXN0ZW5jZS8jcnVucy1pbi1tZW1vcnkpIGlmIHRoZSB2YXJpYWJsZXMgYXJlIHBlcnNpc3RlZCAoZS5nLiB0aGF0IGhhdmUgYmVlbiBgcmVjb3JkYGVkIGluIHlvdXIgSnVsaWEgbW9kZWwpLlxuICAgICAgICAgKiBAcGFyYW0ge09iamVjdH0gYG91dHB1dE1vZGlmaWVyYCAoT3B0aW9uYWwpIEF2YWlsYWJsZSBmaWVsZHMgaW5jbHVkZTogYHN0YXJ0cmVjb3JkYCwgYGVuZHJlY29yZGAsIGBzb3J0YCwgYW5kIGBkaXJlY3Rpb25gIChgYXNjYCBvciBgZGVzY2ApLlxuICAgICAgICAgKiBAcGFyYW0ge09iamVjdH0gYG9wdGlvbnNgIChPcHRpb25hbCkgT3ZlcnJpZGVzIGZvciBjb25maWd1cmF0aW9uIG9wdGlvbnMuXG4gICAgICAgICAqL1xuICAgICAgICBxdWVyeTogZnVuY3Rpb24gKHFzLCBvdXRwdXRNb2RpZmllciwgb3B0aW9ucykge1xuICAgICAgICAgICAgc2VydmljZU9wdGlvbnMuZmlsdGVyID0gcXM7IC8vc2hvdWxkbid0IGJlIGFibGUgdG8gb3Zlci1yaWRlXG4gICAgICAgICAgICB2YXIgaHR0cE9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSwgc2VydmljZU9wdGlvbnMsIG9wdGlvbnMpO1xuICAgICAgICAgICAgaHR0cE9wdGlvbnMgPSB1cmxDb25maWcuYWRkQXV0b1Jlc3RvcmVIZWFkZXIoaHR0cE9wdGlvbnMpO1xuXG4gICAgICAgICAgICByZXR1cm4gaHR0cC5zcGxpdEdldChvdXRwdXRNb2RpZmllciwgaHR0cE9wdGlvbnMpO1xuICAgICAgICB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBSZXR1cm5zIHBhcnRpY3VsYXIgcnVucywgYmFzZWQgb24gY29uZGl0aW9ucyBzcGVjaWZpZWQgaW4gdGhlIGBxc2Agb2JqZWN0LlxuICAgICAgICAgKlxuICAgICAgICAgKiBTaW1pbGFyIHRvIGAucXVlcnkoKWAuXG4gICAgICAgICAqXG4gICAgICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICAgICAqIEBwYXJhbSB7T2JqZWN0fSBgZmlsdGVyYCBGaWx0ZXIgb2JqZWN0LiBFYWNoIGtleSBjYW4gYmUgYSBwcm9wZXJ0eSBvZiB0aGUgcnVuIG9yIHRoZSBuYW1lIG9mIHZhcmlhYmxlIHRoYXQgaGFzIGJlZW4gc2F2ZWQgaW4gdGhlIHJ1biAocHJlZmFjZWQgYnkgYHZhcmlhYmxlcy5gKS4gRWFjaCB2YWx1ZSBjYW4gYmUgYSBsaXRlcmFsIHZhbHVlLCBvciBhIGNvbXBhcmlzb24gb3BlcmF0b3IgYW5kIHZhbHVlLiAoU2VlIFttb3JlIG9uIGZpbHRlcmluZ10oLi4vLi4vLi4vcmVzdF9hcGlzL2FnZ3JlZ2F0ZV9ydW5fYXBpLyNmaWx0ZXJzKSBhbGxvd2VkIGluIHRoZSB1bmRlcmx5aW5nIFJ1biBBUEkuKSBGaWx0ZXJpbmcgZm9yIHZhcmlhYmxlcyBpcyBhdmFpbGFibGUgZm9yIHJ1bnMgW2luIG1lbW9yeV0oLi4vLi4vLi4vcnVuX3BlcnNpc3RlbmNlLyNydW5zLWluLW1lbW9yeSkgYW5kIGZvciBydW5zIFtpbiB0aGUgZGF0YWJhc2VdKC4uLy4uLy4uL3J1bl9wZXJzaXN0ZW5jZS8jcnVucy1pbi1tZW1vcnkpIGlmIHRoZSB2YXJpYWJsZXMgYXJlIHBlcnNpc3RlZCAoZS5nLiB0aGF0IGhhdmUgYmVlbiBgcmVjb3JkYGVkIGluIHlvdXIgSnVsaWEgbW9kZWwpLlxuICAgICAgICAgKiBAcGFyYW0ge09iamVjdH0gYG91dHB1dE1vZGlmaWVyYCAoT3B0aW9uYWwpIEF2YWlsYWJsZSBmaWVsZHMgaW5jbHVkZTogYHN0YXJ0cmVjb3JkYCwgYGVuZHJlY29yZGAsIGBzb3J0YCwgYW5kIGBkaXJlY3Rpb25gIChgYXNjYCBvciBgZGVzY2ApLlxuICAgICAgICAgKiBAcGFyYW0ge09iamVjdH0gYG9wdGlvbnNgIChPcHRpb25hbCkgT3ZlcnJpZGVzIGZvciBjb25maWd1cmF0aW9uIG9wdGlvbnMuXG4gICAgICAgICAqL1xuICAgICAgICBmaWx0ZXI6IGZ1bmN0aW9uIChmaWx0ZXIsIG91dHB1dE1vZGlmaWVyLCBvcHRpb25zKSB7XG4gICAgICAgICAgICBpZiAoJC5pc1BsYWluT2JqZWN0KHNlcnZpY2VPcHRpb25zLmZpbHRlcikpIHtcbiAgICAgICAgICAgICAgICAkLmV4dGVuZChzZXJ2aWNlT3B0aW9ucy5maWx0ZXIsIGZpbHRlcik7XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgIHNlcnZpY2VPcHRpb25zLmZpbHRlciA9IGZpbHRlcjtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHZhciBodHRwT3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LCBzZXJ2aWNlT3B0aW9ucywgb3B0aW9ucyk7XG4gICAgICAgICAgICBodHRwT3B0aW9ucyA9IHVybENvbmZpZy5hZGRBdXRvUmVzdG9yZUhlYWRlcihodHRwT3B0aW9ucyk7XG4gICAgICAgICAgICByZXR1cm4gaHR0cC5zcGxpdEdldChvdXRwdXRNb2RpZmllciwgaHR0cE9wdGlvbnMpO1xuICAgICAgICB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBHZXQgZGF0YSBmb3IgYSBzcGVjaWZpYyBydW4uIFRoaXMgaW5jbHVkZXMgc3RhbmRhcmQgcnVuIGRhdGEgc3VjaCBhcyB0aGUgYWNjb3VudCwgbW9kZWwsIHByb2plY3QsIGFuZCBjcmVhdGVkIGFuZCBsYXN0IG1vZGlmaWVkIGRhdGVzLiBUbyByZXF1ZXN0IHNwZWNpZmljIG1vZGVsIHZhcmlhYmxlcywgcGFzcyB0aGVtIGFzIHBhcnQgb2YgdGhlIGBmaWx0ZXJzYCBwYXJhbWV0ZXIuXG4gICAgICAgICAqXG4gICAgICAgICAqIE5vdGUgdGhhdCBpZiB0aGUgcnVuIGlzIFtpbiBtZW1vcnldKC4uLy4uLy4uL3J1bl9wZXJzaXN0ZW5jZS8jcnVucy1pbi1tZW1vcnkpLCBhbnkgbW9kZWwgdmFyaWFibGVzIGFyZSBhdmFpbGFibGU7IGlmIHRoZSBydW4gaXMgW2luIHRoZSBkYXRhYmFzZV0oLi4vLi4vLi4vcnVuX3BlcnNpc3RlbmNlLyNydW5zLWluLWRiKSwgb25seSBtb2RlbCB2YXJpYWJsZXMgdGhhdCBoYXZlIGJlZW4gcGVyc2lzdGVkICZtZGFzaDsgdGhhdCBpcywgYHJlY29yZGBlZCBpbiB5b3VyIEp1bGlhIG1vZGVsICZtZGFzaDsgYXJlIGF2YWlsYWJsZS5cbiAgICAgICAgICpcbiAgICAgICAgICogKipFeGFtcGxlKipcbiAgICAgICAgICpcbiAgICAgICAgICogICAgIHJzLmxvYWQoJ2JiNTg5Njc3LWQ0NzYtNDk3MS1hNjhlLTBjNThkMTkxZTQ1MCcsIHsgaW5jbHVkZTogWycucHJpY2UnLCAnLnNhbGVzJ10gfSk7XG4gICAgICAgICAqXG4gICAgICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICAgICAqIEBwYXJhbSB7U3RyaW5nfSBgcnVuSURgIFRoZSBydW4gaWQuXG4gICAgICAgICAqIEBwYXJhbSB7T2JqZWN0fSBgZmlsdGVyc2AgKE9wdGlvbmFsKSBPYmplY3QgY29udGFpbmluZyBmaWx0ZXJzIGFuZCBvcGVyYXRpb24gbW9kaWZpZXJzLiBVc2Uga2V5IGBpbmNsdWRlYCB0byBsaXN0IG1vZGVsIHZhcmlhYmxlcyB0aGF0IHlvdSB3YW50IHRvIGluY2x1ZGUgaW4gdGhlIHJlc3BvbnNlLiBPdGhlciBhdmFpbGFibGUgZmllbGRzIGluY2x1ZGU6IGBzdGFydHJlY29yZGAsIGBlbmRyZWNvcmRgLCBgc29ydGAsIGFuZCBgZGlyZWN0aW9uYCAoYGFzY2Agb3IgYGRlc2NgKS5cbiAgICAgICAgICogQHBhcmFtIHtPYmplY3R9IGBvcHRpb25zYCAoT3B0aW9uYWwpIE92ZXJyaWRlcyBmb3IgY29uZmlndXJhdGlvbiBvcHRpb25zLlxuICAgICAgICAgKi9cbiAgICAgICAgbG9hZDogZnVuY3Rpb24gKHJ1bklELCBmaWx0ZXJzLCBvcHRpb25zKSB7XG4gICAgICAgICAgICBpZiAocnVuSUQpIHtcbiAgICAgICAgICAgICAgICBzZXJ2aWNlT3B0aW9ucy5maWx0ZXIgPSBydW5JRDsgLy9zaG91bGRuJ3QgYmUgYWJsZSB0byBvdmVyLXJpZGVcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHZhciBodHRwT3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LCBzZXJ2aWNlT3B0aW9ucywgb3B0aW9ucyk7XG4gICAgICAgICAgICBodHRwT3B0aW9ucyA9IHVybENvbmZpZy5hZGRBdXRvUmVzdG9yZUhlYWRlcihodHRwT3B0aW9ucyk7XG4gICAgICAgICAgICByZXR1cm4gaHR0cC5nZXQoZmlsdGVycywgaHR0cE9wdGlvbnMpO1xuICAgICAgICB9LFxuXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIFNhdmUgYXR0cmlidXRlcyAoZGF0YSwgbW9kZWwgdmFyaWFibGVzKSBvZiB0aGUgcnVuLlxuICAgICAgICAgKlxuICAgICAgICAgKiAqKkV4YW1wbGVzKipcbiAgICAgICAgICpcbiAgICAgICAgICogICAgIC8vIGFkZCAnY29tcGxldGVkJyBmaWVsZCB0byBydW4gcmVjb3JkXG4gICAgICAgICAqICAgICBycy5zYXZlKHsgY29tcGxldGVkOiB0cnVlIH0pO1xuICAgICAgICAgKlxuICAgICAgICAgKiAgICAgLy8gdXBkYXRlICdzYXZlZCcgZmllbGQgb2YgcnVuIHJlY29yZCwgYW5kIHVwZGF0ZSB2YWx1ZXMgb2YgbW9kZWwgdmFyaWFibGVzIGZvciB0aGlzIHJ1blxuICAgICAgICAgKiAgICAgcnMuc2F2ZSh7IHNhdmVkOiB0cnVlLCB2YXJpYWJsZXM6IHsgYTogMjMsIGI6IDIzIH0gfSk7XG4gICAgICAgICAqXG4gICAgICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICAgICAqIEBwYXJhbSB7T2JqZWN0fSBgYXR0cmlidXRlc2AgVGhlIHJ1biBkYXRhIGFuZCB2YXJpYWJsZXMgdG8gc2F2ZS5cbiAgICAgICAgICogQHBhcmFtIHtPYmplY3R9IGBhdHRyaWJ1dGVzLnZhcmlhYmxlc2AgTW9kZWwgdmFyaWFibGVzIG11c3QgYmUgaW5jbHVkZWQgaW4gYSBgdmFyaWFibGVzYCBmaWVsZCB3aXRoaW4gdGhlIGBhdHRyaWJ1dGVzYCBvYmplY3QuIChPdGhlcndpc2UgdGhleSBhcmUgdHJlYXRlZCBhcyBydW4gZGF0YSBhbmQgYWRkZWQgdG8gdGhlIHJ1biByZWNvcmQgZGlyZWN0bHkuKVxuICAgICAgICAgKiBAcGFyYW0ge09iamVjdH0gYG9wdGlvbnNgIChPcHRpb25hbCkgT3ZlcnJpZGVzIGZvciBjb25maWd1cmF0aW9uIG9wdGlvbnMuXG4gICAgICAgICAqL1xuICAgICAgICBzYXZlOiBmdW5jdGlvbiAoYXR0cmlidXRlcywgb3B0aW9ucykge1xuICAgICAgICAgICAgdmFyIGh0dHBPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sIHNlcnZpY2VPcHRpb25zLCBvcHRpb25zKTtcbiAgICAgICAgICAgIHNldEZpbHRlck9yVGhyb3dFcnJvcihodHRwT3B0aW9ucyk7XG4gICAgICAgICAgICByZXR1cm4gaHR0cC5wYXRjaChhdHRyaWJ1dGVzLCBodHRwT3B0aW9ucyk7XG4gICAgICAgIH0sXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIENhbGwgYSBtZXRob2QgZnJvbSB0aGUgbW9kZWwuXG4gICAgICAgICAqXG4gICAgICAgICAqIERlcGVuZGluZyBvbiB0aGUgbGFuZ3VhZ2UgaW4gd2hpY2ggeW91IGhhdmUgd3JpdHRlbiB5b3VyIG1vZGVsLCB0aGUgbWV0aG9kIG1heSBuZWVkIHRvIGJlIGV4cG9zZWQgKGUuZy4gYGV4cG9ydGAgZm9yIGEgSnVsaWEgbW9kZWwpIGluIHRoZSBtb2RlbCBmaWxlIGluIG9yZGVyIHRvIGJlIGNhbGxlZCB0aHJvdWdoIHRoZSBBUEkuIFNlZSBbV3JpdGluZyB5b3VyIE1vZGVsXSguLi8uLi8uLi93cml0aW5nX3lvdXJfbW9kZWwvKSkuXG4gICAgICAgICAqXG4gICAgICAgICAqIFRoZSBgcGFyYW1zYCBhcmd1bWVudCBpcyBub3JtYWxseSBhbiBhcnJheSBvZiBhcmd1bWVudHMgdG8gdGhlIGBvcGVyYXRpb25gLiBJbiB0aGUgc3BlY2lhbCBjYXNlIHdoZXJlIGBvcGVyYXRpb25gIG9ubHkgdGFrZXMgb25lIGFyZ3VtZW50LCB5b3UgYXJlIG5vdCByZXF1aXJlZCB0byBwdXQgdGhhdCBhcmd1bWVudCBpbnRvIGFuIGFycmF5LlxuICAgICAgICAgKlxuICAgICAgICAgKiBOb3RlIHRoYXQgeW91IGNhbiBjb21iaW5lIHRoZSBgb3BlcmF0aW9uYCBhbmQgYHBhcmFtc2AgYXJndW1lbnRzIGludG8gYSBzaW5nbGUgb2JqZWN0IGlmIHlvdSBwcmVmZXIsIGFzIGluIHRoZSBsYXN0IGV4YW1wbGUuXG4gICAgICAgICAqXG4gICAgICAgICAqICoqRXhhbXBsZXMqKlxuICAgICAgICAgKlxuICAgICAgICAgKiAgICAgIC8vIG1ldGhvZCBcInNvbHZlXCIgdGFrZXMgbm8gYXJndW1lbnRzXG4gICAgICAgICAqICAgICBycy5kbygnc29sdmUnKTtcbiAgICAgICAgICogICAgICAvLyBtZXRob2QgXCJlY2hvXCIgdGFrZXMgb25lIGFyZ3VtZW50LCBhIHN0cmluZ1xuICAgICAgICAgKiAgICAgcnMuZG8oJ2VjaG8nLCBbJ2hlbGxvJ10pO1xuICAgICAgICAgKiAgICAgIC8vIG1ldGhvZCBcImVjaG9cIiB0YWtlcyBvbmUgYXJndW1lbnQsIGEgc3RyaW5nXG4gICAgICAgICAqICAgICBycy5kbygnZWNobycsICdoZWxsbycpO1xuICAgICAgICAgKiAgICAgIC8vIG1ldGhvZCBcInN1bUFycmF5XCIgdGFrZXMgb25lIGFyZ3VtZW50LCBhbiBhcnJheVxuICAgICAgICAgKiAgICAgcnMuZG8oJ3N1bUFycmF5JywgW1s0LDIsMV1dKTtcbiAgICAgICAgICogICAgICAvLyBtZXRob2QgXCJhZGRcIiB0YWtlcyB0d28gYXJndW1lbnRzLCBib3RoIGludGVnZXJzXG4gICAgICAgICAqICAgICBycy5kbyh7IG5hbWU6J2FkZCcsIHBhcmFtczpbMiw0XSB9KTtcbiAgICAgICAgICpcbiAgICAgICAgICogKipQYXJhbWV0ZXJzKipcbiAgICAgICAgICogQHBhcmFtIHtTdHJpbmd9IGBvcGVyYXRpb25gIE5hbWUgb2YgbWV0aG9kLlxuICAgICAgICAgKiBAcGFyYW0ge0FycmF5fSBgcGFyYW1zYCAoT3B0aW9uYWwpIEFueSBwYXJhbWV0ZXJzIHRoZSBvcGVyYXRpb24gdGFrZXMsIHBhc3NlZCBhcyBhbiBhcnJheS4gSW4gdGhlIHNwZWNpYWwgY2FzZSB3aGVyZSBgb3BlcmF0aW9uYCBvbmx5IHRha2VzIG9uZSBhcmd1bWVudCwgeW91IGFyZSBub3QgcmVxdWlyZWQgdG8gcHV0IHRoYXQgYXJndW1lbnQgaW50byBhbiBhcnJheSwgYW5kIGNhbiBqdXN0IHBhc3MgaXQgZGlyZWN0bHkuXG4gICAgICAgICAqIEBwYXJhbSB7T2JqZWN0fSBgb3B0aW9uc2AgKE9wdGlvbmFsKSBPdmVycmlkZXMgZm9yIGNvbmZpZ3VyYXRpb24gb3B0aW9ucy5cbiAgICAgICAgICovXG4gICAgICAgIGRvOiBmdW5jdGlvbiAob3BlcmF0aW9uLCBwYXJhbXMsIG9wdGlvbnMpIHtcbiAgICAgICAgICAgIC8vIGNvbnNvbGUubG9nKCdkbycsIG9wZXJhdGlvbiwgcGFyYW1zKTtcbiAgICAgICAgICAgIHZhciBvcHNBcmdzO1xuICAgICAgICAgICAgdmFyIHBvc3RPcHRpb25zO1xuICAgICAgICAgICAgaWYgKG9wdGlvbnMpIHtcbiAgICAgICAgICAgICAgICBvcHNBcmdzID0gcGFyYW1zO1xuICAgICAgICAgICAgICAgIHBvc3RPcHRpb25zID0gb3B0aW9ucztcbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgaWYgKCQuaXNQbGFpbk9iamVjdChwYXJhbXMpKSB7XG4gICAgICAgICAgICAgICAgICAgIG9wc0FyZ3MgPSBudWxsO1xuICAgICAgICAgICAgICAgICAgICBwb3N0T3B0aW9ucyA9IHBhcmFtcztcbiAgICAgICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICBvcHNBcmdzID0gcGFyYW1zO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHZhciByZXN1bHQgPSBydXRpbC5ub3JtYWxpemVPcGVyYXRpb25zKG9wZXJhdGlvbiwgb3BzQXJncyk7XG4gICAgICAgICAgICB2YXIgaHR0cE9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSwgc2VydmljZU9wdGlvbnMsIHBvc3RPcHRpb25zKTtcblxuICAgICAgICAgICAgc2V0RmlsdGVyT3JUaHJvd0Vycm9yKGh0dHBPcHRpb25zKTtcblxuICAgICAgICAgICAgdmFyIHBybXMgPSAocmVzdWx0LmFyZ3NbMF0ubGVuZ3RoICYmIChyZXN1bHQuYXJnc1swXSAhPT0gbnVsbCAmJiByZXN1bHQuYXJnc1swXSAhPT0gdW5kZWZpbmVkKSkgPyByZXN1bHQuYXJnc1swXSA6IFtdO1xuICAgICAgICAgICAgcmV0dXJuIGh0dHAucG9zdCh7IGFyZ3VtZW50czogcHJtcyB9LCAkLmV4dGVuZCh0cnVlLCB7fSwgaHR0cE9wdGlvbnMsIHtcbiAgICAgICAgICAgICAgICB1cmw6IHVybENvbmZpZy5nZXRGaWx0ZXJVUkwoKSArICdvcGVyYXRpb25zLycgKyByZXN1bHQub3BzWzBdICsgJy8nXG4gICAgICAgICAgICB9KSk7XG4gICAgICAgIH0sXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIENhbGwgc2V2ZXJhbCBtZXRob2RzIGZyb20gdGhlIG1vZGVsLCBzZXF1ZW50aWFsbHkuXG4gICAgICAgICAqXG4gICAgICAgICAqIERlcGVuZGluZyBvbiB0aGUgbGFuZ3VhZ2UgaW4gd2hpY2ggeW91IGhhdmUgd3JpdHRlbiB5b3VyIG1vZGVsLCB0aGUgbWV0aG9kcyBtYXkgbmVlZCB0byBiZSBleHBvc2VkIChlLmcuIGBleHBvcnRgIGZvciBhIEp1bGlhIG1vZGVsKSBpbiB0aGUgbW9kZWwgZmlsZSBpbiBvcmRlciB0byBiZSBjYWxsZWQgdGhyb3VnaCB0aGUgQVBJLiBTZWUgW1dyaXRpbmcgeW91ciBNb2RlbF0oLi4vLi4vLi4vd3JpdGluZ195b3VyX21vZGVsLykpLlxuICAgICAgICAgKlxuICAgICAgICAgKiAqKkV4YW1wbGVzKipcbiAgICAgICAgICpcbiAgICAgICAgICogICAgICAvLyBtZXRob2RzIFwiaW5pdGlhbGl6ZVwiIGFuZCBcInNvbHZlXCIgZG8gbm90IHRha2UgYW55IGFyZ3VtZW50c1xuICAgICAgICAgKiAgICAgcnMuc2VyaWFsKFsnaW5pdGlhbGl6ZScsICdzb2x2ZSddKTtcbiAgICAgICAgICogICAgICAvLyBtZXRob2RzIFwiaW5pdFwiIGFuZCBcInJlc2V0XCIgdGFrZSB0d28gYXJndW1lbnRzIGVhY2hcbiAgICAgICAgICogICAgIHJzLnNlcmlhbChbICB7IG5hbWU6ICdpbml0JywgcGFyYW1zOiBbMSwyXSB9LFxuICAgICAgICAgKiAgICAgICAgICAgICAgICAgIHsgbmFtZTogJ3Jlc2V0JywgcGFyYW1zOiBbMiwzXSB9XSk7XG4gICAgICAgICAqICAgICAgLy8gbWV0aG9kIFwiaW5pdFwiIHRha2VzIHR3byBhcmd1bWVudHMsXG4gICAgICAgICAqICAgICAgLy8gbWV0aG9kIFwicnVubW9kZWxcIiB0YWtlcyBub25lXG4gICAgICAgICAqICAgICBycy5zZXJpYWwoWyAgeyBuYW1lOiAnaW5pdCcsIHBhcmFtczogWzEsMl0gfSxcbiAgICAgICAgICogICAgICAgICAgICAgICAgICB7IG5hbWU6ICdydW5tb2RlbCcsIHBhcmFtczogW10gfV0pO1xuICAgICAgICAgKlxuICAgICAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAgKiBAcGFyYW0ge0FycmF5fSBgb3BlcmF0aW9uc2AgSWYgbm9uZSBvZiB0aGUgbWV0aG9kcyB0YWtlIHBhcmFtZXRlcnMsIHBhc3MgYW4gYXJyYXkgb2YgdGhlIG1ldGhvZCBuYW1lcyAoc3RyaW5ncykuIElmIGFueSBvZiB0aGUgbWV0aG9kcyBkbyB0YWtlIHBhcmFtZXRlcnMsIHBhc3MgYW4gYXJyYXkgb2Ygb2JqZWN0cywgZWFjaCBvZiB3aGljaCBjb250YWlucyBhIG1ldGhvZCBuYW1lIGFuZCBpdHMgb3duIChwb3NzaWJseSBlbXB0eSkgYXJyYXkgb2YgcGFyYW1ldGVycy5cbiAgICAgICAgICogQHBhcmFtIHsqfSBgcGFyYW1zYCBQYXJhbWV0ZXJzIHRvIHBhc3MgdG8gb3BlcmF0aW9ucy5cbiAgICAgICAgICogQHBhcmFtIHtPYmplY3R9IGBvcHRpb25zYCAoT3B0aW9uYWwpIE92ZXJyaWRlcyBmb3IgY29uZmlndXJhdGlvbiBvcHRpb25zLlxuICAgICAgICAgKi9cbiAgICAgICAgc2VyaWFsOiBmdW5jdGlvbiAob3BlcmF0aW9ucywgcGFyYW1zLCBvcHRpb25zKSB7XG4gICAgICAgICAgICB2YXIgb3BQYXJhbXMgPSBydXRpbC5ub3JtYWxpemVPcGVyYXRpb25zKG9wZXJhdGlvbnMsIHBhcmFtcyk7XG4gICAgICAgICAgICB2YXIgb3BzID0gb3BQYXJhbXMub3BzO1xuICAgICAgICAgICAgdmFyIGFyZ3MgPSBvcFBhcmFtcy5hcmdzO1xuICAgICAgICAgICAgdmFyIG1lID0gdGhpcztcblxuICAgICAgICAgICAgdmFyICRkID0gJC5EZWZlcnJlZCgpO1xuICAgICAgICAgICAgdmFyIHBvc3RPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sIHNlcnZpY2VPcHRpb25zLCBvcHRpb25zKTtcblxuICAgICAgICAgICAgdmFyIGRvU2luZ2xlT3AgPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICAgICAgdmFyIG9wID0gb3BzLnNoaWZ0KCk7XG4gICAgICAgICAgICAgICAgdmFyIGFyZyA9IGFyZ3Muc2hpZnQoKTtcblxuICAgICAgICAgICAgICAgIG1lLmRvKG9wLCBhcmcsIHtcbiAgICAgICAgICAgICAgICAgICAgc3VjY2VzczogZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgICAgICAgICAgICAgaWYgKG9wcy5sZW5ndGgpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBkb1NpbmdsZU9wKCk7XG4gICAgICAgICAgICAgICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICRkLnJlc29sdmUuYXBwbHkodGhpcywgYXJndW1lbnRzKTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBwb3N0T3B0aW9ucy5zdWNjZXNzLmFwcGx5KHRoaXMsIGFyZ3VtZW50cyk7XG4gICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICAgICAgICAgIGVycm9yOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAkZC5yZWplY3QuYXBwbHkodGhpcywgYXJndW1lbnRzKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIHBvc3RPcHRpb25zLmVycm9yLmFwcGx5KHRoaXMsIGFyZ3VtZW50cyk7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgIH07XG5cbiAgICAgICAgICAgIGRvU2luZ2xlT3AoKTtcblxuICAgICAgICAgICAgcmV0dXJuICRkLnByb21pc2UoKTtcbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgICogQ2FsbCBzZXZlcmFsIG1ldGhvZHMgZnJvbSB0aGUgbW9kZWwsIGV4ZWN1dGluZyB0aGVtIGluIHBhcmFsbGVsLlxuICAgICAgICAgKlxuICAgICAgICAgKiBEZXBlbmRpbmcgb24gdGhlIGxhbmd1YWdlIGluIHdoaWNoIHlvdSBoYXZlIHdyaXR0ZW4geW91ciBtb2RlbCwgdGhlIG1ldGhvZHMgbWF5IG5lZWQgdG8gYmUgZXhwb3NlZCAoZS5nLiBgZXhwb3J0YCBmb3IgYSBKdWxpYSBtb2RlbCkgaW4gdGhlIG1vZGVsIGZpbGUgaW4gb3JkZXIgdG8gYmUgY2FsbGVkIHRocm91Z2ggdGhlIEFQSS4gU2VlIFtXcml0aW5nIHlvdXIgTW9kZWxdKC4uLy4uLy4uL3dyaXRpbmdfeW91cl9tb2RlbC8pKS5cbiAgICAgICAgICpcbiAgICAgICAgICogKipFeGFtcGxlKipcbiAgICAgICAgICpcbiAgICAgICAgICogICAgICAvLyBtZXRob2RzIFwic29sdmVcIiBhbmQgXCJyZXNldFwiIGRvIG5vdCB0YWtlIGFueSBhcmd1bWVudHNcbiAgICAgICAgICogICAgIHJzLnBhcmFsbGVsKFsnc29sdmUnLCAncmVzZXQnXSk7XG4gICAgICAgICAqICAgICAgLy8gbWV0aG9kcyBcImFkZFwiIGFuZCBcInN1YnRyYWN0XCIgdGFrZSB0d28gYXJndW1lbnRzIGVhY2hcbiAgICAgICAgICogICAgIHJzLnBhcmFsbGVsKFsgeyBuYW1lOiAnYWRkJywgcGFyYW1zOiBbMSwyXSB9LFxuICAgICAgICAgKiAgICAgICAgICAgICAgICAgICB7IG5hbWU6ICdzdWJ0cmFjdCcsIHBhcmFtczpbMiwzXSB9XSk7XG4gICAgICAgICAqICAgICAgLy8gbWV0aG9kcyBcImFkZFwiIGFuZCBcInN1YnRyYWN0XCIgdGFrZSB0d28gYXJndW1lbnRzIGVhY2hcbiAgICAgICAgICogICAgIHJzLnBhcmFsbGVsKHsgYWRkOiBbMSwyXSwgc3VidHJhY3Q6IFsyLDRdIH0pO1xuICAgICAgICAgKlxuICAgICAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAgKiBAcGFyYW0ge0FycmF5fE9iamVjdH0gYG9wZXJhdGlvbnNgIElmIG5vbmUgb2YgdGhlIG1ldGhvZHMgdGFrZSBwYXJhbWV0ZXJzLCBwYXNzIGFuIGFycmF5IG9mIHRoZSBtZXRob2QgbmFtZXMgKGFzIHN0cmluZ3MpLiBJZiBhbnkgb2YgdGhlIG1ldGhvZHMgZG8gdGFrZSBwYXJhbWV0ZXJzLCB5b3UgaGF2ZSB0d28gb3B0aW9ucy4gWW91IGNhbiBwYXNzIGFuIGFycmF5IG9mIG9iamVjdHMsIGVhY2ggb2Ygd2hpY2ggY29udGFpbnMgYSBtZXRob2QgbmFtZSBhbmQgaXRzIG93biAocG9zc2libHkgZW1wdHkpIGFycmF5IG9mIHBhcmFtZXRlcnMuIEFsdGVybmF0aXZlbHksIHlvdSBjYW4gcGFzcyBhIHNpbmdsZSBvYmplY3Qgd2l0aCB0aGUgbWV0aG9kIG5hbWUgYW5kIGEgKHBvc3NpYmx5IGVtcHR5KSBhcnJheSBvZiBwYXJhbWV0ZXJzLlxuICAgICAgICAgKiBAcGFyYW0geyp9IGBwYXJhbXNgIFBhcmFtZXRlcnMgdG8gcGFzcyB0byBvcGVyYXRpb25zLlxuICAgICAgICAgKiBAcGFyYW0ge09iamVjdH0gYG9wdGlvbnNgIChPcHRpb25hbCkgT3ZlcnJpZGVzIGZvciBjb25maWd1cmF0aW9uIG9wdGlvbnMuXG4gICAgICAgICAqL1xuICAgICAgICBwYXJhbGxlbDogZnVuY3Rpb24gKG9wZXJhdGlvbnMsIHBhcmFtcywgb3B0aW9ucykge1xuICAgICAgICAgICAgdmFyICRkID0gJC5EZWZlcnJlZCgpO1xuXG4gICAgICAgICAgICB2YXIgb3BQYXJhbXMgPSBydXRpbC5ub3JtYWxpemVPcGVyYXRpb25zKG9wZXJhdGlvbnMsIHBhcmFtcyk7XG4gICAgICAgICAgICB2YXIgb3BzID0gb3BQYXJhbXMub3BzO1xuICAgICAgICAgICAgdmFyIGFyZ3MgPSBvcFBhcmFtcy5hcmdzO1xuICAgICAgICAgICAgdmFyIHBvc3RPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sIHNlcnZpY2VPcHRpb25zLCBvcHRpb25zKTtcblxuICAgICAgICAgICAgdmFyIHF1ZXVlICA9IFtdO1xuICAgICAgICAgICAgZm9yICh2YXIgaSA9IDA7IGk8IG9wcy5sZW5ndGg7IGkrKykge1xuICAgICAgICAgICAgICAgIHF1ZXVlLnB1c2goXG4gICAgICAgICAgICAgICAgICAgIHRoaXMuZG8ob3BzW2ldLCBhcmdzW2ldKVxuICAgICAgICAgICAgICAgICk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICAkLndoZW4uYXBwbHkodGhpcywgcXVldWUpXG4gICAgICAgICAgICAgICAgLmRvbmUoZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgICAgICAgICAkZC5yZXNvbHZlLmFwcGx5KHRoaXMsIGFyZ3VtZW50cyk7XG4gICAgICAgICAgICAgICAgICAgIHBvc3RPcHRpb25zLnN1Y2Nlc3MuYXBwbHkodGhpcy5hcmd1bWVudHMpO1xuICAgICAgICAgICAgICAgIH0pXG4gICAgICAgICAgICAgICAgLmZhaWwoZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgICAgICAgICAkZC5yZWplY3QuYXBwbHkodGhpcywgYXJndW1lbnRzKTtcbiAgICAgICAgICAgICAgICAgICAgcG9zdE9wdGlvbnMuZXJyb3IuYXBwbHkodGhpcy5hcmd1bWVudHMpO1xuICAgICAgICAgICAgICAgIH0pO1xuXG4gICAgICAgICAgICByZXR1cm4gJGQucHJvbWlzZSgpO1xuICAgICAgICB9XG4gICAgfTtcblxuICAgIHZhciBwdWJsaWNTeW5jQVBJID0ge1xuICAgICAgICBnZXRDdXJyZW50Q29uZmlnOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICByZXR1cm4gc2VydmljZU9wdGlvbnM7XG4gICAgICAgIH0sXG4gICAgICAgIC8qKlxuICAgICAgICAgICogUmV0dXJucyBhIFZhcmlhYmxlcyBTZXJ2aWNlIGluc3RhbmNlLiBVc2UgdGhlIHZhcmlhYmxlcyBpbnN0YW5jZSB0byBsb2FkLCBzYXZlLCBhbmQgcXVlcnkgZm9yIHNwZWNpZmljIG1vZGVsIHZhcmlhYmxlcy4gU2VlIHRoZSBbVmFyaWFibGUgQVBJIFNlcnZpY2VdKC4uL3ZhcmlhYmxlcy1hcGktc2VydmljZS8pIGZvciBtb3JlIGluZm9ybWF0aW9uLlxuICAgICAgICAgICpcbiAgICAgICAgICAqICoqRXhhbXBsZSoqXG4gICAgICAgICAgKlxuICAgICAgICAgICogICAgICB2YXIgdnMgPSBycy52YXJpYWJsZXMoKTtcbiAgICAgICAgICAqICAgICAgdnMuc2F2ZSh7IHNhbXBsZV9pbnQ6IDQgfSk7XG4gICAgICAgICAgKlxuICAgICAgICAgICogKipQYXJhbWV0ZXJzKipcbiAgICAgICAgICAqIEBwYXJhbSB7T2JqZWN0fSBgY29uZmlnYCAoT3B0aW9uYWwpIE92ZXJyaWRlcyBmb3IgY29uZmlndXJhdGlvbiBvcHRpb25zLlxuICAgICAgICAgICovXG4gICAgICAgIHZhcmlhYmxlczogZnVuY3Rpb24gKGNvbmZpZykge1xuICAgICAgICAgICAgdmFyIHZzID0gbmV3IFZhcmlhYmxlc1NlcnZpY2UoJC5leHRlbmQodHJ1ZSwge30sIHNlcnZpY2VPcHRpb25zLCBjb25maWcsIHtcbiAgICAgICAgICAgICAgICBydW5TZXJ2aWNlOiB0aGlzXG4gICAgICAgICAgICB9KSk7XG4gICAgICAgICAgICByZXR1cm4gdnM7XG4gICAgICAgIH1cbiAgICB9O1xuXG4gICAgJC5leHRlbmQodGhpcywgcHVibGljQXN5bmNBUEkpO1xuICAgICQuZXh0ZW5kKHRoaXMsIHB1YmxpY1N5bmNBUEkpO1xufTtcbiIsIid1c2Ugc3RyaWN0JztcblxudmFyIENvbmZpZ1NlcnZpY2UgPSByZXF1aXJlKCcuL2NvbmZpZ3VyYXRpb24tc2VydmljZScpO1xudmFyIFNlc3Npb25NYW5hZ2VyID0gcmVxdWlyZSgnLi4vc3RvcmUvc2Vzc2lvbi1tYW5hZ2VyJyk7XG52YXIgb2JqZWN0QXNzaWduID0gcmVxdWlyZSgnb2JqZWN0LWFzc2lnbicpO1xuXG52YXIgc2VydmljZVV0aWxzID0ge1xuICAgIC8qXG4gICAgKiBHZXRzIHRoZSBkZWZhdWx0IG9wdGlvbnMgZm9yIGEgYXBpIHNlcnZpY2UuXG4gICAgKiBJdCB3aWxsIG1lcmdlOlxuICAgICogLSBUaGUgU2Vzc2lvbiBvcHRpb25zIChVc2luZyB0aGUgU2Vzc2lvbiBNYW5hZ2VyKVxuICAgICogLSBUaGUgQXV0aG9yaXphdGlvbiBIZWFkZXIgZnJvbSB0aGUgdG9rZW4gb3B0aW9uXG4gICAgKiAtIFRoZSBmdWxsIHVybCBmcm9tIHRoZSBlbmRwb2ludCBvcHRpb25cbiAgICAqIFdpdGggdGhlIHN1cHBsaWVkIG92ZXJyaWRlcyBhbmQgZGVmYXVsdHNcbiAgICAqXG4gICAgKi9cbiAgICBnZXREZWZhdWx0T3B0aW9uczogZnVuY3Rpb24gKGRlZmF1bHRzKSB7XG4gICAgICAgIHZhciByZXN0ID0gQXJyYXkucHJvdG90eXBlLnNsaWNlLmNhbGwoYXJndW1lbnRzLCAxKTtcbiAgICAgICAgdmFyIHNlc3Npb25NYW5hZ2VyID0gbmV3IFNlc3Npb25NYW5hZ2VyKCk7XG4gICAgICAgIHZhciBzZXJ2aWNlT3B0aW9ucyA9IHNlc3Npb25NYW5hZ2VyLmdldE1lcmdlZE9wdGlvbnMuYXBwbHkoc2Vzc2lvbk1hbmFnZXIsIFtkZWZhdWx0c10uY29uY2F0KHJlc3QpKTtcblxuICAgICAgICBzZXJ2aWNlT3B0aW9ucy50cmFuc3BvcnQgPSBvYmplY3RBc3NpZ24oe30sIHNlcnZpY2VPcHRpb25zLnRyYW5zcG9ydCwge1xuICAgICAgICAgICAgdXJsOiB0aGlzLmdldEFwaVVybChzZXJ2aWNlT3B0aW9ucy5hcGlFbmRwb2ludCwgc2VydmljZU9wdGlvbnMpXG4gICAgICAgIH0pO1xuXG4gICAgICAgIGlmIChzZXJ2aWNlT3B0aW9ucy50b2tlbikge1xuICAgICAgICAgICAgc2VydmljZU9wdGlvbnMudHJhbnNwb3J0LmhlYWRlcnMgPSB7XG4gICAgICAgICAgICAgICAgJ0F1dGhvcml6YXRpb24nOiAnQmVhcmVyICcgKyBzZXJ2aWNlT3B0aW9ucy50b2tlblxuICAgICAgICAgICAgfTtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gc2VydmljZU9wdGlvbnM7XG4gICAgfSxcblxuICAgIGdldEFwaVVybDogZnVuY3Rpb24gKGFwaUVuZHBvaW50LCBzZXJ2aWNlT3B0aW9ucykge1xuICAgICAgICB2YXIgdXJsQ29uZmlnID0gbmV3IENvbmZpZ1NlcnZpY2Uoc2VydmljZU9wdGlvbnMpLmdldCgnc2VydmVyJyk7XG4gICAgICAgIHJldHVybiB1cmxDb25maWcuZ2V0QVBJUGF0aChhcGlFbmRwb2ludCk7XG4gICAgfVxufTtcblxubW9kdWxlLmV4cG9ydHMgPSBzZXJ2aWNlVXRpbHM7IiwiJ3VzZSBzdHJpY3QnO1xuLyoqXG4gKiAjIyBTdGF0ZSBBUEkgQWRhcHRlclxuICpcbiAqIFRoZSBTdGF0ZSBBUEkgQWRhcHRlciBhbGxvd3MgeW91IHRvIHJlcGxheSBvciBjbG9uZSBydW5zLiBJdCBicmluZ3MgZXhpc3RpbmcsIHBlcnNpc3RlZCBydW4gZGF0YSBmcm9tIHRoZSBkYXRhYmFzZSBiYWNrIGludG8gbWVtb3J5LCB1c2luZyB0aGUgc2FtZSBydW4gaWQgKGByZXBsYXlgKSBvciBhIG5ldyBydW4gaWQgKGBjbG9uZWApLiBSdW5zIG11c3QgYmUgaW4gbWVtb3J5IGluIG9yZGVyIGZvciB5b3UgdG8gdXBkYXRlIHZhcmlhYmxlcyBvciBjYWxsIG9wZXJhdGlvbnMgb24gdGhlbS5cbiAqXG4gKiBTcGVjaWZpY2FsbHksIHRoZSBTdGF0ZSBBUEkgQWRhcHRlciB3b3JrcyBieSBcInJlLXJ1bm5pbmdcIiB0aGUgcnVuICh1c2VyIGludGVyYWN0aW9ucykgZnJvbSB0aGUgY3JlYXRpb24gb2YgdGhlIHJ1biB1cCB0byB0aGUgdGltZSBpdCB3YXMgbGFzdCBwZXJzaXN0ZWQgaW4gdGhlIGRhdGFiYXNlLiBUaGlzIHByb2Nlc3MgdXNlcyB0aGUgY3VycmVudCB2ZXJzaW9uIG9mIHRoZSBydW4ncyBtb2RlbC4gVGhlcmVmb3JlLCBpZiB0aGUgbW9kZWwgaGFzIGNoYW5nZWQgc2luY2UgdGhlIG9yaWdpbmFsIHJ1biB3YXMgY3JlYXRlZCwgdGhlIHJldHJpZXZlZCBydW4gd2lsbCB1c2UgdGhlIG5ldyBtb2RlbCDigJQgYW5kIG1heSBlbmQgdXAgaGF2aW5nIGRpZmZlcmVudCB2YWx1ZXMgb3IgYmVoYXZpb3IgYXMgYSByZXN1bHQuIFVzZSB3aXRoIGNhcmUhXG4gKlxuICogVG8gdXNlIHRoZSBTdGF0ZSBBUEkgQWRhcHRlciwgaW5zdGFudGlhdGUgaXQgYW5kIHRoZW4gY2FsbCBpdHMgbWV0aG9kczpcbiAqXG4gKiAgICAgIHZhciBzYSA9IG5ldyBGLnNlcnZpY2UuU3RhdGUoKTtcbiAqICAgICAgc2EucmVwbGF5KHtydW5JZDogJzE4NDJiYjVjLTgzYWQtNGJhOC1hOTU1LWJkMTNjYzJmZGI0Zid9KTtcbiAqXG4gKiBUaGUgY29uc3RydWN0b3IgdGFrZXMgYW4gb3B0aW9uYWwgYG9wdGlvbnNgIHBhcmFtZXRlciBpbiB3aGljaCB5b3UgY2FuIHNwZWNpZnkgdGhlIGBhY2NvdW50YCBhbmQgYHByb2plY3RgIGlmIHRoZXkgYXJlIG5vdCBhbHJlYWR5IGF2YWlsYWJsZSBpbiB0aGUgY3VycmVudCBjb250ZXh0LlxuICpcbiAqL1xuXG52YXIgQ29uZmlnU2VydmljZSA9IHJlcXVpcmUoJy4vY29uZmlndXJhdGlvbi1zZXJ2aWNlJyk7XG52YXIgVHJhbnNwb3J0RmFjdG9yeSA9IHJlcXVpcmUoJy4uL3RyYW5zcG9ydC9odHRwLXRyYW5zcG9ydC1mYWN0b3J5Jyk7XG52YXIgX3BpY2sgPSByZXF1aXJlKCcuLi91dGlsL29iamVjdC11dGlsJykuX3BpY2s7XG52YXIgU2Vzc2lvbk1hbmFnZXIgPSByZXF1aXJlKCcuLi9zdG9yZS9zZXNzaW9uLW1hbmFnZXInKTtcbnZhciBhcGlFbmRwb2ludCA9ICdtb2RlbC9zdGF0ZSc7XG5cbm1vZHVsZS5leHBvcnRzID0gZnVuY3Rpb24gKGNvbmZpZykge1xuXG4gICAgdmFyIGRlZmF1bHRzID0ge1xuXG4gICAgfTtcblxuICAgIHRoaXMuc2Vzc2lvbk1hbmFnZXIgPSBuZXcgU2Vzc2lvbk1hbmFnZXIoKTtcbiAgICB2YXIgc2VydmljZU9wdGlvbnMgPSB0aGlzLnNlc3Npb25NYW5hZ2VyLmdldE1lcmdlZE9wdGlvbnMoZGVmYXVsdHMsIGNvbmZpZyk7XG4gICAgdmFyIHVybENvbmZpZyA9IG5ldyBDb25maWdTZXJ2aWNlKHNlcnZpY2VPcHRpb25zKS5nZXQoJ3NlcnZlcicpO1xuXG4gICAgdmFyIHRyYW5zcG9ydE9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSwgc2VydmljZU9wdGlvbnMudHJhbnNwb3J0LCB7XG4gICAgICAgIHVybDogdXJsQ29uZmlnLmdldEFQSVBhdGgoYXBpRW5kcG9pbnQpXG4gICAgfSk7XG5cbiAgICBpZiAoc2VydmljZU9wdGlvbnMudG9rZW4pIHtcbiAgICAgICAgdHJhbnNwb3J0T3B0aW9ucy5oZWFkZXJzID0ge1xuICAgICAgICAgICAgJ0F1dGhvcml6YXRpb24nOiAnQmVhcmVyICcgKyBzZXJ2aWNlT3B0aW9ucy50b2tlblxuICAgICAgICB9O1xuICAgIH1cblxuICAgIHZhciBodHRwID0gbmV3IFRyYW5zcG9ydEZhY3RvcnkodHJhbnNwb3J0T3B0aW9ucyk7XG4gICAgdmFyIHBhcnNlUnVuSWRPckVycm9yID0gZnVuY3Rpb24gKHBhcmFtcykge1xuICAgICAgICBpZiAoJC5pc1BsYWluT2JqZWN0KHBhcmFtcykgJiYgcGFyYW1zLnJ1bklkKSB7XG4gICAgICAgICAgICByZXR1cm4gcGFyYW1zLnJ1bklkO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdQbGVhc2UgcGFzcyBpbiBhIHJ1biBpZCcpO1xuICAgICAgICB9XG4gICAgfTtcblxuICAgIHZhciBwdWJsaWNBUEkgPSB7XG4gICAgICAgIC8qKlxuICAgICAgICAqIFJlcGxheSBhIHJ1bi4gQWZ0ZXIgdGhpcyBjYWxsLCB0aGUgcnVuLCB3aXRoIGl0cyBvcmlnaW5hbCBydW4gaWQsIGlzIG5vdyBhdmFpbGFibGUgW2luIG1lbW9yeV0oLi4vLi4vLi4vcnVuX3BlcnNpc3RlbmNlLyNydW5zLWluLW1lbW9yeSkuIChJdCBjb250aW51ZXMgdG8gYmUgcGVyc2lzdGVkIGludG8gdGhlIEVwaWNlbnRlciBkYXRhYmFzZSBhdCByZWd1bGFyIGludGVydmFscy4pXG4gICAgICAgICpcbiAgICAgICAgKiAgKipFeGFtcGxlKipcbiAgICAgICAgKlxuICAgICAgICAqICAgICAgdmFyIHNhID0gbmV3IEYuc2VydmljZS5TdGF0ZSgpO1xuICAgICAgICAqICAgICAgc2EucmVwbGF5KHtydW5JZDogJzE4NDJiYjVjLTgzYWQtNGJhOC1hOTU1LWJkMTNjYzJmZGI0ZicsIHN0b3BCZWZvcmU6ICdjYWxjdWxhdGVTY29yZSd9KTtcbiAgICAgICAgKlxuICAgICAgICAqICAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAqIEBwYXJhbSB7b2JqZWN0fSBgcGFyYW1zYCBQYXJhbWV0ZXJzIG9iamVjdC5cbiAgICAgICAgKiBAcGFyYW0ge3N0cmluZ30gYHBhcmFtcy5ydW5JZGAgVGhlIGlkIG9mIHRoZSBydW4gdG8gYnJpbmcgYmFjayB0byBtZW1vcnkuXG4gICAgICAgICogQHBhcmFtIHtzdHJpbmd9IGBwYXJhbXMuc3RvcEJlZm9yZWAgKE9wdGlvbmFsKSBUaGUgcnVuIGlzIGFkdmFuY2VkIG9ubHkgdXAgdG8gdGhlIGZpcnN0IG9jY3VycmVuY2Ugb2YgdGhpcyBtZXRob2QuXG4gICAgICAgICogQHBhcmFtIHthcnJheX0gYHBhcmFtcy5leGNsdWRlYCAoT3B0aW9uYWwpIEFycmF5IG9mIG1ldGhvZHMgdG8gZXhjbHVkZSB3aGVuIGFkdmFuY2luZyB0aGUgcnVuLlxuICAgICAgICAqIEBwYXJhbSB7b2JqZWN0fSBgb3B0aW9uc2AgKE9wdGlvbmFsKSBPdmVycmlkZXMgZm9yIGNvbmZpZ3VyYXRpb24gb3B0aW9ucy5cbiAgICAgICAgKi9cbiAgICAgICAgcmVwbGF5OiBmdW5jdGlvbiAocGFyYW1zLCBvcHRpb25zKSB7XG4gICAgICAgICAgICB2YXIgcnVuSWQgPSBwYXJzZVJ1bklkT3JFcnJvcihwYXJhbXMpO1xuXG4gICAgICAgICAgICB2YXIgcmVwbGF5T3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LFxuICAgICAgICAgICAgICAgIHNlcnZpY2VPcHRpb25zLFxuICAgICAgICAgICAgICAgIG9wdGlvbnMsXG4gICAgICAgICAgICAgICAgeyB1cmw6IHVybENvbmZpZy5nZXRBUElQYXRoKGFwaUVuZHBvaW50KSArIHJ1bklkIH1cbiAgICAgICAgICAgICk7XG5cbiAgICAgICAgICAgIHBhcmFtcyA9ICQuZXh0ZW5kKHRydWUsIHsgYWN0aW9uOiAncmVwbGF5JyB9LCBfcGljayhwYXJhbXMsIFsnc3RvcEJlZm9yZScsICdleGNsdWRlJ10pKTtcblxuICAgICAgICAgICAgcmV0dXJuIGh0dHAucG9zdChwYXJhbXMsIHJlcGxheU9wdGlvbnMpO1xuICAgICAgICB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAqIENsb25lIGEgZ2l2ZW4gcnVuIGFuZCByZXR1cm4gYSBuZXcgcnVuIGluIHRoZSBzYW1lIHN0YXRlIGFzIHRoZSBnaXZlbiBydW4uXG4gICAgICAgICpcbiAgICAgICAgKiBUaGUgbmV3IHJ1biBpZCBpcyBub3cgYXZhaWxhYmxlIFtpbiBtZW1vcnldKC4uLy4uLy4uL3J1bl9wZXJzaXN0ZW5jZS8jcnVucy1pbi1tZW1vcnkpLiBUaGUgbmV3IHJ1biBpbmNsdWRlcyBhIGNvcHkgb2YgYWxsIG9mIHRoZSBkYXRhIGZyb20gdGhlIG9yaWdpbmFsIHJ1biwgRVhDRVBUOlxuICAgICAgICAqXG4gICAgICAgICogKiBUaGUgYHNhdmVkYCBmaWVsZCBpbiB0aGUgbmV3IHJ1biByZWNvcmQgaXMgbm90IGNvcGllZCBmcm9tIHRoZSBvcmlnaW5hbCBydW4gcmVjb3JkLiBJdCBkZWZhdWx0cyB0byBgZmFsc2VgLlxuICAgICAgICAqICogVGhlIGBpbml0aWFsaXplZGAgZmllbGQgaW4gdGhlIG5ldyBydW4gcmVjb3JkIGlzIG5vdCBjb3BpZWQgZnJvbSB0aGUgb3JpZ2luYWwgcnVuIHJlY29yZC4gSXQgZGVmYXVsdHMgdG8gYGZhbHNlYCBidXQgbWF5IGNoYW5nZSB0byBgdHJ1ZWAgYXMgdGhlIG5ldyBydW4gaXMgYWR2YW5jZWQuIEZvciBleGFtcGxlLCBpZiB0aGVyZSBoYXMgYmVlbiBhIGNhbGwgdG8gdGhlIGBzdGVwYCBmdW5jdGlvbiAoZm9yIFZlbnNpbSBtb2RlbHMpLCB0aGUgYGluaXRpYWxpemVkYCBmaWVsZCBpcyBzZXQgdG8gYHRydWVgLlxuICAgICAgICAqICogVGhlIGBjcmVhdGVkYCBmaWVsZCBpbiB0aGUgbmV3IHJ1biByZWNvcmQgaXMgdGhlIGRhdGUgYW5kIHRpbWUgYXQgd2hpY2ggdGhlIGNsb25lIHdhcyBjcmVhdGVkIChub3QgdGhlIHRpbWUgdGhhdCB0aGUgb3JpZ2luYWwgcnVuIHdhcyBjcmVhdGVkLilcbiAgICAgICAgKlxuICAgICAgICAqIFRoZSBvcmlnaW5hbCBydW4gcmVtYWlucyBvbmx5IFtpbiB0aGUgZGF0YWJhc2VdKC4uLy4uLy4uL3J1bl9wZXJzaXN0ZW5jZS8jcnVucy1pbi1kYikuXG4gICAgICAgICpcbiAgICAgICAgKiAgKipFeGFtcGxlKipcbiAgICAgICAgKlxuICAgICAgICAqICAgICAgdmFyIHNhID0gbmV3IEYuc2VydmljZS5TdGF0ZSgpO1xuICAgICAgICAqICAgICAgc2EuY2xvbmUoe3J1bklkOiAnMTg0MmJiNWMtODNhZC00YmE4LWE5NTUtYmQxM2NjMmZkYjRmJywgc3RvcEJlZm9yZTogJ2NhbGN1bGF0ZVNjb3JlJywgZXhjbHVkZTogWydpbnRlcmltQ2FsY3VsYXRpb24nXSB9KTtcbiAgICAgICAgKlxuICAgICAgICAqICAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAqIEBwYXJhbSB7b2JqZWN0fSBgcGFyYW1zYCBQYXJhbWV0ZXJzIG9iamVjdC5cbiAgICAgICAgKiBAcGFyYW0ge3N0cmluZ30gYHBhcmFtcy5ydW5JZGAgVGhlIGlkIG9mIHRoZSBydW4gdG8gY2xvbmUgZnJvbSBtZW1vcnkuXG4gICAgICAgICogQHBhcmFtIHtzdHJpbmd9IGBwYXJhbXMuc3RvcEJlZm9yZWAgKE9wdGlvbmFsKSBUaGUgbmV3bHkgY2xvbmVkIHJ1biBpcyBhZHZhbmNlZCBvbmx5IHVwIHRvIHRoZSBmaXJzdCBvY2N1cnJlbmNlIG9mIHRoaXMgbWV0aG9kLlxuICAgICAgICAqIEBwYXJhbSB7YXJyYXl9IGBwYXJhbXMuZXhjbHVkZWAgKE9wdGlvbmFsKSBBcnJheSBvZiBtZXRob2RzIHRvIGV4Y2x1ZGUgd2hlbiBhZHZhbmNpbmcgdGhlIG5ld2x5IGNsb25lZCBydW4uXG4gICAgICAgICogQHBhcmFtIHtvYmplY3R9IGBvcHRpb25zYCAoT3B0aW9uYWwpIE92ZXJyaWRlcyBmb3IgY29uZmlndXJhdGlvbiBvcHRpb25zLlxuICAgICAgICAqL1xuICAgICAgICBjbG9uZTogZnVuY3Rpb24gKHBhcmFtcywgb3B0aW9ucykge1xuICAgICAgICAgICAgdmFyIHJ1bklkID0gcGFyc2VSdW5JZE9yRXJyb3IocGFyYW1zKTtcblxuICAgICAgICAgICAgdmFyIHJlcGxheU9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSxcbiAgICAgICAgICAgICAgICBzZXJ2aWNlT3B0aW9ucyxcbiAgICAgICAgICAgICAgICBvcHRpb25zLFxuICAgICAgICAgICAgICAgIHsgdXJsOiB1cmxDb25maWcuZ2V0QVBJUGF0aChhcGlFbmRwb2ludCkgKyBydW5JZCB9XG4gICAgICAgICAgICApO1xuXG4gICAgICAgICAgICBwYXJhbXMgPSAkLmV4dGVuZCh0cnVlLCB7IGFjdGlvbjogJ2Nsb25lJyB9LCBfcGljayhwYXJhbXMsIFsnc3RvcEJlZm9yZScsICdleGNsdWRlJ10pKTtcblxuICAgICAgICAgICAgcmV0dXJuIGh0dHAucG9zdChwYXJhbXMsIHJlcGxheU9wdGlvbnMpO1xuICAgICAgICB9XG4gICAgfTtcblxuICAgICQuZXh0ZW5kKHRoaXMsIHB1YmxpY0FQSSk7XG59O1xuIiwiJ3VzZSBzdHJpY3QnO1xuXG52YXIgZXBpVmVyc2lvbiA9IHJlcXVpcmUoJy4uL2FwaS12ZXJzaW9uLmpzb24nKTtcblxuLy9UT0RPOiB1cmx1dGlscyB0byBnZXQgaG9zdCwgc2luY2Ugbm8gd2luZG93IG9uIG5vZGVcbnZhciBkZWZhdWx0cyA9IHtcbiAgICBob3N0OiB3aW5kb3cubG9jYXRpb24uaG9zdCxcbiAgICBwYXRobmFtZTogd2luZG93LmxvY2F0aW9uLnBhdGhuYW1lXG59O1xuXG52YXIgVXJsQ29uZmlnU2VydmljZSA9IGZ1bmN0aW9uIChjb25maWcpIHtcbiAgICB2YXIgb3B0aW9ucyA9ICQuZXh0ZW5kKHt9LCBkZWZhdWx0cywgY29uZmlnKTtcbiAgICBmdW5jdGlvbiBpc0xvY2FsaG9zdCgpIHtcbiAgICAgICAgdmFyIGhvc3QgPSBvcHRpb25zLmhvc3Q7XG4gICAgICAgIHZhciBwYXRoID0gb3B0aW9ucy5wYXRobmFtZTtcbiAgICAgICAgLy8gU29ydCBvZiBoYXJkY29kZSB0aGUgZmFjdCB0aGF0IGVwaWNlbnRlciBhcHBsaWNhdGlvbiBzcGFjZSBpcyBwcmVmaXhlZCBieSAvYXBwL1xuICAgICAgICByZXR1cm4gKCFob3N0IHx8IHBhdGguaW5kZXhPZignL2FwcC8nKSAhPT0gMCk7XG4gICAgfVxuXG4gICAgdmFyIEFQSV9QUk9UT0NPTCA9ICdodHRwcyc7XG4gICAgdmFyIEhPU1RfQVBJX01BUFBJTkcgPSB7XG4gICAgICAgICdmb3Jpby5jb20nOiAnYXBpLmZvcmlvLmNvbScsXG4gICAgICAgICdmb3Jpb2Rldi5jb20nOiAnYXBpLmVwaWNlbnRlci5mb3Jpb2Rldi5jb20nXG4gICAgfTtcblxuICAgIHZhciBwdWJsaWNFeHBvcnRzID0ge1xuICAgICAgICBwcm90b2NvbDogQVBJX1BST1RPQ09MLFxuXG4gICAgICAgIGFwaTogJycsXG5cbiAgICAgICAgaG9zdDogKGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIHZhciBob3N0ID0gb3B0aW9ucy5ob3N0O1xuICAgICAgICAgICAgaWYgKGlzTG9jYWxob3N0KCkpIHtcbiAgICAgICAgICAgICAgICBob3N0ID0gJ2ZvcmlvLmNvbSc7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICByZXR1cm4gKEhPU1RfQVBJX01BUFBJTkdbaG9zdF0pID8gSE9TVF9BUElfTUFQUElOR1tob3N0XSA6ICdhcGkuJyArIGhvc3Q7XG4gICAgICAgIH0oKSksXG5cbiAgICAgICAgYXBwUGF0aDogKGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIHZhciBwYXRoID0gb3B0aW9ucy5wYXRobmFtZS5zcGxpdCgnXFwvJyk7XG5cbiAgICAgICAgICAgIHJldHVybiBwYXRoICYmIHBhdGhbMV0gfHwgJyc7XG4gICAgICAgIH0oKSksXG5cbiAgICAgICAgYWNjb3VudFBhdGg6IChmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICB2YXIgYWNjbnQgPSAnJztcbiAgICAgICAgICAgIHZhciBwYXRoID0gb3B0aW9ucy5wYXRobmFtZS5zcGxpdCgnXFwvJyk7XG4gICAgICAgICAgICBpZiAocGF0aCAmJiBwYXRoWzFdID09PSAnYXBwJykge1xuICAgICAgICAgICAgICAgIGFjY250ID0gcGF0aFsyXTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHJldHVybiBhY2NudDtcbiAgICAgICAgfSgpKSxcblxuICAgICAgICBwcm9qZWN0UGF0aDogKGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIHZhciBwcmogPSAnJztcbiAgICAgICAgICAgIHZhciBwYXRoID0gb3B0aW9ucy5wYXRobmFtZS5zcGxpdCgnXFwvJyk7XG4gICAgICAgICAgICBpZiAocGF0aCAmJiBwYXRoWzFdID09PSAnYXBwJykge1xuICAgICAgICAgICAgICAgIHByaiA9IHBhdGhbM107XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICByZXR1cm4gcHJqO1xuICAgICAgICB9KCkpLFxuXG4gICAgICAgIHZlcnNpb25QYXRoOiAoZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgdmFyIHZlcnNpb24gPSBlcGlWZXJzaW9uLnZlcnNpb24gPyBlcGlWZXJzaW9uLnZlcnNpb24gKyAnLycgOiAnJztcbiAgICAgICAgICAgIHJldHVybiB2ZXJzaW9uO1xuICAgICAgICB9KCkpLFxuXG4gICAgICAgIGlzTG9jYWxob3N0OiBpc0xvY2FsaG9zdCxcblxuICAgICAgICBnZXRBUElQYXRoOiBmdW5jdGlvbiAoYXBpKSB7XG4gICAgICAgICAgICB2YXIgUFJPSkVDVF9BUElTID0gWydydW4nLCAnZGF0YScsICdmaWxlJ107XG5cbiAgICAgICAgICAgIHZhciBhcGlQYXRoID0gdGhpcy5wcm90b2NvbCArICc6Ly8nICsgdGhpcy5ob3N0ICsgJy8nICsgdGhpcy52ZXJzaW9uUGF0aCArIGFwaSArICcvJztcblxuICAgICAgICAgICAgaWYgKCQuaW5BcnJheShhcGksIFBST0pFQ1RfQVBJUykgIT09IC0xKSB7XG4gICAgICAgICAgICAgICAgYXBpUGF0aCArPSB0aGlzLmFjY291bnRQYXRoICsgJy8nICsgdGhpcy5wcm9qZWN0UGF0aCAgKyAnLyc7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICByZXR1cm4gYXBpUGF0aDtcbiAgICAgICAgfVxuICAgIH07XG5cbiAgICAvLyBUaGlzIGRhdGEgaXMgc2V0IGJ5IGFuIGV4dGVybmFsIHNjcmlwdCAoc3RhcnQtbG9hZC5qcylcbiAgICB2YXIgZW52Q29uZiA9IHtcbiAgICAgICAgcHJvdG9jb2w6IFVybENvbmZpZ1NlcnZpY2UucHJvdG9jb2wsXG4gICAgICAgIGhvc3Q6IFVybENvbmZpZ1NlcnZpY2UuaG9zdFxuICAgIH07XG5cbiAgICAkLmV4dGVuZChwdWJsaWNFeHBvcnRzLCBlbnZDb25mLCBjb25maWcpO1xuICAgIHJldHVybiBwdWJsaWNFeHBvcnRzO1xufTtcblxubW9kdWxlLmV4cG9ydHMgPSBVcmxDb25maWdTZXJ2aWNlO1xuIiwiJ3VzZSBzdHJpY3QnO1xuLyoqXG4qICMjIFVzZXIgQVBJIEFkYXB0ZXJcbipcbiogVGhlIFVzZXIgQVBJIEFkYXB0ZXIgYWxsb3dzIHlvdSB0byByZXRyaWV2ZSBkZXRhaWxzIGFib3V0IGVuZCB1c2VycyBpbiB5b3VyIHRlYW0gKGFjY291bnQpLiBJdCBpcyBiYXNlZCBvbiB0aGUgcXVlcnlpbmcgY2FwYWJpbGl0aWVzIG9mIHRoZSB1bmRlcmx5aW5nIFJFU1RmdWwgW1VzZXIgQVBJXSguLi8uLi8uLi9yZXN0X2FwaXMvdXNlcl9tYW5hZ2VtZW50L3VzZXIvKS5cbipcbiogVG8gdXNlIHRoZSBVc2VyIEFQSSBBZGFwdGVyLCBpbnN0YW50aWF0ZSBpdCBhbmQgdGhlbiBjYWxsIGl0cyBtZXRob2RzLlxuKlxuKiAgICAgICB2YXIgdWEgPSBuZXcgRi5zZXJ2aWNlLlVzZXIoe1xuKiAgICAgICAgICAgYWNjb3VudDogJ2FjbWUtc2ltdWxhdGlvbnMnLFxuKiAgICAgICAgICAgdG9rZW46ICd1c2VyLW9yLXByb2plY3QtYWNjZXNzLXRva2VuJ1xuKiAgICAgICB9KTtcbiogICAgICAgdWEuZ2V0QnlJZCgnNDI4MzZkNGItNWI2MS00ZmU0LTgwZWItMzEzNmU5NTZlZTVjJyk7XG4qICAgICAgIHVhLmdldCh7IHVzZXJOYW1lOiAnanNtaXRoJyB9KTtcbiogICAgICAgdWEuZ2V0KHsgaWQ6IFsnNDI4MzZkNGItNWI2MS00ZmU0LTgwZWItMzEzNmU5NTZlZTVjJyxcbiogICAgICAgICAgICAgICAgICAgJzRlYTc1NjMxLTRjOGQtNDg3Mi05ZDgwLWI0NjAwMTQ2NDc4ZSddIH0pO1xuKlxuKiBUaGUgY29uc3RydWN0b3IgdGFrZXMgYW4gb3B0aW9uYWwgYG9wdGlvbnNgIHBhcmFtZXRlciBpbiB3aGljaCB5b3UgY2FuIHNwZWNpZnkgdGhlIGBhY2NvdW50YCBhbmQgYHRva2VuYCBpZiB0aGV5IGFyZSBub3QgYWxyZWFkeSBhdmFpbGFibGUgaW4gdGhlIGN1cnJlbnQgY29udGV4dC5cbiovXG5cbnZhciBDb25maWdTZXJ2aWNlID0gcmVxdWlyZSgnLi9jb25maWd1cmF0aW9uLXNlcnZpY2UnKTtcbnZhciBUcmFuc3BvcnRGYWN0b3J5ID0gcmVxdWlyZSgnLi4vdHJhbnNwb3J0L2h0dHAtdHJhbnNwb3J0LWZhY3RvcnknKTtcbnZhciBTZXNzaW9uTWFuYWdlciA9IHJlcXVpcmUoJy4uL3N0b3JlL3Nlc3Npb24tbWFuYWdlcicpO1xudmFyIHF1dGlsID0gcmVxdWlyZSgnLi4vdXRpbC9xdWVyeS11dGlsJyk7XG5cbm1vZHVsZS5leHBvcnRzID0gZnVuY3Rpb24gKGNvbmZpZykge1xuICAgIHZhciBkZWZhdWx0cyA9IHtcblxuICAgICAgICAvKipcbiAgICAgICAgICogVGhlIGFjY291bnQgaWQuIEluIHRoZSBFcGljZW50ZXIgVUksIHRoaXMgaXMgdGhlICoqVGVhbSBJRCoqIChmb3IgdGVhbSBwcm9qZWN0cykgb3IgKipVc2VyIElEKiogKGZvciBwZXJzb25hbCBwcm9qZWN0cykuIERlZmF1bHRzIHRvIGVtcHR5IHN0cmluZy5cbiAgICAgICAgICogQHR5cGUge1N0cmluZ31cbiAgICAgICAgICovXG4gICAgICAgIGFjY291bnQ6IHVuZGVmaW5lZCxcblxuICAgICAgICAvKipcbiAgICAgICAgICogVGhlIGFjY2VzcyB0b2tlbiB0byB1c2Ugd2hlbiBzZWFyY2hpbmcgZm9yIGVuZCB1c2Vycy4gKFNlZSBbbW9yZSBiYWNrZ3JvdW5kIG9uIGFjY2VzcyB0b2tlbnNdKC4uLy4uLy4uL3Byb2plY3RfYWNjZXNzLykpLlxuICAgICAgICAgKiBAdHlwZSB7U3RyaW5nfVxuICAgICAgICAgKi9cbiAgICAgICAgdG9rZW46IHVuZGVmaW5lZCxcblxuICAgICAgICAvKipcbiAgICAgICAgICogT3B0aW9ucyB0byBwYXNzIG9uIHRvIHRoZSB1bmRlcmx5aW5nIHRyYW5zcG9ydCBsYXllci4gQWxsIGpxdWVyeS5hamF4IG9wdGlvbnMgYXQgaHR0cDovL2FwaS5qcXVlcnkuY29tL2pRdWVyeS5hamF4LyBhcmUgYXZhaWxhYmxlLiBEZWZhdWx0cyB0byBlbXB0eSBvYmplY3QuXG4gICAgICAgICAqIEB0eXBlIHtPYmplY3R9XG4gICAgICAgICAqL1xuICAgICAgICB0cmFuc3BvcnQ6IHt9XG4gICAgfTtcblxuICAgIHRoaXMuc2Vzc2lvbk1hbmFnZXIgPSBuZXcgU2Vzc2lvbk1hbmFnZXIoKTtcbiAgICB2YXIgc2VydmljZU9wdGlvbnMgPSB0aGlzLnNlc3Npb25NYW5hZ2VyLmdldE1lcmdlZE9wdGlvbnMoZGVmYXVsdHMsIGNvbmZpZyk7XG4gICAgdmFyIHVybENvbmZpZyA9IG5ldyBDb25maWdTZXJ2aWNlKHNlcnZpY2VPcHRpb25zKS5nZXQoJ3NlcnZlcicpO1xuICAgIHZhciB0cmFuc3BvcnRPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sIHNlcnZpY2VPcHRpb25zLnRyYW5zcG9ydCwge1xuICAgICAgICB1cmw6IHVybENvbmZpZy5nZXRBUElQYXRoKCd1c2VyJylcbiAgICB9KTtcblxuICAgIGlmIChzZXJ2aWNlT3B0aW9ucy50b2tlbikge1xuICAgICAgICB0cmFuc3BvcnRPcHRpb25zLmhlYWRlcnMgPSB7XG4gICAgICAgICAgICAnQXV0aG9yaXphdGlvbic6ICdCZWFyZXIgJyArIHNlcnZpY2VPcHRpb25zLnRva2VuXG4gICAgICAgIH07XG4gICAgfVxuXG4gICAgdmFyIGh0dHAgPSBuZXcgVHJhbnNwb3J0RmFjdG9yeSh0cmFuc3BvcnRPcHRpb25zKTtcblxuICAgIHZhciBwdWJsaWNBUEkgPSB7XG5cbiAgICAgICAgLyoqXG4gICAgICAgICogUmV0cmlldmUgZGV0YWlscyBhYm91dCBwYXJ0aWN1bGFyIGVuZCB1c2VycyBpbiB5b3VyIHRlYW0sIGJhc2VkIG9uIHVzZXIgbmFtZSBvciB1c2VyIGlkLlxuICAgICAgICAqXG4gICAgICAgICogKipFeGFtcGxlKipcbiAgICAgICAgKlxuICAgICAgICAqICAgICAgIHZhciB1YSA9IG5ldyBGLnNlcnZpY2UuVXNlcih7XG4gICAgICAgICogICAgICAgICAgIGFjY291bnQ6ICdhY21lLXNpbXVsYXRpb25zJyxcbiAgICAgICAgKiAgICAgICAgICAgdG9rZW46ICd1c2VyLW9yLXByb2plY3QtYWNjZXNzLXRva2VuJ1xuICAgICAgICAqICAgICAgIH0pO1xuICAgICAgICAqICAgICAgIHVhLmdldCh7IHVzZXJOYW1lOiAnanNtaXRoJyB9KTtcbiAgICAgICAgKiAgICAgICB1YS5nZXQoeyBpZDogWyc0MjgzNmQ0Yi01YjYxLTRmZTQtODBlYi0zMTM2ZTk1NmVlNWMnLFxuICAgICAgICAqICAgICAgICAgICAgICAgICAgICc0ZWE3NTYzMS00YzhkLTQ4NzItOWQ4MC1iNDYwMDE0NjQ3OGUnXSB9KTtcbiAgICAgICAgKlxuICAgICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICAgICogQHBhcmFtIHtvYmplY3R9IGBmaWx0ZXJgIE9iamVjdCB3aXRoIGZpZWxkIGB1c2VyTmFtZWAgYW5kIHZhbHVlIG9mIHRoZSB1c2VybmFtZS4gQWx0ZXJuYXRpdmVseSwgb2JqZWN0IHdpdGggZmllbGQgYGlkYCBhbmQgdmFsdWUgb2YgYW4gYXJyYXkgb2YgdXNlciBpZHMuXG4gICAgICAgICogQHBhcmFtIHtvYmplY3R9IGBvcHRpb25zYCAoT3B0aW9uYWwpIE92ZXJyaWRlcyBmb3IgY29uZmlndXJhdGlvbiBvcHRpb25zLlxuICAgICAgICAqL1xuXG4gICAgICAgIGdldDogZnVuY3Rpb24gKGZpbHRlciwgb3B0aW9ucykge1xuICAgICAgICAgICAgb3B0aW9ucyA9IG9wdGlvbnMgfHwge307XG4gICAgICAgICAgICBmaWx0ZXIgPSBmaWx0ZXIgfHwge307XG5cbiAgICAgICAgICAgIHZhciBnZXRPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sXG4gICAgICAgICAgICAgICAgc2VydmljZU9wdGlvbnMsXG4gICAgICAgICAgICAgICAgb3B0aW9uc1xuICAgICAgICAgICAgKTtcblxuICAgICAgICAgICAgdmFyIHRvUUZpbHRlciA9IGZ1bmN0aW9uIChmaWx0ZXIpIHtcbiAgICAgICAgICAgICAgICB2YXIgcmVzID0ge307XG5cbiAgICAgICAgICAgICAgICAvLyBBUEkgb25seSBzdXBwb3J0cyBmaWx0ZXJpbmcgYnkgdXNlcm5hbWUgZm9yIG5vd1xuICAgICAgICAgICAgICAgIGlmIChmaWx0ZXIudXNlck5hbWUpIHtcbiAgICAgICAgICAgICAgICAgICAgcmVzLnEgPSBmaWx0ZXIudXNlck5hbWU7XG4gICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgcmV0dXJuIHJlcztcbiAgICAgICAgICAgIH07XG5cbiAgICAgICAgICAgIHZhciB0b0lkRmlsdGVycyA9IGZ1bmN0aW9uIChpZCkge1xuICAgICAgICAgICAgICAgIGlmICghaWQpIHtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuICcnO1xuICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgIGlkID0gJC5pc0FycmF5KGlkKSA/IGlkIDogW2lkXTtcbiAgICAgICAgICAgICAgICByZXR1cm4gJ2lkPScgKyBpZC5qb2luKCcmaWQ9Jyk7XG4gICAgICAgICAgICB9O1xuXG4gICAgICAgICAgICB2YXIgZ2V0RmlsdGVycyA9IFtcbiAgICAgICAgICAgICAgICAnYWNjb3VudD0nICsgZ2V0T3B0aW9ucy5hY2NvdW50LFxuICAgICAgICAgICAgICAgIHRvSWRGaWx0ZXJzKGZpbHRlci5pZCksXG4gICAgICAgICAgICAgICAgcXV0aWwudG9RdWVyeUZvcm1hdCh0b1FGaWx0ZXIoZmlsdGVyKSlcbiAgICAgICAgICAgIF0uam9pbignJicpO1xuXG4gICAgICAgICAgICAvLyBzcGVjaWFsIGNhc2UgZm9yIHF1ZXJpZXMgd2l0aCBsYXJnZSBudW1iZXIgb2YgaWRzXG4gICAgICAgICAgICAvLyBtYWtlIGl0IGFzIGEgcG9zdCB3aXRoIEdFVCBzZW1hbnRpY3NcbiAgICAgICAgICAgIHZhciB0aHJlc2hvbGQgPSAzMDtcbiAgICAgICAgICAgIGlmIChmaWx0ZXIuaWQgJiYgJC5pc0FycmF5KGZpbHRlci5pZCkgJiYgZmlsdGVyLmlkLmxlbmd0aCA+PSB0aHJlc2hvbGQpIHtcbiAgICAgICAgICAgICAgICBnZXRPcHRpb25zLnVybCA9IHVybENvbmZpZy5nZXRBUElQYXRoKCd1c2VyJykgKyAnP19tZXRob2Q9R0VUJztcbiAgICAgICAgICAgICAgICByZXR1cm4gaHR0cC5wb3N0KHsgaWQ6IGZpbHRlci5pZCB9LCBnZXRPcHRpb25zKTtcbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIGh0dHAuZ2V0KGdldEZpbHRlcnMsIGdldE9wdGlvbnMpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAqIFJldHJpZXZlIGRldGFpbHMgYWJvdXQgYSBzaW5nbGUgZW5kIHVzZXIgaW4geW91ciB0ZWFtLCBiYXNlZCBvbiB1c2VyIGlkLlxuICAgICAgICAqXG4gICAgICAgICogKipFeGFtcGxlKipcbiAgICAgICAgKlxuICAgICAgICAqICAgICAgIHZhciB1YSA9IG5ldyBGLnNlcnZpY2UuVXNlcih7XG4gICAgICAgICogICAgICAgICAgIGFjY291bnQ6ICdhY21lLXNpbXVsYXRpb25zJyxcbiAgICAgICAgKiAgICAgICAgICAgdG9rZW46ICd1c2VyLW9yLXByb2plY3QtYWNjZXNzLXRva2VuJ1xuICAgICAgICAqICAgICAgIH0pO1xuICAgICAgICAqICAgICAgIHVhLmdldEJ5SWQoJzQyODM2ZDRiLTViNjEtNGZlNC04MGViLTMxMzZlOTU2ZWU1YycpO1xuICAgICAgICAqXG4gICAgICAgICogKipQYXJhbWV0ZXJzKipcbiAgICAgICAgKiBAcGFyYW0ge3N0cmluZ30gYHVzZXJJZGAgVGhlIHVzZXIgaWQgZm9yIHRoZSBlbmQgdXNlciBpbiB5b3VyIHRlYW0uXG4gICAgICAgICogQHBhcmFtIHtvYmplY3R9IGBvcHRpb25zYCAoT3B0aW9uYWwpIE92ZXJyaWRlcyBmb3IgY29uZmlndXJhdGlvbiBvcHRpb25zLlxuICAgICAgICAqL1xuXG4gICAgICAgIGdldEJ5SWQ6IGZ1bmN0aW9uICh1c2VySWQsIG9wdGlvbnMpIHtcbiAgICAgICAgICAgIHJldHVybiBwdWJsaWNBUEkuZ2V0KHsgaWQ6IHVzZXJJZCB9LCBvcHRpb25zKTtcbiAgICAgICAgfVxuICAgIH07XG5cbiAgICAkLmV4dGVuZCh0aGlzLCBwdWJsaWNBUEkpO1xufTtcblxuXG5cblxuIiwiLyoqXG4gKlxuICogIyMgVmFyaWFibGVzIEFQSSBTZXJ2aWNlXG4gKlxuICogVXNlZCBpbiBjb25qdW5jdGlvbiB3aXRoIHRoZSBbUnVuIEFQSSBTZXJ2aWNlXSguLi9ydW4tYXBpLXNlcnZpY2UvKSB0byByZWFkLCB3cml0ZSwgYW5kIHNlYXJjaCBmb3Igc3BlY2lmaWMgbW9kZWwgdmFyaWFibGVzLlxuICpcbiAqICAgICB2YXIgcm0gPSBuZXcgRi5tYW5hZ2VyLlJ1bk1hbmFnZXIoe1xuICogICAgICAgICAgIHJ1bjoge1xuICogICAgICAgICAgICAgICBhY2NvdW50OiAnYWNtZS1zaW11bGF0aW9ucycsXG4gKiAgICAgICAgICAgICAgIHByb2plY3Q6ICdzdXBwbHktY2hhaW4tZ2FtZScsXG4gKiAgICAgICAgICAgICAgIG1vZGVsOiAnc3VwcGx5LWNoYWluLW1vZGVsLmpsJ1xuICogICAgICAgICAgIH1cbiAqICAgICAgfSk7XG4gKiAgICAgcm0uZ2V0UnVuKClcbiAqICAgICAgIC50aGVuKGZ1bmN0aW9uKCkge1xuICogICAgICAgICAgdmFyIHZzID0gcm0ucnVuLnZhcmlhYmxlcygpO1xuICogICAgICAgICAgdnMuc2F2ZSh7c2FtcGxlX2ludDogNH0pO1xuICogICAgICAgIH0pO1xuICpcbiAqL1xuXG5cbiAndXNlIHN0cmljdCc7XG5cbiB2YXIgVHJhbnNwb3J0RmFjdG9yeSA9IHJlcXVpcmUoJy4uL3RyYW5zcG9ydC9odHRwLXRyYW5zcG9ydC1mYWN0b3J5Jyk7XG4gdmFyIHJ1dGlsID0gcmVxdWlyZSgnLi4vdXRpbC9ydW4tdXRpbCcpO1xuXG5tb2R1bGUuZXhwb3J0cyA9IGZ1bmN0aW9uIChjb25maWcpIHtcbiAgICB2YXIgZGVmYXVsdHMgPSB7XG4gICAgICAgIC8qKlxuICAgICAgICAgKiBUaGUgcnVucyBvYmplY3QgdG8gd2hpY2ggdGhlIHZhcmlhYmxlIGZpbHRlcnMgYXBwbHkuIERlZmF1bHRzIHRvIG51bGwuXG4gICAgICAgICAqIEB0eXBlIHtydW5TZXJ2aWNlfVxuICAgICAgICAgKi9cbiAgICAgICAgcnVuU2VydmljZTogbnVsbFxuICAgIH07XG4gICAgdmFyIHNlcnZpY2VPcHRpb25zID0gJC5leHRlbmQoe30sIGRlZmF1bHRzLCBjb25maWcpO1xuXG4gICAgdmFyIGdldFVSTCA9IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgcmV0dXJuIHNlcnZpY2VPcHRpb25zLnJ1blNlcnZpY2UudXJsQ29uZmlnLmdldEZpbHRlclVSTCgpICsgJ3ZhcmlhYmxlcy8nO1xuICAgIH07XG5cbiAgICB2YXIgYWRkQXV0b1Jlc3RvcmVIZWFkZXIgPSBmdW5jdGlvbiAob3B0aW9ucykge1xuICAgICAgICByZXR1cm4gc2VydmljZU9wdGlvbnMucnVuU2VydmljZS51cmxDb25maWcuYWRkQXV0b1Jlc3RvcmVIZWFkZXIob3B0aW9ucyk7XG4gICAgfTtcblxuICAgIHZhciBodHRwT3B0aW9ucyA9IHtcbiAgICAgICAgdXJsOiBnZXRVUkxcbiAgICB9O1xuICAgIGlmIChzZXJ2aWNlT3B0aW9ucy50b2tlbikge1xuICAgICAgICBodHRwT3B0aW9ucy5oZWFkZXJzID0ge1xuICAgICAgICAgICAgJ0F1dGhvcml6YXRpb24nOiAnQmVhcmVyICcgKyBzZXJ2aWNlT3B0aW9ucy50b2tlblxuICAgICAgICB9O1xuICAgIH1cbiAgICB2YXIgaHR0cCA9IG5ldyBUcmFuc3BvcnRGYWN0b3J5KGh0dHBPcHRpb25zKTtcbiAgICBodHRwLnNwbGl0R2V0ID0gcnV0aWwuc3BsaXRHZXRGYWN0b3J5KGh0dHBPcHRpb25zKTtcblxuICAgIHZhciBwdWJsaWNBUEkgPSB7XG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIEdldCB2YWx1ZXMgZm9yIGEgdmFyaWFibGUuXG4gICAgICAgICAqXG4gICAgICAgICAqICoqRXhhbXBsZSoqXG4gICAgICAgICAqXG4gICAgICAgICAqICAgICAgdnMubG9hZCgnc2FtcGxlX2ludCcpXG4gICAgICAgICAqICAgICAgICAgIC50aGVuKGZ1bmN0aW9uKHZhbCl7XG4gICAgICAgICAqICAgICAgICAgICAgICAvLyB2YWwgY29udGFpbnMgdGhlIHZhbHVlIG9mIHNhbXBsZV9pbnRcbiAgICAgICAgICogICAgICAgICAgfSk7XG4gICAgICAgICAqXG4gICAgICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICAgICAqIEBwYXJhbSB7U3RyaW5nfSBgdmFyaWFibGVgIE5hbWUgb2YgdmFyaWFibGUgdG8gbG9hZC5cbiAgICAgICAgICogQHBhcmFtIHtPYmplY3R9IGBvdXRwdXRNb2RpZmllcmAgKE9wdGlvbmFsKSBBdmFpbGFibGUgZmllbGRzIGluY2x1ZGU6IGBzdGFydHJlY29yZGAsIGBlbmRyZWNvcmRgLCBgc29ydGAsIGFuZCBgZGlyZWN0aW9uYCAoYGFzY2Agb3IgYGRlc2NgKS5cbiAgICAgICAgICogQHBhcmFtIHtPYmplY3R9IGBvcHRpb25zYCAoT3B0aW9uYWwpIE92ZXJyaWRlcyBmb3IgY29uZmlndXJhdGlvbiBvcHRpb25zLlxuICAgICAgICAgKi9cbiAgICAgICAgbG9hZDogZnVuY3Rpb24gKHZhcmlhYmxlLCBvdXRwdXRNb2RpZmllciwgb3B0aW9ucykge1xuICAgICAgICAgICAgdmFyIGh0dHBPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sIHNlcnZpY2VPcHRpb25zLCBvcHRpb25zKTtcbiAgICAgICAgICAgIGh0dHBPcHRpb25zID0gYWRkQXV0b1Jlc3RvcmVIZWFkZXIoaHR0cE9wdGlvbnMpO1xuICAgICAgICAgICAgcmV0dXJuIGh0dHAuZ2V0KG91dHB1dE1vZGlmaWVyLCAkLmV4dGVuZCh7fSwgaHR0cE9wdGlvbnMsIHtcbiAgICAgICAgICAgICAgICB1cmw6IGdldFVSTCgpICsgdmFyaWFibGUgKyAnLydcbiAgICAgICAgICAgIH0pKTtcbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgICogUmV0dXJucyBwYXJ0aWN1bGFyIHZhcmlhYmxlcywgYmFzZWQgb24gY29uZGl0aW9ucyBzcGVjaWZpZWQgaW4gdGhlIGBxdWVyeWAgb2JqZWN0LlxuICAgICAgICAgKlxuICAgICAgICAgKiAqKkV4YW1wbGUqKlxuICAgICAgICAgKlxuICAgICAgICAgKiAgICAgIHZzLnF1ZXJ5KFsncHJpY2UnLCAnc2FsZXMnXSlcbiAgICAgICAgICogICAgICAgICAgLnRoZW4oZnVuY3Rpb24odmFsKSB7XG4gICAgICAgICAqICAgICAgICAgICAgICAvLyB2YWwgaXMgYW4gb2JqZWN0IHdpdGggdGhlIHZhbHVlcyBvZiB0aGUgcmVxdWVzdGVkIHZhcmlhYmxlczogdmFsLnByaWNlLCB2YWwuc2FsZXNcbiAgICAgICAgICogICAgICAgICAgfSk7XG4gICAgICAgICAqXG4gICAgICAgICAqICAgICAgdnMucXVlcnkoeyBpbmNsdWRlOlsncHJpY2UnLCAnc2FsZXMnXSB9KTtcbiAgICAgICAgICpcbiAgICAgICAgICogKipQYXJhbWV0ZXJzKipcbiAgICAgICAgICogQHBhcmFtIHtPYmplY3R8QXJyYXl9IGBxdWVyeWAgVGhlIG5hbWVzIG9mIHRoZSB2YXJpYWJsZXMgcmVxdWVzdGVkLlxuICAgICAgICAgKiBAcGFyYW0ge09iamVjdH0gYG91dHB1dE1vZGlmaWVyYCAoT3B0aW9uYWwpIEF2YWlsYWJsZSBmaWVsZHMgaW5jbHVkZTogYHN0YXJ0cmVjb3JkYCwgYGVuZHJlY29yZGAsIGBzb3J0YCwgYW5kIGBkaXJlY3Rpb25gIChgYXNjYCBvciBgZGVzY2ApLlxuICAgICAgICAgKiBAcGFyYW0ge09iamVjdH0gYG9wdGlvbnNgIChPcHRpb25hbCkgT3ZlcnJpZGVzIGZvciBjb25maWd1cmF0aW9uIG9wdGlvbnMuXG4gICAgICAgICAqXG4gICAgICAgICAqL1xuICAgICAgICBxdWVyeTogZnVuY3Rpb24gKHF1ZXJ5LCBvdXRwdXRNb2RpZmllciwgb3B0aW9ucykge1xuICAgICAgICAgICAgLy9RdWVyeSBhbmQgb3V0cHV0TW9kaWZpZXIgYXJlIGJvdGggcXVlcnlzdHJpbmdzIGluIHRoZSB1cmw7IG9ubHkgY2FsbGluZyB0aGVtIG91dCBzZXBhcmF0ZWx5IGhlcmUgdG8gYmUgY29uc2lzdGVudCB3aXRoIHRoZSBvdGhlciBjYWxsc1xuICAgICAgICAgICAgdmFyIGh0dHBPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sIHNlcnZpY2VPcHRpb25zLCBvcHRpb25zKTtcbiAgICAgICAgICAgIGh0dHBPcHRpb25zID0gYWRkQXV0b1Jlc3RvcmVIZWFkZXIoaHR0cE9wdGlvbnMpO1xuXG4gICAgICAgICAgICBpZiAoJC5pc0FycmF5KHF1ZXJ5KSkge1xuICAgICAgICAgICAgICAgIHF1ZXJ5ID0geyBpbmNsdWRlOiBxdWVyeSB9O1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgJC5leHRlbmQocXVlcnksIG91dHB1dE1vZGlmaWVyKTtcbiAgICAgICAgICAgIHJldHVybiBodHRwLnNwbGl0R2V0KHF1ZXJ5LCBodHRwT3B0aW9ucyk7XG4gICAgICAgIH0sXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIFNhdmUgdmFsdWVzIHRvIG1vZGVsIHZhcmlhYmxlcy4gT3ZlcndyaXRlcyBleGlzdGluZyB2YWx1ZXMuIE5vdGUgdGhhdCB5b3UgY2FuIG9ubHkgdXBkYXRlIG1vZGVsIHZhcmlhYmxlcyBpZiB0aGUgcnVuIGlzIFtpbiBtZW1vcnldKC4uLy4uLy4uL3J1bl9wZXJzaXN0ZW5jZS8jcnVucy1pbi1tZW1vcnkpLiAoQW4gYWx0ZXJuYXRlIHdheSB0byB1cGRhdGUgbW9kZWwgdmFyaWFibGVzIGlzIHRvIGNhbGwgYSBtZXRob2QgZnJvbSB0aGUgbW9kZWwgYW5kIG1ha2Ugc3VyZSB0aGF0IHRoZSBtZXRob2QgcGVyc2lzdHMgdGhlIHZhcmlhYmxlcy4gU2VlIGBkb2AsIGBzZXJpYWxgLCBhbmQgYHBhcmFsbGVsYCBpbiB0aGUgW1J1biBBUEkgU2VydmljZV0oLi4vcnVuLWFwaS1zZXJ2aWNlLykgZm9yIGNhbGxpbmcgbWV0aG9kcyBmcm9tIHRoZSBtb2RlbC4pXG4gICAgICAgICAqXG4gICAgICAgICAqICoqRXhhbXBsZSoqXG4gICAgICAgICAqXG4gICAgICAgICAqICAgICAgdnMuc2F2ZSgncHJpY2UnLCA0KTtcbiAgICAgICAgICogICAgICB2cy5zYXZlKHsgcHJpY2U6IDQsIHF1YW50aXR5OiA1LCBwcm9kdWN0czogWzIsMyw0XSB9KTtcbiAgICAgICAgICpcbiAgICAgICAgICogKipQYXJhbWV0ZXJzKipcbiAgICAgICAgICogQHBhcmFtIHtPYmplY3R8U3RyaW5nfSBgdmFyaWFibGVgIEFuIG9iamVjdCBjb21wb3NlZCBvZiB0aGUgbW9kZWwgdmFyaWFibGVzIGFuZCB0aGUgdmFsdWVzIHRvIHNhdmUuIEFsdGVybmF0aXZlbHksIGEgc3RyaW5nIHdpdGggdGhlIG5hbWUgb2YgdGhlIHZhcmlhYmxlLlxuICAgICAgICAgKiBAcGFyYW0ge09iamVjdH0gYHZhbGAgKE9wdGlvbmFsKSBJZiBwYXNzaW5nIGEgc3RyaW5nIGZvciBgdmFyaWFibGVgLCB1c2UgdGhpcyBhcmd1bWVudCBmb3IgdGhlIHZhbHVlIHRvIHNhdmUuXG4gICAgICAgICAqIEBwYXJhbSB7T2JqZWN0fSBgb3B0aW9uc2AgKE9wdGlvbmFsKSBPdmVycmlkZXMgZm9yIGNvbmZpZ3VyYXRpb24gb3B0aW9ucy5cbiAgICAgICAgICovXG4gICAgICAgIHNhdmU6IGZ1bmN0aW9uICh2YXJpYWJsZSwgdmFsLCBvcHRpb25zKSB7XG4gICAgICAgICAgICB2YXIgYXR0cnM7XG4gICAgICAgICAgICBpZiAodHlwZW9mIHZhcmlhYmxlID09PSAnb2JqZWN0Jykge1xuICAgICAgICAgICAgICAgIGF0dHJzID0gdmFyaWFibGU7XG4gICAgICAgICAgICAgICAgb3B0aW9ucyA9IHZhbDtcbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgKGF0dHJzID0ge30pW3ZhcmlhYmxlXSA9IHZhbDtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHZhciBodHRwT3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LCBzZXJ2aWNlT3B0aW9ucywgb3B0aW9ucyk7XG5cbiAgICAgICAgICAgIHJldHVybiBodHRwLnBhdGNoLmNhbGwodGhpcywgYXR0cnMsIGh0dHBPcHRpb25zKTtcbiAgICAgICAgfVxuXG4gICAgICAgIC8vIE5vdCBBdmFpbGFibGUgdW50aWwgdW5kZXJseWluZyBBUEkgc3VwcG9ydHMgUFVULiBPdGhlcndpc2Ugc2F2ZSB3b3VsZCBiZSBQVVQgYW5kIG1lcmdlIHdvdWxkIGJlIFBBVENIXG4gICAgICAgIC8vICpcbiAgICAgICAgLy8gICogU2F2ZSB2YWx1ZXMgdG8gdGhlIGFwaS4gTWVyZ2VzIGFycmF5cywgYnV0IG90aGVyd2lzZSBzYW1lIGFzIHNhdmVcbiAgICAgICAgLy8gICogQHBhcmFtIHtPYmplY3R8U3RyaW5nfSB2YXJpYWJsZSBPYmplY3Qgd2l0aCBhdHRyaWJ1dGVzLCBvciBzdHJpbmcga2V5XG4gICAgICAgIC8vICAqIEBwYXJhbSB7T2JqZWN0fSB2YWwgT3B0aW9uYWwgaWYgcHJldiBwYXJhbWV0ZXIgd2FzIGEgc3RyaW5nLCBzZXQgdmFsdWUgaGVyZVxuICAgICAgICAvLyAgKiBAcGFyYW0ge09iamVjdH0gb3B0aW9ucyBPdmVycmlkZXMgZm9yIGNvbmZpZ3VyYXRpb24gb3B0aW9uc1xuICAgICAgICAvLyAgKlxuICAgICAgICAvLyAgKiBAZXhhbXBsZVxuICAgICAgICAvLyAgKiAgICAgdnMubWVyZ2UoeyBwcmljZTogNCwgcXVhbnRpdHk6IDUsIHByb2R1Y3RzOiBbMiwzLDRdIH0pXG4gICAgICAgIC8vICAqICAgICB2cy5tZXJnZSgncHJpY2UnLCA0KTtcblxuICAgICAgICAvLyBtZXJnZTogZnVuY3Rpb24gKHZhcmlhYmxlLCB2YWwsIG9wdGlvbnMpIHtcbiAgICAgICAgLy8gICAgIHZhciBhdHRycztcbiAgICAgICAgLy8gICAgIGlmICh0eXBlb2YgdmFyaWFibGUgPT09ICdvYmplY3QnKSB7XG4gICAgICAgIC8vICAgICAgIGF0dHJzID0gdmFyaWFibGU7XG4gICAgICAgIC8vICAgICAgIG9wdGlvbnMgPSB2YWw7XG4gICAgICAgIC8vICAgICB9IGVsc2Uge1xuICAgICAgICAvLyAgICAgICAoYXR0cnMgPSB7fSlbdmFyaWFibGVdID0gdmFsO1xuICAgICAgICAvLyAgICAgfVxuICAgICAgICAvLyAgICAgdmFyIGh0dHBPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sIHNlcnZpY2VPcHRpb25zLCBvcHRpb25zKTtcblxuICAgICAgICAvLyAgICAgcmV0dXJuIGh0dHAucGF0Y2guY2FsbCh0aGlzLCBhdHRycywgaHR0cE9wdGlvbnMpO1xuICAgICAgICAvLyB9XG4gICAgfTtcbiAgICAkLmV4dGVuZCh0aGlzLCBwdWJsaWNBUEkpO1xufTtcbiIsIi8qKlxuICogIyMgV29ybGQgQVBJIEFkYXB0ZXJcbiAqXG4gKiBBIFtydW5dKC4uLy4uLy4uL2dsb3NzYXJ5LyNydW4pIGlzIGEgY29sbGVjdGlvbiBvZiBlbmQgdXNlciBpbnRlcmFjdGlvbnMgd2l0aCBhIHByb2plY3QgYW5kIGl0cyBtb2RlbCAtLSBpbmNsdWRpbmcgc2V0dGluZyB2YXJpYWJsZXMsIG1ha2luZyBkZWNpc2lvbnMsIGFuZCBjYWxsaW5nIG9wZXJhdGlvbnMuIEZvciBidWlsZGluZyBtdWx0aXBsYXllciBzaW11bGF0aW9ucyB5b3UgdHlwaWNhbGx5IHdhbnQgbXVsdGlwbGUgZW5kIHVzZXJzIHRvIHNoYXJlIHRoZSBzYW1lIHNldCBvZiBpbnRlcmFjdGlvbnMsIGFuZCB3b3JrIHdpdGhpbiBhIGNvbW1vbiBzdGF0ZS4gRXBpY2VudGVyIGFsbG93cyB5b3UgdG8gY3JlYXRlIFwid29ybGRzXCIgdG8gaGFuZGxlIHN1Y2ggY2FzZXMuIE9ubHkgW3RlYW0gcHJvamVjdHNdKC4uLy4uLy4uL2dsb3NzYXJ5LyN0ZWFtKSBjYW4gYmUgbXVsdGlwbGF5ZXIuXG4gKlxuICogVGhlIFdvcmxkIEFQSSBBZGFwdGVyIGFsbG93cyB5b3UgdG8gY3JlYXRlLCBhY2Nlc3MsIGFuZCBtYW5pcHVsYXRlIG11bHRpcGxheWVyIHdvcmxkcyB3aXRoaW4geW91ciBFcGljZW50ZXIgcHJvamVjdC4gWW91IGNhbiB1c2UgdGhpcyB0byBhZGQgYW5kIHJlbW92ZSBlbmQgdXNlcnMgZnJvbSB0aGUgd29ybGQsIGFuZCB0byBjcmVhdGUsIGFjY2VzcywgYW5kIHJlbW92ZSB0aGVpciBydW5zLiBCZWNhdXNlIG9mIHRoaXMsIHR5cGljYWxseSB0aGUgV29ybGQgQWRhcHRlciBpcyB1c2VkIGZvciBmYWNpbGl0YXRvciBwYWdlcyBpbiB5b3VyIHByb2plY3QuIChUaGUgcmVsYXRlZCBbV29ybGQgTWFuYWdlcl0oLi4vd29ybGQtbWFuYWdlci8pIHByb3ZpZGVzIGFuIGVhc3kgd2F5IHRvIGFjY2VzcyBydW5zIGFuZCB3b3JsZHMgZm9yIHBhcnRpY3VsYXIgZW5kIHVzZXJzLCBzbyBpcyB0eXBpY2FsbHkgdXNlZCBpbiBwYWdlcyB0aGF0IGVuZCB1c2VycyB3aWxsIGludGVyYWN0IHdpdGguKVxuICpcbiAqIEFzIHdpdGggYWxsIHRoZSBvdGhlciBbQVBJIEFkYXB0ZXJzXSguLi8uLi8pLCBhbGwgbWV0aG9kcyB0YWtlIGluIGFuIFwib3B0aW9uc1wiIG9iamVjdCBhcyB0aGUgbGFzdCBwYXJhbWV0ZXIuIFRoZSBvcHRpb25zIGNhbiBiZSB1c2VkIHRvIGV4dGVuZC9vdmVycmlkZSB0aGUgV29ybGQgQVBJIFNlcnZpY2UgZGVmYXVsdHMuXG4gKlxuICogVG8gdXNlIHRoZSBXb3JsZCBBZGFwdGVyLCBpbnN0YW50aWF0ZSBpdCBhbmQgdGhlbiBhY2Nlc3MgdGhlIG1ldGhvZHMgcHJvdmlkZWQuIEluc3RhbnRpYXRpbmcgcmVxdWlyZXMgdGhlIGFjY291bnQgaWQgKCoqVGVhbSBJRCoqIGluIHRoZSBFcGljZW50ZXIgdXNlciBpbnRlcmZhY2UpLCBwcm9qZWN0IGlkICgqKlByb2plY3QgSUQqKiksIGFuZCBncm91cCAoKipHcm91cCBOYW1lKiopLlxuICpcbiAqICAgICAgIHZhciB3YSA9IG5ldyBGLnNlcnZpY2UuV29ybGQoe1xuICogICAgICAgICAgYWNjb3VudDogJ2FjbWUtc2ltdWxhdGlvbnMnLFxuICogICAgICAgICAgcHJvamVjdDogJ3N1cHBseS1jaGFpbi1nYW1lJyxcbiAqICAgICAgICAgIGdyb3VwOiAndGVhbTEnIH0pO1xuICogICAgICAgd2EuY3JlYXRlKClcbiAqICAgICAgICAgIC50aGVuKGZ1bmN0aW9uKHdvcmxkKSB7XG4gKiAgICAgICAgICAgICAgLy8gY2FsbCBtZXRob2RzLCBlLmcuIHdhLmFkZFVzZXJzKClcbiAqICAgICAgICAgIH0pO1xuICovXG5cbid1c2Ugc3RyaWN0JztcblxudmFyIENvbmZpZ1NlcnZpY2UgPSByZXF1aXJlKCcuL2NvbmZpZ3VyYXRpb24tc2VydmljZScpO1xuLy8gdmFyIHF1dGlsID0gcmVxdWlyZSgnLi4vdXRpbC9xdWVyeS11dGlsJyk7XG52YXIgVHJhbnNwb3J0RmFjdG9yeSA9IHJlcXVpcmUoJy4uL3RyYW5zcG9ydC9odHRwLXRyYW5zcG9ydC1mYWN0b3J5Jyk7XG52YXIgU2Vzc2lvbk1hbmFnZXIgPSByZXF1aXJlKCcuLi9zdG9yZS9zZXNzaW9uLW1hbmFnZXInKTtcbnZhciBfcGljayA9IHJlcXVpcmUoJy4uL3V0aWwvb2JqZWN0LXV0aWwnKS5fcGljaztcblxudmFyIGFwaUJhc2UgPSAnbXVsdGlwbGF5ZXIvJztcbnZhciBhc3NpZ25tZW50RW5kcG9pbnQgPSBhcGlCYXNlICsgJ2Fzc2lnbic7XG52YXIgYXBpRW5kcG9pbnQgPSBhcGlCYXNlICsgJ3dvcmxkJztcbnZhciBwcm9qZWN0RW5kcG9pbnQgPSBhcGlCYXNlICsgJ3Byb2plY3QnO1xuXG5tb2R1bGUuZXhwb3J0cyA9IGZ1bmN0aW9uIChjb25maWcpIHtcbiAgICB2YXIgZGVmYXVsdHMgPSB7XG4gICAgICAgIC8qKlxuICAgICAgICAgKiBGb3IgcHJvamVjdHMgdGhhdCByZXF1aXJlIGF1dGhlbnRpY2F0aW9uLCBwYXNzIGluIHRoZSB1c2VyIGFjY2VzcyB0b2tlbiAoZGVmYXVsdHMgdG8gZW1wdHkgc3RyaW5nKS4gSWYgdGhlIHVzZXIgaXMgYWxyZWFkeSBsb2dnZWQgaW4gdG8gRXBpY2VudGVyLCB0aGUgdXNlciBhY2Nlc3MgdG9rZW4gaXMgYWxyZWFkeSBzZXQgaW4gYSBjb29raWUgYW5kIGF1dG9tYXRpY2FsbHkgbG9hZGVkIGZyb20gdGhlcmUuIChTZWUgW21vcmUgYmFja2dyb3VuZCBvbiBhY2Nlc3MgdG9rZW5zXSguLi8uLi8uLi9wcm9qZWN0X2FjY2Vzcy8pKS5cbiAgICAgICAgICogQHNlZSBbQXV0aGVudGljYXRpb24gQVBJIFNlcnZpY2VdKC4uL2F1dGgtYXBpLXNlcnZpY2UvKSBmb3IgZ2V0dGluZyB0b2tlbnMuXG4gICAgICAgICAqIEB0eXBlIHtTdHJpbmd9XG4gICAgICAgICAqL1xuICAgICAgIHRva2VuOiB1bmRlZmluZWQsXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIFRoZSBwcm9qZWN0IGlkLiBJZiBsZWZ0IHVuZGVmaW5lZCwgdGFrZW4gZnJvbSB0aGUgVVJMLlxuICAgICAgICAgKiBAdHlwZSB7U3RyaW5nfVxuICAgICAgICAgKi9cbiAgICAgICAgcHJvamVjdDogdW5kZWZpbmVkLFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBUaGUgYWNjb3VudCBpZC4gSW4gdGhlIEVwaWNlbnRlciBVSSwgdGhpcyBpcyB0aGUgKipUZWFtIElEKiogKGZvciB0ZWFtIHByb2plY3RzKS4gSWYgbGVmdCB1bmRlZmluZWQsIHRha2VuIGZyb20gdGhlIFVSTC5cbiAgICAgICAgICogQHR5cGUge1N0cmluZ31cbiAgICAgICAgICovXG4gICAgICAgIGFjY291bnQ6IHVuZGVmaW5lZCxcblxuICAgICAgICAvKipcbiAgICAgICAgICogVGhlIGdyb3VwIG5hbWUuIERlZmF1bHRzIHRvIHVuZGVmaW5lZC5cbiAgICAgICAgICogQHR5cGUge1N0cmluZ31cbiAgICAgICAgICovXG4gICAgICAgIGdyb3VwOiB1bmRlZmluZWQsXG5cbiAgICAgICAvKipcbiAgICAgICAgICogVGhlIG1vZGVsIGZpbGUgdG8gdXNlIHRvIGNyZWF0ZSBydW5zIGluIHRoaXMgd29ybGQuIERlZmF1bHRzIHRvIHVuZGVmaW5lZC5cbiAgICAgICAgICogQHR5cGUge1N0cmluZ31cbiAgICAgICAgICovXG4gICAgICAgIG1vZGVsOiB1bmRlZmluZWQsXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIENyaXRlcmlhIGJ5IHdoaWNoIHRvIGZpbHRlciB3b3JsZC4gQ3VycmVudGx5IG9ubHkgc3VwcG9ydHMgd29ybGQtaWRzIGFzIGZpbHRlcnMuXG4gICAgICAgICAqIEB0eXBlIHtTdHJpbmd9XG4gICAgICAgICAqL1xuICAgICAgICBmaWx0ZXI6ICcnLFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBDb252ZW5pZW5jZSBhbGlhcyBmb3IgZmlsdGVyXG4gICAgICAgICAqIEB0eXBlIHtTdHJpbmd9XG4gICAgICAgICAqL1xuICAgICAgICBpZDogJycsXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIE9wdGlvbnMgdG8gcGFzcyBvbiB0byB0aGUgdW5kZXJseWluZyB0cmFuc3BvcnQgbGF5ZXIuIEFsbCBqcXVlcnkuYWpheCBvcHRpb25zIGF0IGh0dHA6Ly9hcGkuanF1ZXJ5LmNvbS9qUXVlcnkuYWpheC8gYXJlIGF2YWlsYWJsZS4gRGVmYXVsdHMgdG8gZW1wdHkgb2JqZWN0LlxuICAgICAgICAgKiBAdHlwZSB7T2JqZWN0fVxuICAgICAgICAgKi9cbiAgICAgICAgdHJhbnNwb3J0OiB7fSxcblxuICAgICAgICAvKipcbiAgICAgICAgICogQ2FsbGVkIHdoZW4gdGhlIGNhbGwgY29tcGxldGVzIHN1Y2Nlc3NmdWxseS4gRGVmYXVsdHMgdG8gYCQubm9vcGAuXG4gICAgICAgICAqIEB0eXBlIHtmdW5jdGlvbn1cbiAgICAgICAgICovXG4gICAgICAgIHN1Y2Nlc3M6ICQubm9vcCxcblxuICAgICAgICAvKipcbiAgICAgICAgICogQ2FsbGVkIHdoZW4gdGhlIGNhbGwgZmFpbHMuIERlZmF1bHRzIHRvIGAkLm5vb3BgLlxuICAgICAgICAgKiBAdHlwZSB7ZnVuY3Rpb259XG4gICAgICAgICAqL1xuICAgICAgICBlcnJvcjogJC5ub29wXG4gICAgfTtcblxuICAgIHRoaXMuc2Vzc2lvbk1hbmFnZXIgPSBuZXcgU2Vzc2lvbk1hbmFnZXIoKTtcbiAgICB2YXIgc2VydmljZU9wdGlvbnMgPSB0aGlzLnNlc3Npb25NYW5hZ2VyLmdldE1lcmdlZE9wdGlvbnMoZGVmYXVsdHMsIGNvbmZpZyk7XG4gICAgaWYgKHNlcnZpY2VPcHRpb25zLmlkKSB7XG4gICAgICAgIHNlcnZpY2VPcHRpb25zLmZpbHRlciA9IHNlcnZpY2VPcHRpb25zLmlkO1xuICAgIH1cblxuICAgIHZhciB1cmxDb25maWcgPSBuZXcgQ29uZmlnU2VydmljZShzZXJ2aWNlT3B0aW9ucykuZ2V0KCdzZXJ2ZXInKTtcblxuICAgIGlmICghc2VydmljZU9wdGlvbnMuYWNjb3VudCkge1xuICAgICAgICBzZXJ2aWNlT3B0aW9ucy5hY2NvdW50ID0gdXJsQ29uZmlnLmFjY291bnRQYXRoO1xuICAgIH1cblxuICAgIGlmICghc2VydmljZU9wdGlvbnMucHJvamVjdCkge1xuICAgICAgICBzZXJ2aWNlT3B0aW9ucy5wcm9qZWN0ID0gdXJsQ29uZmlnLnByb2plY3RQYXRoO1xuICAgIH1cblxuICAgIHZhciB0cmFuc3BvcnRPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sIHNlcnZpY2VPcHRpb25zLnRyYW5zcG9ydCwge1xuICAgICAgICB1cmw6IHVybENvbmZpZy5nZXRBUElQYXRoKGFwaUVuZHBvaW50KVxuICAgIH0pO1xuXG4gICAgaWYgKHNlcnZpY2VPcHRpb25zLnRva2VuKSB7XG4gICAgICAgIHRyYW5zcG9ydE9wdGlvbnMuaGVhZGVycyA9IHtcbiAgICAgICAgICAgICdBdXRob3JpemF0aW9uJzogJ0JlYXJlciAnICsgc2VydmljZU9wdGlvbnMudG9rZW5cbiAgICAgICAgfTtcbiAgICB9XG5cbiAgICB2YXIgaHR0cCA9IG5ldyBUcmFuc3BvcnRGYWN0b3J5KHRyYW5zcG9ydE9wdGlvbnMpO1xuXG4gICAgdmFyIHNldElkRmlsdGVyT3JUaHJvd0Vycm9yID0gZnVuY3Rpb24gKG9wdGlvbnMpIHtcbiAgICAgICAgaWYgKG9wdGlvbnMuaWQpIHtcbiAgICAgICAgICAgIHNlcnZpY2VPcHRpb25zLmZpbHRlciA9IG9wdGlvbnMuaWQ7XG4gICAgICAgIH1cbiAgICAgICAgaWYgKG9wdGlvbnMuZmlsdGVyKSB7XG4gICAgICAgICAgICBzZXJ2aWNlT3B0aW9ucy5maWx0ZXIgPSBvcHRpb25zLmZpbHRlcjtcbiAgICAgICAgfVxuICAgICAgICBpZiAoIXNlcnZpY2VPcHRpb25zLmZpbHRlcikge1xuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdObyB3b3JsZCBpZCBzcGVjaWZpZWQgdG8gYXBwbHkgb3BlcmF0aW9ucyBhZ2FpbnN0LiBUaGlzIGNvdWxkIGhhcHBlbiBpZiB0aGUgdXNlciBpcyBub3QgYXNzaWduZWQgdG8gYSB3b3JsZCBhbmQgaXMgdHJ5aW5nIHRvIHdvcmsgd2l0aCBydW5zIGZyb20gdGhhdCB3b3JsZC4nKTtcbiAgICAgICAgfVxuICAgIH07XG5cbiAgICB2YXIgdmFsaWRhdGVNb2RlbE9yVGhyb3dFcnJvciA9IGZ1bmN0aW9uIChvcHRpb25zKSB7XG4gICAgICAgIGlmICghb3B0aW9ucy5tb2RlbCkge1xuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdObyBtb2RlbCBzcGVjaWZpZWQgdG8gZ2V0IHRoZSBjdXJyZW50IHJ1bicpO1xuICAgICAgICB9XG4gICAgfTtcblxuICAgIHZhciBwdWJsaWNBUEkgPSB7XG5cbiAgICAgICAgLyoqXG4gICAgICAgICogQ3JlYXRlcyBhIG5ldyBXb3JsZC5cbiAgICAgICAgKlxuICAgICAgICAqIFVzaW5nIHRoaXMgbWV0aG9kIGlzIHJhcmUuIEl0IGlzIG1vcmUgY29tbW9uIHRvIGNyZWF0ZSB3b3JsZHMgYXV0b21hdGljYWxseSB3aGlsZSB5b3UgYGF1dG9Bc3NpZ24oKWAgZW5kIHVzZXJzIHRvIHdvcmxkcy4gKEluIHRoaXMgY2FzZSwgY29uZmlndXJhdGlvbiBkYXRhIGZvciB0aGUgd29ybGQsIHN1Y2ggYXMgdGhlIHJvbGVzLCBhcmUgcmVhZCBmcm9tIHRoZSBwcm9qZWN0LWxldmVsIHdvcmxkIGNvbmZpZ3VyYXRpb24gaW5mb3JtYXRpb24sIGZvciBleGFtcGxlIGJ5IGBnZXRQcm9qZWN0U2V0dGluZ3MoKWAuKVxuICAgICAgICAqXG4gICAgICAgICogICoqRXhhbXBsZSoqXG4gICAgICAgICpcbiAgICAgICAgKiAgICAgIHZhciB3YSA9IG5ldyBGLnNlcnZpY2UuV29ybGQoe1xuICAgICAgICAqICAgICAgICAgICBhY2NvdW50OiAnYWNtZS1zaW11bGF0aW9ucycsXG4gICAgICAgICogICAgICAgICAgIHByb2plY3Q6ICdzdXBwbHktY2hhaW4tZ2FtZScsXG4gICAgICAgICogICAgICAgICAgIGdyb3VwOiAndGVhbTEnIH0pO1xuICAgICAgICAqICAgICAgd2EuY3JlYXRlKHtcbiAgICAgICAgKiAgICAgICAgICAgcm9sZXM6IFsnVlAgTWFya2V0aW5nJywgJ1ZQIFNhbGVzJywgJ1ZQIEVuZ2luZWVyaW5nJ11cbiAgICAgICAgKiAgICAgICB9KTtcbiAgICAgICAgKlxuICAgICAgICAqICAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAqIEBwYXJhbSB7b2JqZWN0fSBgcGFyYW1zYCBQYXJhbWV0ZXJzIHRvIGNyZWF0ZSB0aGUgd29ybGQuXG4gICAgICAgICogQHBhcmFtIHtzdHJpbmd9IGBwYXJhbXMuZ3JvdXBgIChPcHRpb25hbCkgVGhlICoqR3JvdXAgTmFtZSoqIHRvIGNyZWF0ZSB0aGlzIHdvcmxkIHVuZGVyLiBPbmx5IGVuZCB1c2VycyBpbiB0aGlzIGdyb3VwIGFyZSBlbGlnaWJsZSB0byBqb2luIHRoZSB3b3JsZC4gT3B0aW9uYWwgaGVyZTsgcmVxdWlyZWQgd2hlbiBpbnN0YW50aWF0aW5nIHRoZSBzZXJ2aWNlIChgbmV3IEYuc2VydmljZS5Xb3JsZCgpYCkuXG4gICAgICAgICogQHBhcmFtIHtvYmplY3R9IGBwYXJhbXMucm9sZXNgIChPcHRpb25hbCkgVGhlIGxpc3Qgb2Ygcm9sZXMgKHN0cmluZ3MpIGZvciB0aGlzIHdvcmxkLiBTb21lIHdvcmxkcyBoYXZlIHNwZWNpZmljIHJvbGVzIHRoYXQgKiptdXN0KiogYmUgZmlsbGVkIGJ5IGVuZCB1c2Vycy4gTGlzdGluZyB0aGUgcm9sZXMgYWxsb3dzIHlvdSB0byBhdXRvYXNzaWduIHVzZXJzIHRvIHdvcmxkcyBhbmQgZW5zdXJlIHRoYXQgYWxsIHJvbGVzIGFyZSBmaWxsZWQgaW4gZWFjaCB3b3JsZC5cbiAgICAgICAgKiBAcGFyYW0ge29iamVjdH0gYHBhcmFtcy5vcHRpb25hbFJvbGVzYCAoT3B0aW9uYWwpIFRoZSBsaXN0IG9mIG9wdGlvbmFsIHJvbGVzIChzdHJpbmdzKSBmb3IgdGhpcyB3b3JsZC4gU29tZSB3b3JsZHMgaGF2ZSBzcGVjaWZpYyByb2xlcyB0aGF0ICoqbWF5KiogYmUgZmlsbGVkIGJ5IGVuZCB1c2Vycy4gTGlzdGluZyB0aGUgb3B0aW9uYWwgcm9sZXMgYXMgcGFydCBvZiB0aGUgd29ybGQgb2JqZWN0IGFsbG93cyB5b3UgdG8gYXV0b2Fzc2lnbiB1c2VycyB0byB3b3JsZHMgYW5kIGVuc3VyZSB0aGF0IGFsbCByb2xlcyBhcmUgZmlsbGVkIGluIGVhY2ggd29ybGQuXG4gICAgICAgICogQHBhcmFtIHtpbnRlZ2VyfSBgcGFyYW1zLm1pblVzZXJzYCAoT3B0aW9uYWwpIFRoZSBtaW5pbXVtIG51bWJlciBvZiB1c2VycyBmb3IgdGhlIHdvcmxkLiBJbmNsdWRpbmcgdGhpcyBudW1iZXIgYWxsb3dzIHlvdSB0byBhdXRvYXNzaWduIGVuZCB1c2VycyB0byB3b3JsZHMgYW5kIGVuc3VyZSB0aGF0IHRoZSBjb3JyZWN0IG51bWJlciBvZiB1c2VycyBhcmUgaW4gZWFjaCB3b3JsZC5cbiAgICAgICAgKiBAcGFyYW0ge29iamVjdH0gYG9wdGlvbnNgIChPcHRpb25hbCkgT3B0aW9ucyBvYmplY3QgdG8gb3ZlcnJpZGUgZ2xvYmFsIG9wdGlvbnMuXG4gICAgICAgICpcbiAgICAgICAgKi9cbiAgICAgICAgY3JlYXRlOiBmdW5jdGlvbiAocGFyYW1zLCBvcHRpb25zKSB7XG4gICAgICAgICAgICB2YXIgY3JlYXRlT3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LCBzZXJ2aWNlT3B0aW9ucywgb3B0aW9ucywgeyB1cmw6IHVybENvbmZpZy5nZXRBUElQYXRoKGFwaUVuZHBvaW50KSB9KTtcbiAgICAgICAgICAgIHZhciB3b3JsZEFwaVBhcmFtcyA9IFsnc2NvcGUnLCAnZmlsZXMnLCAncm9sZXMnLCAnb3B0aW9uYWxSb2xlcycsICdtaW5Vc2VycycsICdncm91cCcsICduYW1lJ107XG4gICAgICAgICAgICB2YXIgdmFsaWRQYXJhbXMgPSBfcGljayhzZXJ2aWNlT3B0aW9ucywgWydhY2NvdW50JywgJ3Byb2plY3QnLCAnZ3JvdXAnXSk7XG4gICAgICAgICAgICAvLyB3aGl0ZWxpc3QgdGhlIGZpZWxkcyB0aGF0IHdlIGFjdHVhbGx5IGNhbiBzZW5kIHRvIHRoZSBhcGlcbiAgICAgICAgICAgIHBhcmFtcyA9IF9waWNrKHBhcmFtcywgd29ybGRBcGlQYXJhbXMpO1xuXG4gICAgICAgICAgICAvLyBhY2NvdW50IGFuZCBwcm9qZWN0IGdvIGluIHRoZSBib2R5LCBub3QgaW4gdGhlIHVybFxuICAgICAgICAgICAgcGFyYW1zID0gJC5leHRlbmQoe30sIHZhbGlkUGFyYW1zLCBwYXJhbXMpO1xuXG4gICAgICAgICAgICB2YXIgb2xkU3VjY2VzcyA9IGNyZWF0ZU9wdGlvbnMuc3VjY2VzcztcbiAgICAgICAgICAgIGNyZWF0ZU9wdGlvbnMuc3VjY2VzcyA9IGZ1bmN0aW9uIChyZXNwb25zZSkge1xuICAgICAgICAgICAgICAgIHNlcnZpY2VPcHRpb25zLmZpbHRlciA9IHJlc3BvbnNlLmlkOyAvL2FsbCBmdXR1cmUgY2hhaW5lZCBjYWxscyB0byBvcGVyYXRlIG9uIHRoaXMgaWRcbiAgICAgICAgICAgICAgICByZXR1cm4gb2xkU3VjY2Vzcy5hcHBseSh0aGlzLCBhcmd1bWVudHMpO1xuICAgICAgICAgICAgfTtcblxuICAgICAgICAgICAgcmV0dXJuIGh0dHAucG9zdChwYXJhbXMsIGNyZWF0ZU9wdGlvbnMpO1xuICAgICAgICB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAqIFVwZGF0ZXMgYSBXb3JsZCwgZm9yIGV4YW1wbGUgdG8gcmVwbGFjZSB0aGUgcm9sZXMgaW4gdGhlIHdvcmxkLlxuICAgICAgICAqXG4gICAgICAgICogVHlwaWNhbGx5LCB5b3UgY29tcGxldGUgd29ybGQgY29uZmlndXJhdGlvbiBhdCB0aGUgcHJvamVjdCBsZXZlbCwgcmF0aGVyIHRoYW4gYXQgdGhlIHdvcmxkIGxldmVsLiBGb3IgZXhhbXBsZSwgZWFjaCB3b3JsZCBpbiB5b3VyIHByb2plY3QgcHJvYmFibHkgaGFzIHRoZSBzYW1lIHJvbGVzIGZvciBlbmQgdXNlcnMuIEFuZCB5b3VyIHByb2plY3QgaXMgcHJvYmFibHkgZWl0aGVyIGNvbmZpZ3VyZWQgc28gdGhhdCBhbGwgZW5kIHVzZXJzIHNoYXJlIHRoZSBzYW1lIHdvcmxkIChhbmQgcnVuKSwgb3Igc21hbGxlciBzZXRzIG9mIGVuZCB1c2VycyBzaGFyZSB3b3JsZHMg4oCUIGJ1dCBub3QgYm90aC4gSG93ZXZlciwgdGhpcyBtZXRob2QgaXMgYXZhaWxhYmxlIGlmIHlvdSBuZWVkIHRvIHVwZGF0ZSB0aGUgY29uZmlndXJhdGlvbiBvZiBhIHBhcnRpY3VsYXIgd29ybGQuXG4gICAgICAgICpcbiAgICAgICAgKiAgKipFeGFtcGxlKipcbiAgICAgICAgKlxuICAgICAgICAqICAgICAgdmFyIHdhID0gbmV3IEYuc2VydmljZS5Xb3JsZCh7XG4gICAgICAgICogICAgICAgICAgIGFjY291bnQ6ICdhY21lLXNpbXVsYXRpb25zJyxcbiAgICAgICAgKiAgICAgICAgICAgcHJvamVjdDogJ3N1cHBseS1jaGFpbi1nYW1lJyxcbiAgICAgICAgKiAgICAgICAgICAgZ3JvdXA6ICd0ZWFtMScgfSk7XG4gICAgICAgICogICAgICB3YS5jcmVhdGUoKVxuICAgICAgICAqICAgICAgICAgICAudGhlbihmdW5jdGlvbih3b3JsZCkge1xuICAgICAgICAqICAgICAgICAgICAgICAgd2EudXBkYXRlKHsgcm9sZXM6IFsnVlAgTWFya2V0aW5nJywgJ1ZQIFNhbGVzJywgJ1ZQIEVuZ2luZWVyaW5nJ10gfSk7XG4gICAgICAgICogICAgICAgICAgIH0pO1xuICAgICAgICAqXG4gICAgICAgICogICoqUGFyYW1ldGVycyoqXG4gICAgICAgICogQHBhcmFtIHtvYmplY3R9IGBwYXJhbXNgIFBhcmFtZXRlcnMgdG8gdXBkYXRlIHRoZSB3b3JsZC5cbiAgICAgICAgKiBAcGFyYW0ge3N0cmluZ30gYHBhcmFtcy5uYW1lYCBBIHN0cmluZyBpZGVudGlmaWVyIGZvciB0aGUgbGlua2VkIGVuZCB1c2VycywgZm9yIGV4YW1wbGUsIFwibmFtZVwiOiBcIk91ciBUZWFtXCIuXG4gICAgICAgICogQHBhcmFtIHtvYmplY3R9IGBwYXJhbXMucm9sZXNgIChPcHRpb25hbCkgVGhlIGxpc3Qgb2Ygcm9sZXMgKHN0cmluZ3MpIGZvciB0aGlzIHdvcmxkLiBTb21lIHdvcmxkcyBoYXZlIHNwZWNpZmljIHJvbGVzIHRoYXQgKiptdXN0KiogYmUgZmlsbGVkIGJ5IGVuZCB1c2Vycy4gTGlzdGluZyB0aGUgcm9sZXMgYWxsb3dzIHlvdSB0byBhdXRvYXNzaWduIHVzZXJzIHRvIHdvcmxkcyBhbmQgZW5zdXJlIHRoYXQgYWxsIHJvbGVzIGFyZSBmaWxsZWQgaW4gZWFjaCB3b3JsZC5cbiAgICAgICAgKiBAcGFyYW0ge29iamVjdH0gYHBhcmFtcy5vcHRpb25hbFJvbGVzYCAoT3B0aW9uYWwpIFRoZSBsaXN0IG9mIG9wdGlvbmFsIHJvbGVzIChzdHJpbmdzKSBmb3IgdGhpcyB3b3JsZC4gU29tZSB3b3JsZHMgaGF2ZSBzcGVjaWZpYyByb2xlcyB0aGF0ICoqbWF5KiogYmUgZmlsbGVkIGJ5IGVuZCB1c2Vycy4gTGlzdGluZyB0aGUgb3B0aW9uYWwgcm9sZXMgYXMgcGFydCBvZiB0aGUgd29ybGQgb2JqZWN0IGFsbG93cyB5b3UgdG8gYXV0b2Fzc2lnbiB1c2VycyB0byB3b3JsZHMgYW5kIGVuc3VyZSB0aGF0IGFsbCByb2xlcyBhcmUgZmlsbGVkIGluIGVhY2ggd29ybGQuXG4gICAgICAgICogQHBhcmFtIHtpbnRlZ2VyfSBgcGFyYW1zLm1pblVzZXJzYCAoT3B0aW9uYWwpIFRoZSBtaW5pbXVtIG51bWJlciBvZiB1c2VycyBmb3IgdGhlIHdvcmxkLiBJbmNsdWRpbmcgdGhpcyBudW1iZXIgYWxsb3dzIHlvdSB0byBhdXRvYXNzaWduIGVuZCB1c2VycyB0byB3b3JsZHMgYW5kIGVuc3VyZSB0aGF0IHRoZSBjb3JyZWN0IG51bWJlciBvZiB1c2VycyBhcmUgaW4gZWFjaCB3b3JsZC5cbiAgICAgICAgKiBAcGFyYW0ge29iamVjdH0gYG9wdGlvbnNgIChPcHRpb25hbCkgT3B0aW9ucyBvYmplY3QgdG8gb3ZlcnJpZGUgZ2xvYmFsIG9wdGlvbnMuXG4gICAgICAgICpcbiAgICAgICAgKi9cbiAgICAgICAgdXBkYXRlOiBmdW5jdGlvbiAocGFyYW1zLCBvcHRpb25zKSB7XG4gICAgICAgICAgICB2YXIgd2hpdGVsaXN0ID0gWydyb2xlcycsICdvcHRpb25hbFJvbGVzJywgJ21pblVzZXJzJ107XG4gICAgICAgICAgICBvcHRpb25zID0gb3B0aW9ucyB8fCB7fTtcbiAgICAgICAgICAgIHNldElkRmlsdGVyT3JUaHJvd0Vycm9yKG9wdGlvbnMpO1xuXG4gICAgICAgICAgICB2YXIgdXBkYXRlT3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LFxuICAgICAgICAgICAgICAgIHNlcnZpY2VPcHRpb25zLFxuICAgICAgICAgICAgICAgIG9wdGlvbnMsXG4gICAgICAgICAgICAgICAgeyB1cmw6IHVybENvbmZpZy5nZXRBUElQYXRoKGFwaUVuZHBvaW50KSArIHNlcnZpY2VPcHRpb25zLmZpbHRlciB9XG4gICAgICAgICAgICApO1xuXG4gICAgICAgICAgICBwYXJhbXMgPSBfcGljayhwYXJhbXMgfHwge30sIHdoaXRlbGlzdCk7XG5cbiAgICAgICAgICAgIHJldHVybiBodHRwLnBhdGNoKHBhcmFtcywgdXBkYXRlT3B0aW9ucyk7XG4gICAgICAgIH0sXG5cbiAgICAgICAgLyoqXG4gICAgICAgICogRGVsZXRlcyBhbiBleGlzdGluZyB3b3JsZC5cbiAgICAgICAgKlxuICAgICAgICAqIFRoaXMgZnVuY3Rpb24gb3B0aW9uYWxseSB0YWtlcyBvbmUgYXJndW1lbnQuIElmIHRoZSBhcmd1bWVudCBpcyBhIHN0cmluZywgaXQgaXMgdGhlIGlkIG9mIHRoZSB3b3JsZCB0byBkZWxldGUuIElmIHRoZSBhcmd1bWVudCBpcyBhbiBvYmplY3QsIGl0IGlzIHRoZSBvdmVycmlkZSBmb3IgZ2xvYmFsIG9wdGlvbnMuXG4gICAgICAgICpcbiAgICAgICAgKiAgKipFeGFtcGxlKipcbiAgICAgICAgKlxuICAgICAgICAqICAgICAgdmFyIHdhID0gbmV3IEYuc2VydmljZS5Xb3JsZCh7XG4gICAgICAgICogICAgICAgICAgIGFjY291bnQ6ICdhY21lLXNpbXVsYXRpb25zJyxcbiAgICAgICAgKiAgICAgICAgICAgcHJvamVjdDogJ3N1cHBseS1jaGFpbi1nYW1lJyxcbiAgICAgICAgKiAgICAgICAgICAgZ3JvdXA6ICd0ZWFtMScgfSk7XG4gICAgICAgICogICAgICB3YS5jcmVhdGUoKVxuICAgICAgICAqICAgICAgICAgICAudGhlbihmdW5jdGlvbih3b3JsZCkge1xuICAgICAgICAqICAgICAgICAgICAgICAgd2EuZGVsZXRlKCk7XG4gICAgICAgICogICAgICAgICAgIH0pO1xuICAgICAgICAqXG4gICAgICAgICogICoqUGFyYW1ldGVycyoqXG4gICAgICAgICogQHBhcmFtIHtTdHJpbmd8T2JqZWN0fSBgb3B0aW9uc2AgKE9wdGlvbmFsKSBUaGUgaWQgb2YgdGhlIHdvcmxkIHRvIGRlbGV0ZSwgb3Igb3B0aW9ucyBvYmplY3QgdG8gb3ZlcnJpZGUgZ2xvYmFsIG9wdGlvbnMuXG4gICAgICAgICpcbiAgICAgICAgKi9cbiAgICAgICAgZGVsZXRlOiBmdW5jdGlvbiAob3B0aW9ucykge1xuICAgICAgICAgICAgb3B0aW9ucyA9IChvcHRpb25zICYmICh0eXBlb2Ygb3B0aW9ucyA9PT0gJ3N0cmluZycpKSA/IHsgZmlsdGVyOiBvcHRpb25zIH0gOiB7fTtcbiAgICAgICAgICAgIHNldElkRmlsdGVyT3JUaHJvd0Vycm9yKG9wdGlvbnMpO1xuXG4gICAgICAgICAgICB2YXIgZGVsZXRlT3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LFxuICAgICAgICAgICAgICAgIHNlcnZpY2VPcHRpb25zLFxuICAgICAgICAgICAgICAgIG9wdGlvbnMsXG4gICAgICAgICAgICAgICAgeyB1cmw6IHVybENvbmZpZy5nZXRBUElQYXRoKGFwaUVuZHBvaW50KSArIHNlcnZpY2VPcHRpb25zLmZpbHRlciB9XG4gICAgICAgICAgICApO1xuXG4gICAgICAgICAgICByZXR1cm4gaHR0cC5kZWxldGUobnVsbCwgZGVsZXRlT3B0aW9ucyk7XG4gICAgICAgIH0sXG5cbiAgICAgICAgLyoqXG4gICAgICAgICogVXBkYXRlcyB0aGUgY29uZmlndXJhdGlvbiBmb3IgdGhlIGN1cnJlbnQgaW5zdGFuY2Ugb2YgdGhlIFdvcmxkIEFQSSBBZGFwdGVyIChpbmNsdWRpbmcgYWxsIHN1YnNlcXVlbnQgZnVuY3Rpb24gY2FsbHMsIHVudGlsIHRoZSBjb25maWd1cmF0aW9uIGlzIHVwZGF0ZWQgYWdhaW4pLlxuICAgICAgICAqXG4gICAgICAgICogKipFeGFtcGxlKipcbiAgICAgICAgKlxuICAgICAgICAqICAgICAgdmFyIHdhID0gbmV3IEYuc2VydmljZS5Xb3JsZCh7Li4ufSkudXBkYXRlQ29uZmlnKHsgZmlsdGVyOiAnMTIzJyB9KS5hZGRVc2VyKHsgdXNlcklkOiAnMTIzJyB9KTtcbiAgICAgICAgKlxuICAgICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICAgICogQHBhcmFtIHtvYmplY3R9IGBjb25maWdgIFRoZSBjb25maWd1cmF0aW9uIG9iamVjdCB0byB1c2UgaW4gdXBkYXRpbmcgZXhpc3RpbmcgY29uZmlndXJhdGlvbi5cbiAgICAgICAgKi9cbiAgICAgICAgdXBkYXRlQ29uZmlnOiBmdW5jdGlvbiAoY29uZmlnKSB7XG4gICAgICAgICAgICAkLmV4dGVuZChzZXJ2aWNlT3B0aW9ucywgY29uZmlnKTtcblxuICAgICAgICAgICAgcmV0dXJuIHRoaXM7XG4gICAgICAgIH0sXG5cbiAgICAgICAgLyoqXG4gICAgICAgICogTGlzdHMgYWxsIHdvcmxkcyBmb3IgYSBnaXZlbiBhY2NvdW50LCBwcm9qZWN0LCBhbmQgZ3JvdXAuIEFsbCB0aHJlZSBhcmUgcmVxdWlyZWQsIGFuZCBpZiBub3Qgc3BlY2lmaWVkIGFzIHBhcmFtZXRlcnMsIGFyZSByZWFkIGZyb20gdGhlIHNlcnZpY2UuXG4gICAgICAgICpcbiAgICAgICAgKiAgKipFeGFtcGxlKipcbiAgICAgICAgKlxuICAgICAgICAqICAgICAgdmFyIHdhID0gbmV3IEYuc2VydmljZS5Xb3JsZCh7XG4gICAgICAgICogICAgICAgICAgIGFjY291bnQ6ICdhY21lLXNpbXVsYXRpb25zJyxcbiAgICAgICAgKiAgICAgICAgICAgcHJvamVjdDogJ3N1cHBseS1jaGFpbi1nYW1lJyxcbiAgICAgICAgKiAgICAgICAgICAgZ3JvdXA6ICd0ZWFtMScgfSk7XG4gICAgICAgICogICAgICB3YS5jcmVhdGUoKVxuICAgICAgICAqICAgICAgICAgICAudGhlbihmdW5jdGlvbih3b3JsZCkge1xuICAgICAgICAqICAgICAgICAgICAgICAgLy8gbGlzdHMgYWxsIHdvcmxkcyBpbiBncm91cCBcInRlYW0xXCJcbiAgICAgICAgKiAgICAgICAgICAgICAgIHdhLmxpc3QoKTtcbiAgICAgICAgKlxuICAgICAgICAqICAgICAgICAgICAgICAgLy8gbGlzdHMgYWxsIHdvcmxkcyBpbiBncm91cCBcIm90aGVyLWdyb3VwLW5hbWVcIlxuICAgICAgICAqICAgICAgICAgICAgICAgd2EubGlzdCh7IGdyb3VwOiAnb3RoZXItZ3JvdXAtbmFtZScgfSk7XG4gICAgICAgICogICAgICAgICAgIH0pO1xuICAgICAgICAqXG4gICAgICAgICogICoqUGFyYW1ldGVycyoqXG4gICAgICAgICogQHBhcmFtIHtvYmplY3R9IGBvcHRpb25zYCAoT3B0aW9uYWwpIE9wdGlvbnMgb2JqZWN0IHRvIG92ZXJyaWRlIGdsb2JhbCBvcHRpb25zLlxuICAgICAgICAqXG4gICAgICAgICovXG4gICAgICAgIGxpc3Q6IGZ1bmN0aW9uIChvcHRpb25zKSB7XG4gICAgICAgICAgICBvcHRpb25zID0gb3B0aW9ucyB8fCB7fTtcblxuICAgICAgICAgICAgdmFyIGdldE9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSxcbiAgICAgICAgICAgICAgICBzZXJ2aWNlT3B0aW9ucyxcbiAgICAgICAgICAgICAgICBvcHRpb25zLFxuICAgICAgICAgICAgICAgIHsgdXJsOiB1cmxDb25maWcuZ2V0QVBJUGF0aChhcGlFbmRwb2ludCkgfVxuICAgICAgICAgICAgKTtcblxuICAgICAgICAgICAgdmFyIGZpbHRlcnMgPSBfcGljayhnZXRPcHRpb25zLCBbJ2FjY291bnQnLCAncHJvamVjdCcsICdncm91cCddKTtcblxuICAgICAgICAgICAgcmV0dXJuIGh0dHAuZ2V0KGZpbHRlcnMsIGdldE9wdGlvbnMpO1xuICAgICAgICB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAqIEdldHMgYWxsIHdvcmxkcyB0aGF0IGFuIGVuZCB1c2VyIGJlbG9uZ3MgdG8gZm9yIGEgZ2l2ZW4gYWNjb3VudCAodGVhbSksIHByb2plY3QsIGFuZCBncm91cC5cbiAgICAgICAgKlxuICAgICAgICAqICAqKkV4YW1wbGUqKlxuICAgICAgICAqXG4gICAgICAgICogICAgICB2YXIgd2EgPSBuZXcgRi5zZXJ2aWNlLldvcmxkKHtcbiAgICAgICAgKiAgICAgICAgICAgYWNjb3VudDogJ2FjbWUtc2ltdWxhdGlvbnMnLFxuICAgICAgICAqICAgICAgICAgICBwcm9qZWN0OiAnc3VwcGx5LWNoYWluLWdhbWUnLFxuICAgICAgICAqICAgICAgICAgICBncm91cDogJ3RlYW0xJyB9KTtcbiAgICAgICAgKiAgICAgIHdhLmNyZWF0ZSgpXG4gICAgICAgICogICAgICAgICAgIC50aGVuKGZ1bmN0aW9uKHdvcmxkKSB7XG4gICAgICAgICogICAgICAgICAgICAgICB3YS5nZXRXb3JsZHNGb3JVc2VyKCdiMWMxOWRkYS0yZDJlLTQ3NzctYWQ1ZC0zOTI5ZjE3ZTg2ZDMnKVxuICAgICAgICAqICAgICAgICAgICB9KTtcbiAgICAgICAgKlxuICAgICAgICAqICoqIFBhcmFtZXRlcnMgKipcbiAgICAgICAgKiBAcGFyYW0ge3N0cmluZ30gYHVzZXJJZGAgVGhlIGB1c2VySWRgIG9mIHRoZSB1c2VyIHdob3NlIHdvcmxkcyBhcmUgYmVpbmcgcmV0cmlldmVkLlxuICAgICAgICAqIEBwYXJhbSB7b2JqZWN0fSBgb3B0aW9uc2AgKE9wdGlvbmFsKSBPcHRpb25zIG9iamVjdCB0byBvdmVycmlkZSBnbG9iYWwgb3B0aW9ucy5cbiAgICAgICAgKi9cbiAgICAgICAgZ2V0V29ybGRzRm9yVXNlcjogZnVuY3Rpb24gKHVzZXJJZCwgb3B0aW9ucykge1xuICAgICAgICAgICAgb3B0aW9ucyA9IG9wdGlvbnMgfHwge307XG5cbiAgICAgICAgICAgIHZhciBnZXRPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sXG4gICAgICAgICAgICAgICAgc2VydmljZU9wdGlvbnMsXG4gICAgICAgICAgICAgICAgb3B0aW9ucyxcbiAgICAgICAgICAgICAgICB7IHVybDogdXJsQ29uZmlnLmdldEFQSVBhdGgoYXBpRW5kcG9pbnQpIH1cbiAgICAgICAgICAgICk7XG5cbiAgICAgICAgICAgIHZhciBmaWx0ZXJzID0gJC5leHRlbmQoXG4gICAgICAgICAgICAgICAgX3BpY2soZ2V0T3B0aW9ucywgWydhY2NvdW50JywgJ3Byb2plY3QnLCAnZ3JvdXAnXSksXG4gICAgICAgICAgICAgICAgeyB1c2VySWQ6IHVzZXJJZCB9XG4gICAgICAgICAgICApO1xuXG4gICAgICAgICAgICByZXR1cm4gaHR0cC5nZXQoZmlsdGVycywgZ2V0T3B0aW9ucyk7XG4gICAgICAgIH0sXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIExvYWQgaW5mb3JtYXRpb24gZm9yIGEgc3BlY2lmaWMgd29ybGQuIEFsbCBmdXJ0aGVyIGNhbGxzIHRvIHRoZSB3b3JsZCBzZXJ2aWNlIHdpbGwgdXNlIHRoZSBpZCBwcm92aWRlZC5cbiAgICAgICAgICpcbiAgICAgICAgICogKipQYXJhbWV0ZXJzKipcbiAgICAgICAgICogQHBhcmFtIHtTdHJpbmd9IGB3b3JsZElkYCBUaGUgaWQgb2YgdGhlIHdvcmxkIHRvIGxvYWQuXG4gICAgICAgICAqIEBwYXJhbSB7T2JqZWN0fSBgb3B0aW9uc2AgKE9wdGlvbmFsKSBPcHRpb25zIG9iamVjdCB0byBvdmVycmlkZSBnbG9iYWwgb3B0aW9ucy5cbiAgICAgICAgICovXG4gICAgICAgIGxvYWQ6IGZ1bmN0aW9uICh3b3JsZElkLCBvcHRpb25zKSB7XG4gICAgICAgICAgICBpZiAod29ybGRJZCkge1xuICAgICAgICAgICAgICAgIHNlcnZpY2VPcHRpb25zLmZpbHRlciA9IHdvcmxkSWQ7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBpZiAoIXNlcnZpY2VPcHRpb25zLmZpbHRlcikge1xuICAgICAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcignUGxlYXNlIHByb3ZpZGUgYSB3b3JsZGlkIHRvIGxvYWQnKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHZhciBodHRwT3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LCBzZXJ2aWNlT3B0aW9ucywgb3B0aW9ucywgIHsgdXJsOiB1cmxDb25maWcuZ2V0QVBJUGF0aChhcGlFbmRwb2ludCkgKyBzZXJ2aWNlT3B0aW9ucy5maWx0ZXIgKyAnLycgfSk7XG4gICAgICAgICAgICByZXR1cm4gaHR0cC5nZXQoJycsIGh0dHBPcHRpb25zKTtcbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgKiBBZGRzIGFuIGVuZCB1c2VyIG9yIGxpc3Qgb2YgZW5kIHVzZXJzIHRvIGEgZ2l2ZW4gd29ybGQuIFRoZSBlbmQgdXNlciBtdXN0IGJlIGEgbWVtYmVyIG9mIHRoZSBgZ3JvdXBgIHRoYXQgaXMgYXNzb2NpYXRlZCB3aXRoIHRoaXMgd29ybGQuXG4gICAgICAgICpcbiAgICAgICAgKiAgKipFeGFtcGxlKipcbiAgICAgICAgKlxuICAgICAgICAqICAgICAgdmFyIHdhID0gbmV3IEYuc2VydmljZS5Xb3JsZCh7XG4gICAgICAgICogICAgICAgICAgIGFjY291bnQ6ICdhY21lLXNpbXVsYXRpb25zJyxcbiAgICAgICAgKiAgICAgICAgICAgcHJvamVjdDogJ3N1cHBseS1jaGFpbi1nYW1lJyxcbiAgICAgICAgKiAgICAgICAgICAgZ3JvdXA6ICd0ZWFtMScgfSk7XG4gICAgICAgICogICAgICB3YS5jcmVhdGUoKVxuICAgICAgICAqICAgICAgICAgICAudGhlbihmdW5jdGlvbih3b3JsZCkge1xuICAgICAgICAqICAgICAgICAgICAgICAgLy8gYWRkIG9uZSB1c2VyXG4gICAgICAgICogICAgICAgICAgICAgICB3YS5hZGRVc2VycygnYjFjMTlkZGEtMmQyZS00Nzc3LWFkNWQtMzkyOWYxN2U4NmQzJyk7XG4gICAgICAgICogICAgICAgICAgICAgICB3YS5hZGRVc2VycyhbJ2IxYzE5ZGRhLTJkMmUtNDc3Ny1hZDVkLTM5MjlmMTdlODZkMyddKTtcbiAgICAgICAgKiAgICAgICAgICAgICAgIHdhLmFkZFVzZXJzKHsgdXNlcklkOiAnYjFjMTlkZGEtMmQyZS00Nzc3LWFkNWQtMzkyOWYxN2U4NmQzJywgcm9sZTogJ1ZQIFNhbGVzJyB9KTtcbiAgICAgICAgKlxuICAgICAgICAqICAgICAgICAgICAgICAgLy8gYWRkIHNldmVyYWwgdXNlcnNcbiAgICAgICAgKiAgICAgICAgICAgICAgIHdhLmFkZFVzZXJzKFtcbiAgICAgICAgKiAgICAgICAgICAgICAgICAgICB7IHVzZXJJZDogJ2E2ZmUwYzFlLWY0YjgtNGYwMS05ZjVmLTAxY2NmNGMyZWQ0NCcsXG4gICAgICAgICogICAgICAgICAgICAgICAgICAgICByb2xlOiAnVlAgTWFya2V0aW5nJyB9LFxuICAgICAgICAqICAgICAgICAgICAgICAgICAgIHsgdXNlcklkOiAnOGYyNjA0Y2YtOTZjZC00NDlmLTgyZmEtZTMzMTUzMDczNGVlJyxcbiAgICAgICAgKiAgICAgICAgICAgICAgICAgICAgIHJvbGU6ICdWUCBFbmdpbmVlcmluZycgfVxuICAgICAgICAqICAgICAgICAgICAgICAgXSk7XG4gICAgICAgICpcbiAgICAgICAgKiAgICAgICAgICAgICAgIC8vIGFkZCBvbmUgdXNlciB0byBhIHNwZWNpZmljIHdvcmxkXG4gICAgICAgICogICAgICAgICAgICAgICB3YS5hZGRVc2VycygnYjFjMTlkZGEtMmQyZS00Nzc3LWFkNWQtMzkyOWYxN2U4NmQzJywgd29ybGQuaWQpO1xuICAgICAgICAqICAgICAgICAgICAgICAgd2EuYWRkVXNlcnMoJ2IxYzE5ZGRhLTJkMmUtNDc3Ny1hZDVkLTM5MjlmMTdlODZkMycsIHsgZmlsdGVyOiB3b3JsZC5pZCB9KTtcbiAgICAgICAgKiAgICAgICAgICAgfSk7XG4gICAgICAgICpcbiAgICAgICAgKiAqKiBQYXJhbWV0ZXJzICoqXG4gICAgICAgICogQHBhcmFtIHtzdHJpbmd8b2JqZWN0fGFycmF5fSBgdXNlcnNgIFVzZXIgaWQsIGFycmF5IG9mIHVzZXIgaWRzLCBvYmplY3QsIG9yIGFycmF5IG9mIG9iamVjdHMgb2YgdGhlIHVzZXJzIHRvIGFkZCB0byB0aGlzIHdvcmxkLlxuICAgICAgICAqIEBwYXJhbSB7c3RyaW5nfSBgdXNlcnMucm9sZWAgVGhlIGByb2xlYCB0aGUgdXNlciBzaG91bGQgaGF2ZSBpbiB0aGUgd29ybGQuIEl0IGlzIHVwIHRvIHRoZSBjYWxsZXIgdG8gZW5zdXJlLCBpZiBuZWVkZWQsIHRoYXQgdGhlIGByb2xlYCBwYXNzZWQgaW4gaXMgb25lIG9mIHRoZSBgcm9sZXNgIG9yIGBvcHRpb25hbFJvbGVzYCBvZiB0aGlzIHdvcmxkLlxuICAgICAgICAqIEBwYXJhbSB7c3RyaW5nfSBgd29ybGRJZGAgVGhlIHdvcmxkIHRvIHdoaWNoIHRoZSB1c2VycyBzaG91bGQgYmUgYWRkZWQuIElmIG5vdCBzcGVjaWZpZWQsIHRoZSBmaWx0ZXIgcGFyYW1ldGVyIG9mIHRoZSBgb3B0aW9uc2Agb2JqZWN0IGlzIHVzZWQuXG4gICAgICAgICogQHBhcmFtIHtvYmplY3R9IGBvcHRpb25zYCAoT3B0aW9uYWwpIE9wdGlvbnMgb2JqZWN0IHRvIG92ZXJyaWRlIGdsb2JhbCBvcHRpb25zLlxuICAgICAgICAqL1xuICAgICAgICBhZGRVc2VyczogZnVuY3Rpb24gKHVzZXJzLCB3b3JsZElkLCBvcHRpb25zKSB7XG5cbiAgICAgICAgICAgIGlmICghdXNlcnMpIHtcbiAgICAgICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ1BsZWFzZSBwcm92aWRlIGEgbGlzdCBvZiB1c2VycyB0byBhZGQgdG8gdGhlIHdvcmxkJyk7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIC8vIG5vcm1hbGl6ZSB0aGUgbGlzdCBvZiB1c2VycyB0byBhbiBhcnJheSBvZiB1c2VyIG9iamVjdHNcbiAgICAgICAgICAgIHVzZXJzID0gJC5tYXAoW10uY29uY2F0KHVzZXJzKSwgZnVuY3Rpb24gKHUpIHtcbiAgICAgICAgICAgICAgICB2YXIgaXNPYmplY3QgPSAkLmlzUGxhaW5PYmplY3QodSk7XG5cbiAgICAgICAgICAgICAgICBpZiAodHlwZW9mIHUgIT09ICdzdHJpbmcnICYmICFpc09iamVjdCkge1xuICAgICAgICAgICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ1NvbWUgb2YgdGhlIHVzZXJzIGluIHRoZSBsaXN0IGFyZSBub3QgaW4gdGhlIHZhbGlkIGZvcm1hdDogJyArIHUpO1xuICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgIHJldHVybiBpc09iamVjdCA/IHUgOiB7IHVzZXJJZDogdSB9O1xuICAgICAgICAgICAgfSk7XG5cbiAgICAgICAgICAgIC8vIGNoZWNrIGlmIG9wdGlvbnMgd2VyZSBwYXNzZWQgYXMgdGhlIHNlY29uZCBwYXJhbWV0ZXJcbiAgICAgICAgICAgIGlmICgkLmlzUGxhaW5PYmplY3Qod29ybGRJZCkgJiYgIW9wdGlvbnMpIHtcbiAgICAgICAgICAgICAgICBvcHRpb25zID0gd29ybGRJZDtcbiAgICAgICAgICAgICAgICB3b3JsZElkID0gbnVsbDtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgb3B0aW9ucyA9IG9wdGlvbnMgfHwge307XG5cbiAgICAgICAgICAgIC8vIHdlIG11c3QgaGF2ZSBvcHRpb25zIGJ5IG5vd1xuICAgICAgICAgICAgaWYgKHR5cGVvZiB3b3JsZElkID09PSAnc3RyaW5nJykge1xuICAgICAgICAgICAgICAgIG9wdGlvbnMuZmlsdGVyID0gd29ybGRJZDtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgc2V0SWRGaWx0ZXJPclRocm93RXJyb3Iob3B0aW9ucyk7XG5cbiAgICAgICAgICAgIHZhciB1cGRhdGVPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sXG4gICAgICAgICAgICAgICAgc2VydmljZU9wdGlvbnMsXG4gICAgICAgICAgICAgICAgb3B0aW9ucyxcbiAgICAgICAgICAgICAgICB7IHVybDogdXJsQ29uZmlnLmdldEFQSVBhdGgoYXBpRW5kcG9pbnQpICsgc2VydmljZU9wdGlvbnMuZmlsdGVyICsgJy91c2VycycgfVxuICAgICAgICAgICAgKTtcblxuICAgICAgICAgICAgcmV0dXJuIGh0dHAucG9zdCh1c2VycywgdXBkYXRlT3B0aW9ucyk7XG4gICAgICAgIH0sXG5cbiAgICAgICAgLyoqXG4gICAgICAgICogVXBkYXRlcyB0aGUgcm9sZSBvZiBhbiBlbmQgdXNlciBpbiBhIGdpdmVuIHdvcmxkLiAoWW91IGNhbiBvbmx5IHVwZGF0ZSBvbmUgZW5kIHVzZXIgYXQgYSB0aW1lLilcbiAgICAgICAgKlxuICAgICAgICAqICoqRXhhbXBsZSoqXG4gICAgICAgICpcbiAgICAgICAgKiAgICAgIHZhciB3YSA9IG5ldyBGLnNlcnZpY2UuV29ybGQoe1xuICAgICAgICAqICAgICAgICAgICBhY2NvdW50OiAnYWNtZS1zaW11bGF0aW9ucycsXG4gICAgICAgICogICAgICAgICAgIHByb2plY3Q6ICdzdXBwbHktY2hhaW4tZ2FtZScsXG4gICAgICAgICogICAgICAgICAgIGdyb3VwOiAndGVhbTEnIH0pO1xuICAgICAgICAqXG4gICAgICAgICogICAgICB3YS5jcmVhdGUoKS50aGVuKGZ1bmN0aW9uKHdvcmxkKSB7XG4gICAgICAgICogICAgICAgICAgIHdhLmFkZFVzZXJzKCdiMWMxOWRkYS0yZDJlLTQ3NzctYWQ1ZC0zOTI5ZjE3ZTg2ZDMnKTtcbiAgICAgICAgKiAgICAgICAgICAgd2EudXBkYXRlVXNlcih7IHVzZXJJZDogJ2IxYzE5ZGRhLTJkMmUtNDc3Ny1hZDVkLTM5MjlmMTdlODZkMycsIHJvbGU6ICdsZWFkZXInIH0pO1xuICAgICAgICAqICAgICAgfSk7XG4gICAgICAgICpcbiAgICAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAqIEBwYXJhbSB7b2JqZWN0fSBgdXNlcmAgVXNlciBvYmplY3Qgd2l0aCBgdXNlcklkYCBhbmQgdGhlIG5ldyBgcm9sZWAuXG4gICAgICAgICogQHBhcmFtIHtvYmplY3R9IGBvcHRpb25zYCAoT3B0aW9uYWwpIE9wdGlvbnMgb2JqZWN0IHRvIG92ZXJyaWRlIGdsb2JhbCBvcHRpb25zLlxuICAgICAgICAqXG4gICAgICAgICovXG4gICAgICAgIHVwZGF0ZVVzZXI6IGZ1bmN0aW9uICh1c2VyLCBvcHRpb25zKSB7XG4gICAgICAgICAgICBvcHRpb25zID0gb3B0aW9ucyB8fCB7fTtcblxuICAgICAgICAgICAgaWYgKCF1c2VyIHx8ICF1c2VyLnVzZXJJZCkge1xuICAgICAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcignWW91IG5lZWQgdG8gcGFzcyBhIHVzZXJJZCB0byB1cGRhdGUgZnJvbSB0aGUgd29ybGQnKTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgc2V0SWRGaWx0ZXJPclRocm93RXJyb3Iob3B0aW9ucyk7XG5cbiAgICAgICAgICAgIHZhciBwYXRjaE9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSxcbiAgICAgICAgICAgICAgICBzZXJ2aWNlT3B0aW9ucyxcbiAgICAgICAgICAgICAgICBvcHRpb25zLFxuICAgICAgICAgICAgICAgIHsgdXJsOiB1cmxDb25maWcuZ2V0QVBJUGF0aChhcGlFbmRwb2ludCkgKyBzZXJ2aWNlT3B0aW9ucy5maWx0ZXIgKyAnL3VzZXJzLycgKyB1c2VyLnVzZXJJZCB9XG4gICAgICAgICAgICApO1xuXG4gICAgICAgICAgICByZXR1cm4gaHR0cC5wYXRjaChfcGljayh1c2VyLCAncm9sZScpLCBwYXRjaE9wdGlvbnMpO1xuICAgICAgICB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAqIFJlbW92ZXMgYW4gZW5kIHVzZXIgZnJvbSBhIGdpdmVuIHdvcmxkLlxuICAgICAgICAqXG4gICAgICAgICogICoqRXhhbXBsZSoqXG4gICAgICAgICpcbiAgICAgICAgKiAgICAgIHZhciB3YSA9IG5ldyBGLnNlcnZpY2UuV29ybGQoe1xuICAgICAgICAqICAgICAgICAgICBhY2NvdW50OiAnYWNtZS1zaW11bGF0aW9ucycsXG4gICAgICAgICogICAgICAgICAgIHByb2plY3Q6ICdzdXBwbHktY2hhaW4tZ2FtZScsXG4gICAgICAgICogICAgICAgICAgIGdyb3VwOiAndGVhbTEnIH0pO1xuICAgICAgICAqICAgICAgd2EuY3JlYXRlKClcbiAgICAgICAgKiAgICAgICAgICAgLnRoZW4oZnVuY3Rpb24od29ybGQpIHtcbiAgICAgICAgKiAgICAgICAgICAgICAgIHdhLmFkZFVzZXJzKFsnYTZmZTBjMWUtZjRiOC00ZjAxLTlmNWYtMDFjY2Y0YzJlZDQ0JywgJzhmMjYwNGNmLTk2Y2QtNDQ5Zi04MmZhLWUzMzE1MzA3MzRlZSddKTtcbiAgICAgICAgKiAgICAgICAgICAgICAgIHdhLnJlbW92ZVVzZXIoJ2E2ZmUwYzFlLWY0YjgtNGYwMS05ZjVmLTAxY2NmNGMyZWQ0NCcpO1xuICAgICAgICAqICAgICAgICAgICAgICAgd2EucmVtb3ZlVXNlcih7IHVzZXJJZDogJzhmMjYwNGNmLTk2Y2QtNDQ5Zi04MmZhLWUzMzE1MzA3MzRlZScgfSk7XG4gICAgICAgICogICAgICAgICAgIH0pO1xuICAgICAgICAqXG4gICAgICAgICogKiogUGFyYW1ldGVycyAqKlxuICAgICAgICAqIEBwYXJhbSB7b2JqZWN0fHN0cmluZ30gYHVzZXJgIFRoZSBgdXNlcklkYCBvZiB0aGUgdXNlciB0byByZW1vdmUgZnJvbSB0aGUgd29ybGQsIG9yIGFuIG9iamVjdCBjb250YWluaW5nIHRoZSBgdXNlcklkYCBmaWVsZC5cbiAgICAgICAgKiBAcGFyYW0ge29iamVjdH0gYG9wdGlvbnNgIChPcHRpb25hbCkgT3B0aW9ucyBvYmplY3QgdG8gb3ZlcnJpZGUgZ2xvYmFsIG9wdGlvbnMuXG4gICAgICAgICovXG4gICAgICAgIHJlbW92ZVVzZXI6IGZ1bmN0aW9uICh1c2VyLCBvcHRpb25zKSB7XG4gICAgICAgICAgICBvcHRpb25zID0gb3B0aW9ucyB8fCB7fTtcblxuICAgICAgICAgICAgaWYgKHR5cGVvZiB1c2VyID09PSAnc3RyaW5nJykge1xuICAgICAgICAgICAgICAgIHVzZXIgPSB7IHVzZXJJZDogdXNlciB9O1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICBpZiAoIXVzZXIudXNlcklkKSB7XG4gICAgICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdZb3UgbmVlZCB0byBwYXNzIGEgdXNlcklkIHRvIHJlbW92ZSBmcm9tIHRoZSB3b3JsZCcpO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICBzZXRJZEZpbHRlck9yVGhyb3dFcnJvcihvcHRpb25zKTtcblxuICAgICAgICAgICAgdmFyIGdldE9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSxcbiAgICAgICAgICAgICAgICBzZXJ2aWNlT3B0aW9ucyxcbiAgICAgICAgICAgICAgICBvcHRpb25zLFxuICAgICAgICAgICAgICAgIHsgdXJsOiB1cmxDb25maWcuZ2V0QVBJUGF0aChhcGlFbmRwb2ludCkgKyBzZXJ2aWNlT3B0aW9ucy5maWx0ZXIgKyAnL3VzZXJzLycgKyB1c2VyLnVzZXJJZCB9XG4gICAgICAgICAgICApO1xuXG4gICAgICAgICAgICByZXR1cm4gaHR0cC5kZWxldGUobnVsbCwgZ2V0T3B0aW9ucyk7XG4gICAgICAgIH0sXG5cbiAgICAgICAgLyoqXG4gICAgICAgICogR2V0cyB0aGUgcnVuIGlkIG9mIGN1cnJlbnQgcnVuIGZvciB0aGUgZ2l2ZW4gd29ybGQuIElmIHRoZSB3b3JsZCBkb2VzIG5vdCBoYXZlIGEgcnVuLCBjcmVhdGVzIGEgbmV3IG9uZSBhbmQgcmV0dXJucyB0aGUgcnVuIGlkLlxuICAgICAgICAqXG4gICAgICAgICogUmVtZW1iZXIgdGhhdCBhIFtydW5dKC4uLy4uL2dsb3NzYXJ5LyNydW4pIGlzIGEgY29sbGVjdGlvbiBvZiBpbnRlcmFjdGlvbnMgd2l0aCBhIHByb2plY3QgYW5kIGl0cyBtb2RlbC4gSW4gdGhlIGNhc2Ugb2YgbXVsdGlwbGF5ZXIgcHJvamVjdHMsIHRoZSBydW4gaXMgc2hhcmVkIGJ5IGFsbCBlbmQgdXNlcnMgaW4gdGhlIHdvcmxkLlxuICAgICAgICAqXG4gICAgICAgICogICoqRXhhbXBsZSoqXG4gICAgICAgICpcbiAgICAgICAgKiAgICAgIHZhciB3YSA9IG5ldyBGLnNlcnZpY2UuV29ybGQoe1xuICAgICAgICAqICAgICAgICAgICBhY2NvdW50OiAnYWNtZS1zaW11bGF0aW9ucycsXG4gICAgICAgICogICAgICAgICAgIHByb2plY3Q6ICdzdXBwbHktY2hhaW4tZ2FtZScsXG4gICAgICAgICogICAgICAgICAgIGdyb3VwOiAndGVhbTEnIH0pO1xuICAgICAgICAqICAgICAgd2EuY3JlYXRlKClcbiAgICAgICAgKiAgICAgICAgICAgLnRoZW4oZnVuY3Rpb24od29ybGQpIHtcbiAgICAgICAgKiAgICAgICAgICAgICAgIHdhLmdldEN1cnJlbnRSdW5JZCh7IG1vZGVsOiAnbW9kZWwucHknIH0pO1xuICAgICAgICAqICAgICAgICAgICB9KTtcbiAgICAgICAgKlxuICAgICAgICAqICoqIFBhcmFtZXRlcnMgKipcbiAgICAgICAgKiBAcGFyYW0ge29iamVjdH0gYG9wdGlvbnNgIChPcHRpb25hbCkgT3B0aW9ucyBvYmplY3QgdG8gb3ZlcnJpZGUgZ2xvYmFsIG9wdGlvbnMuXG4gICAgICAgICogQHBhcmFtIHtvYmplY3R9IGBvcHRpb25zLm1vZGVsYCBUaGUgbW9kZWwgZmlsZSB0byB1c2UgdG8gY3JlYXRlIGEgcnVuIGlmIG5lZWRlZC5cbiAgICAgICAgKi9cbiAgICAgICAgZ2V0Q3VycmVudFJ1bklkOiBmdW5jdGlvbiAob3B0aW9ucykge1xuICAgICAgICAgICAgb3B0aW9ucyA9IG9wdGlvbnMgfHwge307XG5cbiAgICAgICAgICAgIHNldElkRmlsdGVyT3JUaHJvd0Vycm9yKG9wdGlvbnMpO1xuXG4gICAgICAgICAgICB2YXIgZ2V0T3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LFxuICAgICAgICAgICAgICAgIHNlcnZpY2VPcHRpb25zLFxuICAgICAgICAgICAgICAgIG9wdGlvbnMsXG4gICAgICAgICAgICAgICAgeyB1cmw6IHVybENvbmZpZy5nZXRBUElQYXRoKGFwaUVuZHBvaW50KSArIHNlcnZpY2VPcHRpb25zLmZpbHRlciArICcvcnVuJyB9XG4gICAgICAgICAgICApO1xuXG4gICAgICAgICAgICB2YWxpZGF0ZU1vZGVsT3JUaHJvd0Vycm9yKGdldE9wdGlvbnMpO1xuICAgICAgICAgICAgcmV0dXJuIGh0dHAucG9zdChfcGljayhnZXRPcHRpb25zLCAnbW9kZWwnKSwgZ2V0T3B0aW9ucyk7XG4gICAgICAgIH0sXG5cbiAgICAgICAgLyoqXG4gICAgICAgICogR2V0cyB0aGUgY3VycmVudCAobW9zdCByZWNlbnQpIHdvcmxkIGZvciB0aGUgZ2l2ZW4gZW5kIHVzZXIgaW4gdGhlIGdpdmVuIGdyb3VwLiBCcmluZ3MgdGhpcyBtb3N0IHJlY2VudCB3b3JsZCBpbnRvIG1lbW9yeSBpZiBuZWVkZWQuXG4gICAgICAgICpcbiAgICAgICAgKiAgKipFeGFtcGxlKipcbiAgICAgICAgKlxuICAgICAgICAqICAgICAgdmFyIHdhID0gbmV3IEYuc2VydmljZS5Xb3JsZCh7XG4gICAgICAgICogICAgICAgICAgIGFjY291bnQ6ICdhY21lLXNpbXVsYXRpb25zJyxcbiAgICAgICAgKiAgICAgICAgICAgcHJvamVjdDogJ3N1cHBseS1jaGFpbi1nYW1lJyxcbiAgICAgICAgKiAgICAgICAgICAgZ3JvdXA6ICd0ZWFtMScgfSk7XG4gICAgICAgICogICAgICB3YS5nZXRDdXJyZW50V29ybGRGb3JVc2VyKCc4ZjI2MDRjZi05NmNkLTQ0OWYtODJmYS1lMzMxNTMwNzM0ZWUnKVxuICAgICAgICAqICAgICAgICAgICAudGhlbihmdW5jdGlvbih3b3JsZCkge1xuICAgICAgICAqICAgICAgICAgICAgICAgLy8gdXNlIGRhdGEgZnJvbSB3b3JsZFxuICAgICAgICAqICAgICAgICAgICB9KTtcbiAgICAgICAgKlxuICAgICAgICAqICoqIFBhcmFtZXRlcnMgKipcbiAgICAgICAgKiBAcGFyYW0ge3N0cmluZ30gYHVzZXJJZGAgVGhlIGB1c2VySWRgIG9mIHRoZSB1c2VyIHdob3NlIGN1cnJlbnQgKG1vc3QgcmVjZW50KSB3b3JsZCBpcyBiZWluZyByZXRyaWV2ZWQuXG4gICAgICAgICogQHBhcmFtIHtzdHJpbmd9IGBncm91cE5hbWVgIChPcHRpb25hbCkgVGhlIG5hbWUgb2YgdGhlIGdyb3VwLiBJZiBub3QgcHJvdmlkZWQsIGRlZmF1bHRzIHRvIHRoZSBncm91cCB1c2VkIHRvIGNyZWF0ZSB0aGUgc2VydmljZS5cbiAgICAgICAgKi9cbiAgICAgICAgZ2V0Q3VycmVudFdvcmxkRm9yVXNlcjogZnVuY3Rpb24gKHVzZXJJZCwgZ3JvdXBOYW1lKSB7XG4gICAgICAgICAgICB2YXIgZHRkID0gJC5EZWZlcnJlZCgpO1xuICAgICAgICAgICAgdmFyIG1lID0gdGhpcztcbiAgICAgICAgICAgIHRoaXMuZ2V0V29ybGRzRm9yVXNlcih1c2VySWQsIHsgZ3JvdXA6IGdyb3VwTmFtZSB9KVxuICAgICAgICAgICAgICAgIC50aGVuKGZ1bmN0aW9uICh3b3JsZHMpIHtcbiAgICAgICAgICAgICAgICAgICAgLy8gYXNzdW1lIHRoZSBtb3N0IHJlY2VudCB3b3JsZCBhcyB0aGUgJ2FjdGl2ZScgd29ybGRcbiAgICAgICAgICAgICAgICAgICAgd29ybGRzLnNvcnQoZnVuY3Rpb24gKGEsIGIpIHsgcmV0dXJuIG5ldyBEYXRlKGIubGFzdE1vZGlmaWVkKSAtIG5ldyBEYXRlKGEubGFzdE1vZGlmaWVkKTsgfSk7XG4gICAgICAgICAgICAgICAgICAgIHZhciBjdXJyZW50V29ybGQgPSB3b3JsZHNbMF07XG5cbiAgICAgICAgICAgICAgICAgICAgaWYgKGN1cnJlbnRXb3JsZCkge1xuICAgICAgICAgICAgICAgICAgICAgICAgc2VydmljZU9wdGlvbnMuZmlsdGVyID0gIGN1cnJlbnRXb3JsZC5pZDtcbiAgICAgICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgICAgIGR0ZC5yZXNvbHZlKGN1cnJlbnRXb3JsZCwgbWUpO1xuICAgICAgICAgICAgICAgIH0pXG4gICAgICAgICAgICAgICAgLmZhaWwoZHRkLnJlamVjdCk7XG5cbiAgICAgICAgICAgIHJldHVybiBkdGQucHJvbWlzZSgpO1xuICAgICAgICB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAqIERlbGV0ZXMgdGhlIGN1cnJlbnQgcnVuIGZyb20gdGhlIHdvcmxkLlxuICAgICAgICAqXG4gICAgICAgICogKE5vdGUgdGhhdCB0aGUgd29ybGQgaWQgcmVtYWlucyBwYXJ0IG9mIHRoZSBydW4gcmVjb3JkLCBpbmRpY2F0aW5nIHRoYXQgdGhlIHJ1biB3YXMgZm9ybWVybHkgYW4gYWN0aXZlIHJ1biBmb3IgdGhlIHdvcmxkLilcbiAgICAgICAgKlxuICAgICAgICAqICAqKkV4YW1wbGUqKlxuICAgICAgICAqXG4gICAgICAgICogICAgICB2YXIgd2EgPSBuZXcgRi5zZXJ2aWNlLldvcmxkKHtcbiAgICAgICAgKiAgICAgICAgICAgYWNjb3VudDogJ2FjbWUtc2ltdWxhdGlvbnMnLFxuICAgICAgICAqICAgICAgICAgICBwcm9qZWN0OiAnc3VwcGx5LWNoYWluLWdhbWUnLFxuICAgICAgICAqICAgICAgICAgICBncm91cDogJ3RlYW0xJyB9KTtcbiAgICAgICAgKlxuICAgICAgICAqICAgICAgd2EuZGVsZXRlUnVuKCdzYW1wbGUtd29ybGQtaWQnKTtcbiAgICAgICAgKlxuICAgICAgICAqICAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAqIEBwYXJhbSB7c3RyaW5nfSBgd29ybGRJZGAgVGhlIGB3b3JsZElkYCBvZiB0aGUgd29ybGQgZnJvbSB3aGljaCB0aGUgY3VycmVudCBydW4gaXMgYmVpbmcgZGVsZXRlZC5cbiAgICAgICAgKiBAcGFyYW0ge29iamVjdH0gYG9wdGlvbnNgIChPcHRpb25hbCkgT3B0aW9ucyBvYmplY3QgdG8gb3ZlcnJpZGUgZ2xvYmFsIG9wdGlvbnMuXG4gICAgICAgICovXG4gICAgICAgIGRlbGV0ZVJ1bjogZnVuY3Rpb24gKHdvcmxkSWQsIG9wdGlvbnMpIHtcbiAgICAgICAgICAgIG9wdGlvbnMgPSBvcHRpb25zIHx8IHt9O1xuXG4gICAgICAgICAgICBpZiAod29ybGRJZCkge1xuICAgICAgICAgICAgICAgIG9wdGlvbnMuZmlsdGVyID0gd29ybGRJZDtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgc2V0SWRGaWx0ZXJPclRocm93RXJyb3Iob3B0aW9ucyk7XG5cbiAgICAgICAgICAgIHZhciBkZWxldGVPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sXG4gICAgICAgICAgICAgICAgc2VydmljZU9wdGlvbnMsXG4gICAgICAgICAgICAgICAgb3B0aW9ucyxcbiAgICAgICAgICAgICAgICB7IHVybDogdXJsQ29uZmlnLmdldEFQSVBhdGgoYXBpRW5kcG9pbnQpICsgc2VydmljZU9wdGlvbnMuZmlsdGVyICsgJy9ydW4nIH1cbiAgICAgICAgICAgICk7XG5cbiAgICAgICAgICAgIHJldHVybiBodHRwLmRlbGV0ZShudWxsLCBkZWxldGVPcHRpb25zKTtcbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgKiBDcmVhdGVzIGEgbmV3IHJ1biBmb3IgdGhlIHdvcmxkLlxuICAgICAgICAqXG4gICAgICAgICogICoqRXhhbXBsZSoqXG4gICAgICAgICpcbiAgICAgICAgKiAgICAgIHZhciB3YSA9IG5ldyBGLnNlcnZpY2UuV29ybGQoe1xuICAgICAgICAqICAgICAgICAgICBhY2NvdW50OiAnYWNtZS1zaW11bGF0aW9ucycsXG4gICAgICAgICogICAgICAgICAgIHByb2plY3Q6ICdzdXBwbHktY2hhaW4tZ2FtZScsXG4gICAgICAgICogICAgICAgICAgIGdyb3VwOiAndGVhbTEnIH0pO1xuICAgICAgICAqXG4gICAgICAgICogICAgICB3YS5nZXRDdXJyZW50V29ybGRGb3JVc2VyKCc4ZjI2MDRjZi05NmNkLTQ0OWYtODJmYS1lMzMxNTMwNzM0ZWUnKVxuICAgICAgICAqICAgICAgICAgICAudGhlbihmdW5jdGlvbiAod29ybGQpIHtcbiAgICAgICAgKiAgICAgICAgICAgICAgICAgICB3YS5uZXdSdW5Gb3JXb3JsZCh3b3JsZC5pZCk7XG4gICAgICAgICogICAgICAgICAgIH0pO1xuICAgICAgICAqXG4gICAgICAgICogICoqUGFyYW1ldGVycyoqXG4gICAgICAgICogQHBhcmFtIHtzdHJpbmd9IGB3b3JsZElkYCB3b3JsZElkIGluIHdoaWNoIHdlIGNyZWF0ZSB0aGUgbmV3IHJ1bi5cbiAgICAgICAgKiBAcGFyYW0ge29iamVjdH0gYG9wdGlvbnNgIChPcHRpb25hbCkgT3B0aW9ucyBvYmplY3QgdG8gb3ZlcnJpZGUgZ2xvYmFsIG9wdGlvbnMuXG4gICAgICAgICogQHBhcmFtIHtvYmplY3R9IGBvcHRpb25zLm1vZGVsYCBUaGUgbW9kZWwgZmlsZSB0byB1c2UgdG8gY3JlYXRlIGEgcnVuIGlmIG5lZWRlZC5cbiAgICAgICAgKi9cbiAgICAgICAgbmV3UnVuRm9yV29ybGQ6IGZ1bmN0aW9uICh3b3JsZElkLCBvcHRpb25zKSB7XG4gICAgICAgICAgICB2YXIgY3VycmVudFJ1bk9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSxcbiAgICAgICAgICAgICAgICBvcHRpb25zLFxuICAgICAgICAgICAgICAgIHsgZmlsdGVyOiB3b3JsZElkIHx8IHNlcnZpY2VPcHRpb25zLmZpbHRlciB9XG4gICAgICAgICAgICApO1xuICAgICAgICAgICAgdmFyIF90aGlzID0gdGhpcztcblxuICAgICAgICAgICAgdmFsaWRhdGVNb2RlbE9yVGhyb3dFcnJvcihjdXJyZW50UnVuT3B0aW9ucyk7XG5cbiAgICAgICAgICAgIHJldHVybiB0aGlzLmRlbGV0ZVJ1bih3b3JsZElkLCBvcHRpb25zKVxuICAgICAgICAgICAgICAgIC50aGVuKGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIF90aGlzLmdldEN1cnJlbnRSdW5JZChjdXJyZW50UnVuT3B0aW9ucyk7XG4gICAgICAgICAgICAgICAgfSk7XG4gICAgICAgIH0sXG5cbiAgICAgICAgLyoqXG4gICAgICAgICogQXNzaWducyBlbmQgdXNlcnMgdG8gd29ybGRzLCBjcmVhdGluZyBuZXcgd29ybGRzIGFzIGFwcHJvcHJpYXRlLCBhdXRvbWF0aWNhbGx5LiBBc3NpZ25zIGFsbCBlbmQgdXNlcnMgaW4gdGhlIGdyb3VwLCBhbmQgY3JlYXRlcyBuZXcgd29ybGRzIGFzIG5lZWRlZCBiYXNlZCBvbiB0aGUgcHJvamVjdC1sZXZlbCB3b3JsZCBjb25maWd1cmF0aW9uIChyb2xlcywgb3B0aW9uYWwgcm9sZXMsIGFuZCBtaW5pbXVtIGVuZCB1c2VycyBwZXIgd29ybGQpLlxuICAgICAgICAqXG4gICAgICAgICogKipFeGFtcGxlKipcbiAgICAgICAgKlxuICAgICAgICAqICAgICAgdmFyIHdhID0gbmV3IEYuc2VydmljZS5Xb3JsZCh7XG4gICAgICAgICogICAgICAgICAgIGFjY291bnQ6ICdhY21lLXNpbXVsYXRpb25zJyxcbiAgICAgICAgKiAgICAgICAgICAgcHJvamVjdDogJ3N1cHBseS1jaGFpbi1nYW1lJyxcbiAgICAgICAgKiAgICAgICAgICAgZ3JvdXA6ICd0ZWFtMScgfSk7XG4gICAgICAgICpcbiAgICAgICAgKiAgICAgIHdhLmF1dG9Bc3NpZ24oKTtcbiAgICAgICAgKlxuICAgICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICAgICogQHBhcmFtIHtvYmplY3R9IGBvcHRpb25zYCAoT3B0aW9uYWwpIE9wdGlvbnMgb2JqZWN0IHRvIG92ZXJyaWRlIGdsb2JhbCBvcHRpb25zLlxuICAgICAgICAqXG4gICAgICAgICovXG4gICAgICAgIGF1dG9Bc3NpZ246IGZ1bmN0aW9uIChvcHRpb25zKSB7XG4gICAgICAgICAgICBvcHRpb25zID0gb3B0aW9ucyB8fCB7fTtcblxuICAgICAgICAgICAgdmFyIG9wdCA9ICQuZXh0ZW5kKHRydWUsIHt9LFxuICAgICAgICAgICAgICAgIHNlcnZpY2VPcHRpb25zLFxuICAgICAgICAgICAgICAgIG9wdGlvbnMsXG4gICAgICAgICAgICAgICAgeyB1cmw6IHVybENvbmZpZy5nZXRBUElQYXRoKGFzc2lnbm1lbnRFbmRwb2ludCkgfVxuICAgICAgICAgICAgKTtcblxuICAgICAgICAgICAgdmFyIHBhcmFtcyA9IHtcbiAgICAgICAgICAgICAgICBhY2NvdW50OiBvcHQuYWNjb3VudCxcbiAgICAgICAgICAgICAgICBwcm9qZWN0OiBvcHQucHJvamVjdCxcbiAgICAgICAgICAgICAgICBncm91cDogb3B0Lmdyb3VwXG4gICAgICAgICAgICB9O1xuXG4gICAgICAgICAgICBpZiAob3B0Lm1heFVzZXJzKSB7XG4gICAgICAgICAgICAgICAgcGFyYW1zLm1heFVzZXJzID0gb3B0Lm1heFVzZXJzO1xuICAgICAgICB9XG5cbiAgICAgICAgICAgIHJldHVybiBodHRwLnBvc3QocGFyYW1zLCBvcHQpO1xuICAgICAgICB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAqIEdldHMgdGhlIHByb2plY3QncyB3b3JsZCBjb25maWd1cmF0aW9uLlxuICAgICAgICAqXG4gICAgICAgICogVHlwaWNhbGx5LCBldmVyeSBpbnRlcmFjdGlvbiB3aXRoIHlvdXIgcHJvamVjdCB1c2VzIHRoZSBzYW1lIGNvbmZpZ3VyYXRpb24gb2YgZWFjaCB3b3JsZC4gRm9yIGV4YW1wbGUsIGVhY2ggd29ybGQgaW4geW91ciBwcm9qZWN0IHByb2JhYmx5IGhhcyB0aGUgc2FtZSByb2xlcyBmb3IgZW5kIHVzZXJzLiBBbmQgeW91ciBwcm9qZWN0IGlzIHByb2JhYmx5IGVpdGhlciBjb25maWd1cmVkIHNvIHRoYXQgYWxsIGVuZCB1c2VycyBzaGFyZSB0aGUgc2FtZSB3b3JsZCAoYW5kIHJ1biksIG9yIHNtYWxsZXIgc2V0cyBvZiBlbmQgdXNlcnMgc2hhcmUgd29ybGRzIOKAlCBidXQgbm90IGJvdGguXG4gICAgICAgICpcbiAgICAgICAgKiAoVGhlIFtNdWx0aXBsYXllciBQcm9qZWN0IFJFU1QgQVBJXSguLi8uLi8uLi9yZXN0X2FwaXMvbXVsdGlwbGF5ZXIvbXVsdGlwbGF5ZXJfcHJvamVjdC8pIGFsbG93cyB5b3UgdG8gc2V0IHRoZXNlIHByb2plY3QtbGV2ZWwgd29ybGQgY29uZmlndXJhdGlvbnMuIFRoZSBXb3JsZCBBZGFwdGVyIHNpbXBseSByZXRyaWV2ZXMgdGhlbSwgZm9yIGV4YW1wbGUgc28gdGhleSBjYW4gYmUgdXNlZCBpbiBhdXRvLWFzc2lnbm1lbnQgb2YgZW5kIHVzZXJzIHRvIHdvcmxkcy4pXG4gICAgICAgICpcbiAgICAgICAgKiAqKkV4YW1wbGUqKlxuICAgICAgICAqXG4gICAgICAgICogICAgICB2YXIgd2EgPSBuZXcgRi5zZXJ2aWNlLldvcmxkKHtcbiAgICAgICAgKiAgICAgICAgICAgYWNjb3VudDogJ2FjbWUtc2ltdWxhdGlvbnMnLFxuICAgICAgICAqICAgICAgICAgICBwcm9qZWN0OiAnc3VwcGx5LWNoYWluLWdhbWUnLFxuICAgICAgICAqICAgICAgICAgICBncm91cDogJ3RlYW0xJyB9KTtcbiAgICAgICAgKlxuICAgICAgICAqICAgICAgd2EuZ2V0UHJvamVjdFNldHRpbmdzKClcbiAgICAgICAgKiAgICAgICAgICAgLnRoZW4oZnVuY3Rpb24oc2V0dGluZ3MpIHtcbiAgICAgICAgKiAgICAgICAgICAgICAgIGNvbnNvbGUubG9nKHNldHRpbmdzLnJvbGVzKTtcbiAgICAgICAgKiAgICAgICAgICAgICAgIGNvbnNvbGUubG9nKHNldHRpbmdzLm9wdGlvbmFsUm9sZXMpO1xuICAgICAgICAqICAgICAgICAgICB9KTtcbiAgICAgICAgKlxuICAgICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICAgICogQHBhcmFtIHtvYmplY3R9IGBvcHRpb25zYCAoT3B0aW9uYWwpIE9wdGlvbnMgb2JqZWN0IHRvIG92ZXJyaWRlIGdsb2JhbCBvcHRpb25zLlxuICAgICAgICAqL1xuICAgICAgICBnZXRQcm9qZWN0U2V0dGluZ3M6IGZ1bmN0aW9uIChvcHRpb25zKSB7XG4gICAgICAgICAgICBvcHRpb25zID0gb3B0aW9ucyB8fCB7fTtcblxuICAgICAgICAgICAgdmFyIG9wdCA9ICQuZXh0ZW5kKHRydWUsIHt9LFxuICAgICAgICAgICAgICAgIHNlcnZpY2VPcHRpb25zLFxuICAgICAgICAgICAgICAgIG9wdGlvbnMsXG4gICAgICAgICAgICAgICAgeyB1cmw6IHVybENvbmZpZy5nZXRBUElQYXRoKHByb2plY3RFbmRwb2ludCkgfVxuICAgICAgICAgICAgKTtcblxuICAgICAgICAgICAgb3B0LnVybCArPSBbb3B0LmFjY291bnQsIG9wdC5wcm9qZWN0XS5qb2luKCcvJyk7XG5cbiAgICAgICAgICAgIHJldHVybiBodHRwLmdldChudWxsLCBvcHQpO1xuICAgICAgICB9XG5cbiAgICB9O1xuXG4gICAgJC5leHRlbmQodGhpcywgcHVibGljQVBJKTtcbn07XG4iLCIvKipcbiAqIEBjbGFzcyBDb29raWUgU3RvcmFnZSBTZXJ2aWNlXG4gKlxuICogQGV4YW1wbGVcbiAqICAgICAgdmFyIHBlb3BsZSA9IHJlcXVpcmUoJ2Nvb2tpZS1zdG9yZScpKHsgcm9vdDogJ3Blb3BsZScgfSk7XG4gICAgICAgIHBlb3BsZVxuICAgICAgICAgICAgLnNhdmUoe2xhc3ROYW1lOiAnc21pdGgnIH0pXG5cbiAqL1xuXG5cbid1c2Ugc3RyaWN0JztcblxuLy8gVGhpbiBkb2N1bWVudC5jb29raWUgd3JhcHBlciB0byBhbGxvdyB1bml0IHRlc3RpbmdcbnZhciBDb29raWUgPSBmdW5jdGlvbiAoKSB7XG4gICAgdGhpcy5nZXQgPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHJldHVybiBkb2N1bWVudC5jb29raWU7XG4gICAgfTtcblxuICAgIHRoaXMuc2V0ID0gZnVuY3Rpb24gKG5ld0Nvb2tpZSkge1xuICAgICAgICBkb2N1bWVudC5jb29raWUgPSBuZXdDb29raWU7XG4gICAgfTtcbn07XG5cbm1vZHVsZS5leHBvcnRzID0gZnVuY3Rpb24gKGNvbmZpZykge1xuICAgIHZhciBob3N0ID0gd2luZG93LmxvY2F0aW9uLmhvc3RuYW1lO1xuICAgIHZhciB2YWxpZEhvc3QgPSBob3N0LnNwbGl0KCcuJykubGVuZ3RoID4gMTtcbiAgICB2YXIgZG9tYWluID0gdmFsaWRIb3N0ID8gJy4nICsgaG9zdCA6IG51bGw7XG5cbiAgICB2YXIgZGVmYXVsdHMgPSB7XG4gICAgICAgIC8qKlxuICAgICAgICAgKiBOYW1lIG9mIGNvbGxlY3Rpb25cbiAgICAgICAgICogQHR5cGUgeyBzdHJpbmd9XG4gICAgICAgICAqL1xuICAgICAgICByb290OiAnLycsXG5cbiAgICAgICAgZG9tYWluOiBkb21haW4sXG4gICAgICAgIGNvb2tpZTogbmV3IENvb2tpZSgpXG4gICAgfTtcbiAgICB0aGlzLnNlcnZpY2VPcHRpb25zID0gJC5leHRlbmQoe30sIGRlZmF1bHRzLCBjb25maWcpO1xuXG4gICAgdmFyIHB1YmxpY0FQSSA9IHtcbiAgICAgICAgLy8gKiBUQkRcbiAgICAgICAgLy8gICogUXVlcnkgY29sbGVjdGlvbjsgdXNlcyBNb25nb0RCIHN5bnRheFxuICAgICAgICAvLyAgKiBAc2VlICA8VEJEOiBEYXRhIEFQSSBVUkw+XG4gICAgICAgIC8vICAqXG4gICAgICAgIC8vICAqIEBwYXJhbSB7IHN0cmluZ30gcXMgUXVlcnkgRmlsdGVyXG4gICAgICAgIC8vICAqIEBwYXJhbSB7IHN0cmluZ30gbGltaXRlcnMgQHNlZSA8VEJEOiB1cmwgZm9yIGxpbWl0cywgcGFnaW5nIGV0Yz5cbiAgICAgICAgLy8gICpcbiAgICAgICAgLy8gICogQGV4YW1wbGVcbiAgICAgICAgLy8gICogICAgIGNzLnF1ZXJ5KFxuICAgICAgICAvLyAgKiAgICAgIHsgbmFtZTogJ0pvaG4nLCBjbGFzc05hbWU6ICdDU0MxMDEnIH0sXG4gICAgICAgIC8vICAqICAgICAge2xpbWl0OiAxMH1cbiAgICAgICAgLy8gICogICAgIClcblxuICAgICAgICAvLyBxdWVyeTogZnVuY3Rpb24gKHFzLCBsaW1pdGVycykge1xuXG4gICAgICAgIC8vIH0sXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIFNhdmUgY29va2llIHZhbHVlXG4gICAgICAgICAqIEBwYXJhbSAgeyBzdHJpbmd8T2JqZWN0fSBrZXkgICBJZiBnaXZlbiBhIGtleSBzYXZlIHZhbHVlcyB1bmRlciBpdCwgaWYgZ2l2ZW4gYW4gb2JqZWN0IGRpcmVjdGx5LCBzYXZlIHRvIHRvcC1sZXZlbCBhcGlcbiAgICAgICAgICogQHBhcmFtICB7T2JqZWN0fSB2YWx1ZSAoT3B0aW9uYWwpXG4gICAgICAgICAqIEBwYXJhbSB7T2JqZWN0fSBvcHRpb25zIE92ZXJyaWRlcyBmb3Igc2VydmljZSBvcHRpb25zXG4gICAgICAgICAqXG4gICAgICAgICAqIEByZXR1cm4geyp9IFRoZSBzYXZlZCB2YWx1ZVxuICAgICAgICAgKlxuICAgICAgICAgKiBAZXhhbXBsZVxuICAgICAgICAgKiAgICAgY3Muc2V0KCdwZXJzb24nLCB7IGZpcnN0TmFtZTogJ2pvaG4nLCBsYXN0TmFtZTogJ3NtaXRoJyB9KTtcbiAgICAgICAgICogICAgIGNzLnNldCh7IG5hbWU6J3NtaXRoJywgYWdlOiczMicgfSk7XG4gICAgICAgICAqL1xuICAgICAgICBzZXQ6IGZ1bmN0aW9uIChrZXksIHZhbHVlLCBvcHRpb25zKSB7XG4gICAgICAgICAgICB2YXIgc2V0T3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LCB0aGlzLnNlcnZpY2VPcHRpb25zLCBvcHRpb25zKTtcblxuICAgICAgICAgICAgdmFyIGRvbWFpbiA9IHNldE9wdGlvbnMuZG9tYWluO1xuICAgICAgICAgICAgdmFyIHBhdGggPSBzZXRPcHRpb25zLnJvb3Q7XG4gICAgICAgICAgICB2YXIgY29va2llID0gc2V0T3B0aW9ucy5jb29raWU7XG5cbiAgICAgICAgICAgIGNvb2tpZS5zZXQoZW5jb2RlVVJJQ29tcG9uZW50KGtleSkgKyAnPScgK1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBlbmNvZGVVUklDb21wb25lbnQodmFsdWUpICtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKGRvbWFpbiA/ICc7IGRvbWFpbj0nICsgZG9tYWluIDogJycpICtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKHBhdGggPyAnOyBwYXRoPScgKyBwYXRoIDogJycpXG4gICAgICAgICAgICApO1xuXG4gICAgICAgICAgICByZXR1cm4gdmFsdWU7XG4gICAgICAgIH0sXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIExvYWQgY29va2llIHZhbHVlXG4gICAgICAgICAqIEBwYXJhbSAgeyBzdHJpbmd8T2JqZWN0fSBrZXkgICBJZiBnaXZlbiBhIGtleSBzYXZlIHZhbHVlcyB1bmRlciBpdCwgaWYgZ2l2ZW4gYW4gb2JqZWN0IGRpcmVjdGx5LCBzYXZlIHRvIHRvcC1sZXZlbCBhcGlcbiAgICAgICAgICogQHJldHVybiB7Kn0gVGhlIHZhbHVlIHN0b3JlZFxuICAgICAgICAgKlxuICAgICAgICAgKiBAZXhhbXBsZVxuICAgICAgICAgKiAgICAgY3MuZ2V0KCdwZXJzb24nKTtcbiAgICAgICAgICovXG4gICAgICAgIGdldDogZnVuY3Rpb24gKGtleSkge1xuICAgICAgICAgICAgdmFyIGNvb2tpZSA9IHRoaXMuc2VydmljZU9wdGlvbnMuY29va2llO1xuICAgICAgICAgICAgdmFyIGNvb2tpZVJlZyA9IG5ldyBSZWdFeHAoJyg/Ol58OylcXFxccyonICsgZW5jb2RlVVJJQ29tcG9uZW50KGtleSkucmVwbGFjZSgvW1xcLVxcLlxcK1xcKl0vZywgJ1xcXFwkJicpICsgJ1xcXFxzKlxcXFw9XFxcXHMqKFteO10qKS4qJCcpO1xuICAgICAgICAgICAgdmFyIHJlcyA9IGNvb2tpZVJlZy5leGVjKGNvb2tpZS5nZXQoKSk7XG4gICAgICAgICAgICB2YXIgdmFsID0gcmVzID8gZGVjb2RlVVJJQ29tcG9uZW50KHJlc1sxXSkgOiBudWxsO1xuICAgICAgICAgICAgcmV0dXJuIHZhbDtcbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgICogUmVtb3ZlcyBrZXkgZnJvbSBjb2xsZWN0aW9uXG4gICAgICAgICAqIEBwYXJhbSB7IHN0cmluZ30ga2V5IGtleSB0byByZW1vdmVcbiAgICAgICAgICogQHJldHVybiB7IHN0cmluZ30ga2V5IFRoZSBrZXkgcmVtb3ZlZFxuICAgICAgICAgKlxuICAgICAgICAgKiBAZXhhbXBsZVxuICAgICAgICAgKiAgICAgY3MucmVtb3ZlKCdwZXJzb24nKTtcbiAgICAgICAgICovXG4gICAgICAgIHJlbW92ZTogZnVuY3Rpb24gKGtleSwgb3B0aW9ucykge1xuICAgICAgICAgICAgdmFyIHJlbU9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSwgdGhpcy5zZXJ2aWNlT3B0aW9ucywgb3B0aW9ucyk7XG5cbiAgICAgICAgICAgIHZhciBkb21haW4gPSByZW1PcHRpb25zLmRvbWFpbjtcbiAgICAgICAgICAgIHZhciBwYXRoID0gcmVtT3B0aW9ucy5yb290O1xuICAgICAgICAgICAgdmFyIGNvb2tpZSA9IHJlbU9wdGlvbnMuY29va2llO1xuXG4gICAgICAgICAgICBjb29raWUuc2V0KGVuY29kZVVSSUNvbXBvbmVudChrZXkpICtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAnPTsgZXhwaXJlcz1UaHUsIDAxIEphbiAxOTcwIDAwOjAwOjAwIEdNVCcgK1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIChkb21haW4gPyAnOyBkb21haW49JyArIGRvbWFpbiA6ICcnKSArXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgKHBhdGggPyAnOyBwYXRoPScgKyBwYXRoIDogJycpXG4gICAgICAgICAgICApO1xuICAgICAgICAgICAgcmV0dXJuIGtleTtcbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgICogUmVtb3ZlcyBjb2xsZWN0aW9uIGJlaW5nIHJlZmVyZW5jZWRcbiAgICAgICAgICogQHJldHVybiB7IGFycmF5fSBrZXlzIEFsbCB0aGUga2V5cyByZW1vdmVkXG4gICAgICAgICAqL1xuICAgICAgICBkZXN0cm95OiBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICB2YXIgY29va2llID0gdGhpcy5zZXJ2aWNlT3B0aW9ucy5jb29raWU7XG4gICAgICAgICAgICB2YXIgYUtleXMgPSBjb29raWUuZ2V0KCkucmVwbGFjZSgvKCg/Ol58XFxzKjspW15cXD1dKykoPz07fCQpfF5cXHMqfFxccyooPzpcXD1bXjtdKik/KD86XFwxfCQpL2csICcnKS5zcGxpdCgvXFxzKig/OlxcPVteO10qKT87XFxzKi8pO1xuICAgICAgICAgICAgZm9yICh2YXIgbklkeCA9IDA7IG5JZHggPCBhS2V5cy5sZW5ndGg7IG5JZHgrKykge1xuICAgICAgICAgICAgICAgIHZhciBjb29raWVLZXkgPSBkZWNvZGVVUklDb21wb25lbnQoYUtleXNbbklkeF0pO1xuICAgICAgICAgICAgICAgIHRoaXMucmVtb3ZlKGNvb2tpZUtleSk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICByZXR1cm4gYUtleXM7XG4gICAgICAgIH1cbiAgICB9O1xuXG4gICAgJC5leHRlbmQodGhpcywgcHVibGljQVBJKTtcbn07XG4iLCIndXNlIHN0cmljdCc7XG5cbnZhciBrZXlOYW1lcyA9IHJlcXVpcmUoJy4uL21hbmFnZXJzL2tleS1uYW1lcycpO1xudmFyIFN0b3JhZ2VGYWN0b3J5ID0gcmVxdWlyZSgnLi9zdG9yZS1mYWN0b3J5Jyk7XG52YXIgb3B0aW9uVXRpbHMgPSByZXF1aXJlKCcuLi91dGlsL29wdGlvbi11dGlscycpO1xuXG52YXIgRVBJX1NFU1NJT05fS0VZID0ga2V5TmFtZXMuRVBJX1NFU1NJT05fS0VZO1xudmFyIGRlZmF1bHRzID0ge1xuICAgIC8qKlxuICAgICAqIFdoZXJlIHRvIHN0b3JlIHVzZXIgYWNjZXNzIHRva2VucyBmb3IgdGVtcG9yYXJ5IGFjY2Vzcy4gRGVmYXVsdHMgdG8gc3RvcmluZyBpbiBhIGNvb2tpZSBpbiB0aGUgYnJvd3Nlci5cbiAgICAgKiBAdHlwZSB7c3RyaW5nfVxuICAgICAqL1xuICAgIHN0b3JlOiB7IHN5bmNocm9ub3VzOiB0cnVlIH1cbn07XG5cbnZhciBTZXNzaW9uTWFuYWdlciA9IGZ1bmN0aW9uIChtYW5hZ2VyT3B0aW9ucykge1xuICAgIG1hbmFnZXJPcHRpb25zID0gbWFuYWdlck9wdGlvbnMgfHwge307XG4gICAgZnVuY3Rpb24gZ2V0QmFzZU9wdGlvbnMob3ZlcnJpZGVzKSB7XG4gICAgICAgIG92ZXJyaWRlcyA9IG92ZXJyaWRlcyB8fCB7fTtcbiAgICAgICAgdmFyIGxpYk9wdGlvbnMgPSBvcHRpb25VdGlscy5nZXRPcHRpb25zKCk7XG4gICAgICAgIHZhciBmaW5hbE9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSwgZGVmYXVsdHMsIGxpYk9wdGlvbnMsIG1hbmFnZXJPcHRpb25zLCBvdmVycmlkZXMpO1xuICAgICAgICByZXR1cm4gZmluYWxPcHRpb25zO1xuICAgIH1cblxuICAgIGZ1bmN0aW9uIGdldFN0b3JlKG92ZXJyaWRlcykge1xuICAgICAgICB2YXIgYmFzZU9wdGlvbnMgPSBnZXRCYXNlT3B0aW9ucyhvdmVycmlkZXMpO1xuICAgICAgICB2YXIgc3RvcmVPcHRzID0gYmFzZU9wdGlvbnMuc3RvcmUgfHwge307XG4gICAgICAgIGlmIChzdG9yZU9wdHMucm9vdCA9PT0gdW5kZWZpbmVkICYmIGJhc2VPcHRpb25zLmFjY291bnQgJiYgYmFzZU9wdGlvbnMucHJvamVjdCAmJiAhYmFzZU9wdGlvbnMuaXNMb2NhbCkge1xuICAgICAgICAgICAgc3RvcmVPcHRzLnJvb3QgPSAnL2FwcC8nICsgYmFzZU9wdGlvbnMuYWNjb3VudCArICcvJyArIGJhc2VPcHRpb25zLnByb2plY3Q7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIG5ldyBTdG9yYWdlRmFjdG9yeShzdG9yZU9wdHMpO1xuICAgIH1cblxuICAgIHZhciBwdWJsaWNBUEkgPSB7XG4gICAgICAgIHNhdmVTZXNzaW9uOiBmdW5jdGlvbiAodXNlckluZm8sIG9wdGlvbnMpIHtcbiAgICAgICAgICAgIHZhciBzZXJpYWxpemVkID0gSlNPTi5zdHJpbmdpZnkodXNlckluZm8pO1xuICAgICAgICAgICAgZ2V0U3RvcmUob3B0aW9ucykuc2V0KEVQSV9TRVNTSU9OX0tFWSwgc2VyaWFsaXplZCk7XG4gICAgICAgIH0sXG4gICAgICAgIGdldFNlc3Npb246IGZ1bmN0aW9uIChvcHRpb25zKSB7XG4gICAgICAgICAgICAvLyB2YXIgc2Vzc2lvbiA9IGdldFN0b3JlKG9wdGlvbnMpLmdldChFUElfU0VTU0lPTl9LRVkpIHx8ICd7fSc7XG4gICAgICAgICAgICAvLyByZXR1cm4gSlNPTi5wYXJzZShzZXNzaW9uKTtcbiAgICAgICAgICAgIHZhciBzdG9yZSA9IGdldFN0b3JlKG9wdGlvbnMpO1xuICAgICAgICAgICAgdmFyIGZpbmFsT3B0cyA9IHN0b3JlLnNlcnZpY2VPcHRpb25zO1xuICAgICAgICAgICAgdmFyIHNlcmlhbGl6ZWQgPSBzdG9yZS5nZXQoRVBJX1NFU1NJT05fS0VZKSB8fCAne30nO1xuICAgICAgICAgICAgdmFyIHNlc3Npb24gPSBKU09OLnBhcnNlKHNlcmlhbGl6ZWQpO1xuICAgICAgICAgICAgLy8gSWYgdGhlIHVybCBjb250YWlucyB0aGUgcHJvamVjdCBhbmQgYWNjb3VudFxuICAgICAgICAgICAgLy8gdmFsaWRhdGUgdGhlIGFjY291bnQgYW5kIHByb2plY3QgaW4gdGhlIHNlc3Npb25cbiAgICAgICAgICAgIC8vIGFuZCBvdmVycmlkZSBwcm9qZWN0LCBncm91cE5hbWUsIGdyb3VwSWQgYW5kIGlzRmFjXG4gICAgICAgICAgICAvLyBPdGhlcndpc2UgKGkuZS4gbG9jYWxob3N0KSB1c2UgdGhlIHNhdmVkIHNlc3Npb24gdmFsdWVzXG4gICAgICAgICAgICB2YXIgYWNjb3VudCA9IGZpbmFsT3B0cy5hY2NvdW50O1xuICAgICAgICAgICAgdmFyIHByb2plY3QgPSBmaW5hbE9wdHMucHJvamVjdDtcbiAgICAgICAgICAgIGlmIChhY2NvdW50ICYmIHNlc3Npb24uYWNjb3VudCAhPT0gYWNjb3VudCkge1xuICAgICAgICAgICAgICAgIC8vIFRoaXMgbWVhbnMgdGhhdCB0aGUgdG9rZW4gd2FzIG5vdCB1c2VkIHRvIGxvZ2luIHRvIHRoZSBzYW1lIGFjY291bnRcbiAgICAgICAgICAgICAgICByZXR1cm4ge307XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBpZiAoc2Vzc2lvbi5ncm91cHMgJiYgYWNjb3VudCAmJiBwcm9qZWN0KSB7XG4gICAgICAgICAgICAgICAgdmFyIGdyb3VwID0gc2Vzc2lvbi5ncm91cHNbcHJvamVjdF0gfHwgeyBncm91cElkOiAnJywgZ3JvdXBOYW1lOiAnJywgaXNGYWM6IGZhbHNlIH07XG4gICAgICAgICAgICAgICAgJC5leHRlbmQoc2Vzc2lvbiwgeyBwcm9qZWN0OiBwcm9qZWN0IH0sIGdyb3VwKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHJldHVybiBzZXNzaW9uO1xuICAgICAgICB9LFxuICAgICAgICByZW1vdmVTZXNzaW9uOiBmdW5jdGlvbiAob3B0aW9ucykge1xuICAgICAgICAgICAgdmFyIHN0b3JlID0gZ2V0U3RvcmUob3B0aW9ucyk7XG4gICAgICAgICAgICBPYmplY3Qua2V5cyhrZXlOYW1lcykuZm9yRWFjaChmdW5jdGlvbiAoY29va2llS2V5KSB7XG4gICAgICAgICAgICAgICAgdmFyIGNvb2tpZU5hbWUgPSBrZXlOYW1lc1tjb29raWVLZXldO1xuICAgICAgICAgICAgICAgIHN0b3JlLnJlbW92ZShjb29raWVOYW1lKTtcbiAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgcmV0dXJuIHRydWU7XG4gICAgICAgIH0sXG4gICAgICAgIGdldFN0b3JlOiBmdW5jdGlvbiAob3B0aW9ucykge1xuICAgICAgICAgICAgcmV0dXJuIGdldFN0b3JlKG9wdGlvbnMpO1xuICAgICAgICB9LFxuXG4gICAgICAgIGdldE1lcmdlZE9wdGlvbnM6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIHZhciBhcmdzID0gQXJyYXkucHJvdG90eXBlLnNsaWNlLmNhbGwoYXJndW1lbnRzKTtcbiAgICAgICAgICAgIHZhciBvdmVycmlkZXMgPSAkLmV4dGVuZC5hcHBseSgkLCBbdHJ1ZSwge31dLmNvbmNhdChhcmdzKSk7XG4gICAgICAgICAgICB2YXIgYmFzZU9wdGlvbnMgPSBnZXRCYXNlT3B0aW9ucyhvdmVycmlkZXMpO1xuICAgICAgICAgICAgdmFyIHNlc3Npb24gPSB0aGlzLmdldFNlc3Npb24ob3ZlcnJpZGVzKTtcblxuICAgICAgICAgICAgdmFyIHNlc3Npb25EZWZhdWx0cyA9IHtcbiAgICAgICAgICAgICAgICAvKipcbiAgICAgICAgICAgICAgICAgKiBGb3IgcHJvamVjdHMgdGhhdCByZXF1aXJlIGF1dGhlbnRpY2F0aW9uLCBwYXNzIGluIHRoZSB1c2VyIGFjY2VzcyB0b2tlbiAoZGVmYXVsdHMgdG8gZW1wdHkgc3RyaW5nKS4gSWYgdGhlIHVzZXIgaXMgYWxyZWFkeSBsb2dnZWQgaW4gdG8gRXBpY2VudGVyLCB0aGUgdXNlciBhY2Nlc3MgdG9rZW4gaXMgYWxyZWFkeSBzZXQgaW4gYSBjb29raWUgYW5kIGF1dG9tYXRpY2FsbHkgbG9hZGVkIGZyb20gdGhlcmUuIChTZWUgW21vcmUgYmFja2dyb3VuZCBvbiBhY2Nlc3MgdG9rZW5zXSguLi8uLi8uLi9wcm9qZWN0X2FjY2Vzcy8pKS5cbiAgICAgICAgICAgICAgICAgKiBAc2VlIFtBdXRoZW50aWNhdGlvbiBBUEkgU2VydmljZV0oLi4vYXV0aC1hcGktc2VydmljZS8pIGZvciBnZXR0aW5nIHRva2Vucy5cbiAgICAgICAgICAgICAgICAgKiBAdHlwZSB7U3RyaW5nfVxuICAgICAgICAgICAgICAgICAqL1xuICAgICAgICAgICAgICAgIC8vanNoaW50IGNhbWVsY2FzZTogZmFsc2VcbiAgICAgICAgICAgICAgICAvL2pzY3M6ZGlzYWJsZVxuICAgICAgICAgICAgICAgIHRva2VuOiBzZXNzaW9uLmF1dGhfdG9rZW4sXG4gICAgICAgICAgICAgICAgLyoqXG4gICAgICAgICAgICAgICAgICogVGhlIGdyb3VwIG5hbWUuIElmIGxlZnQgdW5kZWZpbmVkLCB0YWtlbiBmcm9tIHRoZSBjb29raWUgc2Vzc2lvbi5cbiAgICAgICAgICAgICAgICAgKiBAdHlwZSB7U3RyaW5nfVxuICAgICAgICAgICAgICAgICAqL1xuICAgICAgICAgICAgICAgIGdyb3VwOiBzZXNzaW9uLmdyb3VwTmFtZSxcbiAgICAgICAgICAgICAgICAvKipcbiAgICAgICAgICAgICAgICAgKiBUaGUgZ3JvdXAgaWQuIElmIGxlZnQgdW5kZWZpbmVkLCB0YWtlbiBmcm9tIHRoZSBjb29raWUgc2Vzc2lvbi5cbiAgICAgICAgICAgICAgICAgKiBAdHlwZSB7U3RyaW5nfVxuICAgICAgICAgICAgICAgICAqL1xuICAgICAgICAgICAgICAgIGdyb3VwSWQ6IHNlc3Npb24uZ3JvdXBJZCxcbiAgICAgICAgICAgICAgICB1c2VySWQ6IHNlc3Npb24udXNlcklkXG4gICAgICAgICAgICB9O1xuICAgICAgICAgICAgcmV0dXJuICQuZXh0ZW5kKHRydWUsIHNlc3Npb25EZWZhdWx0cywgYmFzZU9wdGlvbnMpO1xuICAgICAgICB9XG4gICAgfTtcbiAgICAkLmV4dGVuZCh0aGlzLCBwdWJsaWNBUEkpO1xufTtcblxubW9kdWxlLmV4cG9ydHMgPSBTZXNzaW9uTWFuYWdlcjsiLCIvKipcbiAgICBEZWNpZGVzIHR5cGUgb2Ygc3RvcmUgdG8gcHJvdmlkZVxuKi9cblxuJ3VzZSBzdHJpY3QnO1xuLy8gdmFyIGlzTm9kZSA9IGZhbHNlOyBGSVhNRTogQnJvd3NlcmlmeS9taW5pZnlpZnkgaGFzIGlzc3VlcyB3aXRoIHRoZSBuZXh0IGxpbmtcbi8vIHZhciBzdG9yZSA9IChpc05vZGUpID8gcmVxdWlyZSgnLi9zZXNzaW9uLXN0b3JlJykgOiByZXF1aXJlKCcuL2Nvb2tpZS1zdG9yZScpO1xudmFyIHN0b3JlID0gcmVxdWlyZSgnLi9jb29raWUtc3RvcmUnKTtcblxubW9kdWxlLmV4cG9ydHMgPSBzdG9yZTtcbiIsIid1c2Ugc3RyaWN0JztcblxudmFyIHF1dGlscyA9IHJlcXVpcmUoJy4uL3V0aWwvcXVlcnktdXRpbCcpO1xuXG5tb2R1bGUuZXhwb3J0cyA9IGZ1bmN0aW9uIChjb25maWcpIHtcblxuICAgIHZhciBkZWZhdWx0cyA9IHtcbiAgICAgICAgdXJsOiAnJyxcblxuICAgICAgICBjb250ZW50VHlwZTogJ2FwcGxpY2F0aW9uL2pzb24nLFxuICAgICAgICBoZWFkZXJzOiB7fSxcbiAgICAgICAgc3RhdHVzQ29kZToge1xuICAgICAgICAgICAgNDA0OiAkLm5vb3BcbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgICogT05MWSBmb3Igc3RyaW5ncyBpbiB0aGUgdXJsLiBBbGwgR0VUICYgREVMRVRFIHBhcmFtcyBhcmUgcnVuIHRocm91Z2ggdGhpc1xuICAgICAgICAgKiBAdHlwZSB7W3R5cGVdIH1cbiAgICAgICAgICovXG4gICAgICAgIHBhcmFtZXRlclBhcnNlcjogcXV0aWxzLnRvUXVlcnlGb3JtYXQsXG5cbiAgICAgICAgLy8gVG8gYWxsb3cgZXBpY2VudGVyLnRva2VuIGFuZCBvdGhlciBzZXNzaW9uIGNvb2tpZXMgdG8gYmUgcGFzc2VkXG4gICAgICAgIC8vIHdpdGggdGhlIHJlcXVlc3RzXG4gICAgICAgIHhockZpZWxkczoge1xuICAgICAgICAgICAgd2l0aENyZWRlbnRpYWxzOiB0cnVlXG4gICAgICAgIH1cbiAgICB9O1xuXG4gICAgdmFyIHRyYW5zcG9ydE9wdGlvbnMgPSAkLmV4dGVuZCh7fSwgZGVmYXVsdHMsIGNvbmZpZyk7XG5cbiAgICB2YXIgcmVzdWx0ID0gZnVuY3Rpb24gKGQpIHtcbiAgICAgICAgcmV0dXJuICgkLmlzRnVuY3Rpb24oZCkpID8gZCgpIDogZDtcbiAgICB9O1xuXG4gICAgdmFyIGNvbm5lY3QgPSBmdW5jdGlvbiAobWV0aG9kLCBwYXJhbXMsIGNvbm5lY3RPcHRpb25zKSB7XG4gICAgICAgIHBhcmFtcyA9IHJlc3VsdChwYXJhbXMpO1xuICAgICAgICBwYXJhbXMgPSAoJC5pc1BsYWluT2JqZWN0KHBhcmFtcykgfHwgJC5pc0FycmF5KHBhcmFtcykpID8gSlNPTi5zdHJpbmdpZnkocGFyYW1zKSA6IHBhcmFtcztcblxuICAgICAgICB2YXIgb3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LCB0cmFuc3BvcnRPcHRpb25zLCBjb25uZWN0T3B0aW9ucywge1xuICAgICAgICAgICAgdHlwZTogbWV0aG9kLFxuICAgICAgICAgICAgZGF0YTogcGFyYW1zXG4gICAgICAgIH0pO1xuICAgICAgICB2YXIgQUxMT1dFRF9UT19CRV9GVU5DVElPTlMgPSBbJ2RhdGEnLCAndXJsJ107XG4gICAgICAgICQuZWFjaChvcHRpb25zLCBmdW5jdGlvbiAoa2V5LCB2YWx1ZSkge1xuICAgICAgICAgICAgaWYgKCQuaXNGdW5jdGlvbih2YWx1ZSkgJiYgJC5pbkFycmF5KGtleSwgQUxMT1dFRF9UT19CRV9GVU5DVElPTlMpICE9PSAtMSkge1xuICAgICAgICAgICAgICAgIG9wdGlvbnNba2V5XSA9IHZhbHVlKCk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH0pO1xuXG4gICAgICAgIGlmIChvcHRpb25zLmxvZ0xldmVsICYmIG9wdGlvbnMubG9nTGV2ZWwgPT09ICdERUJVRycpIHtcbiAgICAgICAgICAgIGNvbnNvbGUubG9nKG9wdGlvbnMudXJsKTtcbiAgICAgICAgICAgIHZhciBvbGRTdWNjZXNzRm4gPSBvcHRpb25zLnN1Y2Nlc3MgfHwgJC5ub29wO1xuICAgICAgICAgICAgb3B0aW9ucy5zdWNjZXNzID0gZnVuY3Rpb24gKHJlc3BvbnNlLCBhamF4U3RhdHVzLCBhamF4UmVxKSB7XG4gICAgICAgICAgICAgICAgY29uc29sZS5sb2cocmVzcG9uc2UpO1xuICAgICAgICAgICAgICAgIG9sZFN1Y2Nlc3NGbi5hcHBseSh0aGlzLCBhcmd1bWVudHMpO1xuICAgICAgICAgICAgfTtcbiAgICAgICAgfVxuXG4gICAgICAgIHZhciBiZWZvcmVTZW5kID0gb3B0aW9ucy5iZWZvcmVTZW5kO1xuICAgICAgICBvcHRpb25zLmJlZm9yZVNlbmQgPSBmdW5jdGlvbiAoeGhyLCBzZXR0aW5ncykge1xuICAgICAgICAgICAgeGhyLnJlcXVlc3RVcmwgPSAoY29ubmVjdE9wdGlvbnMgfHwge30pLnVybDtcbiAgICAgICAgICAgIGlmIChiZWZvcmVTZW5kKSB7XG4gICAgICAgICAgICAgICAgYmVmb3JlU2VuZC5hcHBseSh0aGlzLCBhcmd1bWVudHMpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9O1xuXG4gICAgICAgIHJldHVybiAkLmFqYXgob3B0aW9ucyk7XG4gICAgfTtcblxuICAgIHZhciBwdWJsaWNBUEkgPSB7XG4gICAgICAgIGdldDpmdW5jdGlvbiAocGFyYW1zLCBhamF4T3B0aW9ucykge1xuICAgICAgICAgICAgdmFyIG9wdGlvbnMgPSAkLmV4dGVuZCh7fSwgdHJhbnNwb3J0T3B0aW9ucywgYWpheE9wdGlvbnMpO1xuICAgICAgICAgICAgcGFyYW1zID0gb3B0aW9ucy5wYXJhbWV0ZXJQYXJzZXIocmVzdWx0KHBhcmFtcykpO1xuICAgICAgICAgICAgcmV0dXJuIGNvbm5lY3QuY2FsbCh0aGlzLCAnR0VUJywgcGFyYW1zLCBvcHRpb25zKTtcbiAgICAgICAgfSxcbiAgICAgICAgc3BsaXRHZXQ6IGZ1bmN0aW9uICgpIHtcblxuICAgICAgICB9LFxuICAgICAgICBwb3N0OiBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICByZXR1cm4gY29ubmVjdC5hcHBseSh0aGlzLCBbJ3Bvc3QnXS5jb25jYXQoW10uc2xpY2UuY2FsbChhcmd1bWVudHMpKSk7XG4gICAgICAgIH0sXG4gICAgICAgIHBhdGNoOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICByZXR1cm4gY29ubmVjdC5hcHBseSh0aGlzLCBbJ3BhdGNoJ10uY29uY2F0KFtdLnNsaWNlLmNhbGwoYXJndW1lbnRzKSkpO1xuICAgICAgICB9LFxuICAgICAgICBwdXQ6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIHJldHVybiBjb25uZWN0LmFwcGx5KHRoaXMsIFsncHV0J10uY29uY2F0KFtdLnNsaWNlLmNhbGwoYXJndW1lbnRzKSkpO1xuICAgICAgICB9LFxuICAgICAgICBkZWxldGU6IGZ1bmN0aW9uIChwYXJhbXMsIGFqYXhPcHRpb25zKSB7XG4gICAgICAgICAgICAvL0RFTEVURSBkb2Vzbid0IHN1cHBvcnQgYm9keSBwYXJhbXMsIGJ1dCBqUXVlcnkgdGhpbmtzIGl0IGRvZXMuXG4gICAgICAgICAgICB2YXIgb3B0aW9ucyA9ICQuZXh0ZW5kKHt9LCB0cmFuc3BvcnRPcHRpb25zLCBhamF4T3B0aW9ucyk7XG4gICAgICAgICAgICBwYXJhbXMgPSBvcHRpb25zLnBhcmFtZXRlclBhcnNlcihyZXN1bHQocGFyYW1zKSk7XG4gICAgICAgICAgICBpZiAoJC50cmltKHBhcmFtcykpIHtcbiAgICAgICAgICAgICAgICB2YXIgZGVsaW1pdGVyID0gKHJlc3VsdChvcHRpb25zLnVybCkuaW5kZXhPZignPycpID09PSAtMSkgPyAnPycgOiAnJic7XG4gICAgICAgICAgICAgICAgb3B0aW9ucy51cmwgPSByZXN1bHQob3B0aW9ucy51cmwpICsgZGVsaW1pdGVyICsgcGFyYW1zO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgcmV0dXJuIGNvbm5lY3QuY2FsbCh0aGlzLCAnREVMRVRFJywgbnVsbCwgb3B0aW9ucyk7XG4gICAgICAgIH0sXG4gICAgICAgIGhlYWQ6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIHJldHVybiBjb25uZWN0LmFwcGx5KHRoaXMsIFsnaGVhZCddLmNvbmNhdChbXS5zbGljZS5jYWxsKGFyZ3VtZW50cykpKTtcbiAgICAgICAgfSxcbiAgICAgICAgb3B0aW9uczogZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgcmV0dXJuIGNvbm5lY3QuYXBwbHkodGhpcywgWydvcHRpb25zJ10uY29uY2F0KFtdLnNsaWNlLmNhbGwoYXJndW1lbnRzKSkpO1xuICAgICAgICB9XG4gICAgfTtcblxuICAgIHJldHVybiAkLmV4dGVuZCh0aGlzLCBwdWJsaWNBUEkpO1xufTtcbiIsIid1c2Ugc3RyaWN0JztcblxuLy8gdmFyIGlzTm9kZSA9IGZhbHNlOyBGSVhNRTogQnJvd3NlcmlmeS9taW5pZnlpZnkgaGFzIGlzc3VlcyB3aXRoIHRoZSBuZXh0IGxpbmtcbi8vIHZhciB0cmFuc3BvcnQgPSAoaXNOb2RlKSA/IHJlcXVpcmUoJy4vbm9kZS1odHRwLXRyYW5zcG9ydCcpIDogcmVxdWlyZSgnLi9hamF4LWh0dHAtdHJhbnNwb3J0Jyk7XG52YXIgdHJhbnNwb3J0ID0gcmVxdWlyZSgnLi9hamF4LWh0dHAtdHJhbnNwb3J0Jyk7XG5tb2R1bGUuZXhwb3J0cyA9IHRyYW5zcG9ydDtcbiIsIi8qKlxuLyogSW5oZXJpdCBmcm9tIGEgY2xhc3MgKHVzaW5nIHByb3RvdHlwZSBib3Jyb3dpbmcpXG4qL1xuJ3VzZSBzdHJpY3QnO1xuXG5mdW5jdGlvbiBpbmhlcml0KEMsIFApIHtcbiAgICB2YXIgRiA9IGZ1bmN0aW9uICgpIHt9O1xuICAgIEYucHJvdG90eXBlID0gUC5wcm90b3R5cGU7XG4gICAgQy5wcm90b3R5cGUgPSBuZXcgRigpO1xuICAgIEMuX19zdXBlciA9IFAucHJvdG90eXBlO1xuICAgIEMucHJvdG90eXBlLmNvbnN0cnVjdG9yID0gQztcbn1cblxuLyoqXG4qIFNoYWxsb3cgY29weSBvZiBhbiBvYmplY3RcbiovXG52YXIgZXh0ZW5kID0gZnVuY3Rpb24gKGRlc3QgLyosIHZhcl9hcmdzKi8pIHtcbiAgICB2YXIgb2JqID0gQXJyYXkucHJvdG90eXBlLnNsaWNlLmNhbGwoYXJndW1lbnRzLCAxKTtcbiAgICB2YXIgY3VycmVudDtcbiAgICBmb3IgKHZhciBqID0gMDsgajxvYmoubGVuZ3RoOyBqKyspIHtcbiAgICAgICAgaWYgKCEoY3VycmVudCA9IG9ialtqXSkpIHtcbiAgICAgICAgICAgIGNvbnRpbnVlO1xuICAgICAgICB9XG5cbiAgICAgICAgLy8gZG8gbm90IHdyYXAgaW5uZXIgaW4gZGVzdC5oYXNPd25Qcm9wZXJ0eSBvciBiYWQgdGhpbmdzIHdpbGwgaGFwcGVuXG4gICAgICAgIC8qanNoaW50IC1XMDg5ICovXG4gICAgICAgIGZvciAodmFyIGtleSBpbiBjdXJyZW50KSB7XG4gICAgICAgICAgICBkZXN0W2tleV0gPSBjdXJyZW50W2tleV07XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICByZXR1cm4gZGVzdDtcbn07XG5cbm1vZHVsZS5leHBvcnRzID0gZnVuY3Rpb24gKGJhc2UsIHByb3BzLCBzdGF0aWNQcm9wcykge1xuICAgIHZhciBwYXJlbnQgPSBiYXNlO1xuICAgIHZhciBjaGlsZDtcblxuICAgIGNoaWxkID0gcHJvcHMgJiYgcHJvcHMuaGFzT3duUHJvcGVydHkoJ2NvbnN0cnVjdG9yJykgPyBwcm9wcy5jb25zdHJ1Y3RvciA6IGZ1bmN0aW9uICgpIHsgcmV0dXJuIHBhcmVudC5hcHBseSh0aGlzLCBhcmd1bWVudHMpOyB9O1xuXG4gICAgLy8gYWRkIHN0YXRpYyBwcm9wZXJ0aWVzIHRvIHRoZSBjaGlsZCBjb25zdHJ1Y3RvciBmdW5jdGlvblxuICAgIGV4dGVuZChjaGlsZCwgcGFyZW50LCBzdGF0aWNQcm9wcyk7XG5cbiAgICAvLyBhc3NvY2lhdGUgcHJvdG90eXBlIGNoYWluXG4gICAgaW5oZXJpdChjaGlsZCwgcGFyZW50KTtcblxuICAgIC8vIGFkZCBpbnN0YW5jZSBwcm9wZXJ0aWVzXG4gICAgaWYgKHByb3BzKSB7XG4gICAgICAgIGV4dGVuZChjaGlsZC5wcm90b3R5cGUsIHByb3BzKTtcbiAgICB9XG5cbiAgICAvLyBkb25lXG4gICAgcmV0dXJuIGNoaWxkO1xufTtcbiIsIid1c2Ugc3RyaWN0Jztcbi8qanNoaW50IGxvb3BmdW5jOmZhbHNlICovXG5cbmZ1bmN0aW9uIF93KHZhbCkge1xuICAgIGlmICh2YWwgJiYgdmFsLnRoZW4pIHtcbiAgICAgICAgcmV0dXJuIHZhbDtcbiAgICB9XG4gICAgdmFyIHAgPSAkLkRlZmVycmVkKCk7XG4gICAgcC5yZXNvbHZlKHZhbCk7XG5cbiAgICByZXR1cm4gcC5wcm9taXNlKCk7XG59XG5cbmZ1bmN0aW9uIHNlcSgpIHtcbiAgICB2YXIgbGlzdCA9IEFycmF5LnByb3RvdHlwZS5zbGljZS5hcHBseShhcmd1bWVudHMpO1xuXG4gICAgZnVuY3Rpb24gbmV4dChwKSB7XG4gICAgICAgIHZhciBjdXIgPSBsaXN0LnNwbGljZSgwLDEpWzBdO1xuXG4gICAgICAgIGlmICghY3VyKSB7XG4gICAgICAgICAgICByZXR1cm4gcDtcbiAgICAgICAgfVxuXG4gICAgICAgIHJldHVybiBfdyhjdXIocCkpLnRoZW4obmV4dCk7XG4gICAgfVxuXG4gICAgcmV0dXJuIGZ1bmN0aW9uIChzZWVkKSB7XG4gICAgICAgIHJldHVybiBuZXh0KHNlZWQpLmZhaWwoc2VxLmZhaWwpO1xuICAgIH07XG59XG5cbmZ1bmN0aW9uIE1ha2VTZXEob2JqKSB7XG4gICAgdmFyIHJlcyA9IHtcbiAgICAgICAgX19jYWxsczogW10sXG5cbiAgICAgICAgb3JpZ2luYWw6IG9iaixcblxuICAgICAgICB0aGVuOiBmdW5jdGlvbiAoZm4pIHtcbiAgICAgICAgICAgIHRoaXMuX19jYWxscy5wdXNoKGZuKTtcbiAgICAgICAgICAgIHJldHVybiB0aGlzO1xuICAgICAgICB9LFxuXG4gICAgICAgIHN0YXJ0OiBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICB2YXIgX3RoaXMgPSB0aGlzO1xuXG4gICAgICAgICAgICAvLyBjbGVhbiB1cFxuICAgICAgICAgICAgdGhpcy50aGVuKGZ1bmN0aW9uIChydW4pIHtcbiAgICAgICAgICAgICAgICBfdGhpcy5fX2NhbGxzLmxlbmd0aCA9IDA7XG4gICAgICAgICAgICAgICAgcmV0dXJuIHJ1bjtcbiAgICAgICAgICAgIH0pO1xuXG4gICAgICAgICAgICByZXR1cm4gc2VxLmFwcGx5KG51bGwsIHRoaXMuX19jYWxscykoKTtcbiAgICAgICAgfSxcblxuICAgICAgICBmYWlsOiBmdW5jdGlvbiAoZm4pIHtcbiAgICAgICAgICAgIHNlcS5mYWlsID0gZm47XG4gICAgICAgICAgICByZXR1cm4gdGhpcztcbiAgICAgICAgfVxuICAgIH07XG5cbiAgICB2YXIgZnVuY01ha2VyID0gZnVuY3Rpb24gKHAsIG9iaikge1xuICAgICAgICB2YXIgZm4gPSBvYmpbcF0uYmluZChvYmopO1xuICAgICAgICByZXR1cm4gZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgdmFyIGFyZ3MgPSBBcnJheS5wcm90b3R5cGUuc2xpY2UuYXBwbHkoYXJndW1lbnRzKTtcbiAgICAgICAgICAgIHRoaXMuX19jYWxscy5wdXNoKEZ1bmN0aW9uLmJpbmQuYXBwbHkoZm4sIFtudWxsXS5jb25jYXQoYXJncykpKTtcbiAgICAgICAgICAgIHJldHVybiB0aGlzO1xuICAgICAgICB9O1xuICAgIH07XG5cbiAgICBmb3IgKHZhciBwcm9wIGluIG9iaikge1xuICAgICAgICBpZiAodHlwZW9mIG9ialtwcm9wXSA9PT0gJ2Z1bmN0aW9uJykge1xuICAgICAgICAgICAgcmVzW3Byb3BdID0gZnVuY01ha2VyKHByb3AsIG9iaik7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICByZXNbcHJvcF0gPSBvYmpbcHJvcF07XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICByZXR1cm4gcmVzO1xufVxuXG5tb2R1bGUuZXhwb3J0cyA9IE1ha2VTZXE7XG4iLCIndXNlIHN0cmljdCc7XG5cbm1vZHVsZS5leHBvcnRzID0ge1xuICAgIF9waWNrOiBmdW5jdGlvbiAob2JqLCBwcm9wcykge1xuICAgICAgICB2YXIgcmVzID0ge307XG4gICAgICAgIGZvciAodmFyIHAgaW4gb2JqKSB7XG4gICAgICAgICAgICBpZiAocHJvcHMuaW5kZXhPZihwKSAhPT0gLTEpIHtcbiAgICAgICAgICAgICAgICByZXNbcF0gPSBvYmpbcF07XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICByZXR1cm4gcmVzO1xuICAgIH1cbn07XG4iLCIndXNlIHN0cmljdCc7XG5cbnZhciBDb25maWdTZXJ2aWNlID0gcmVxdWlyZSgnLi4vc2VydmljZS9jb25maWd1cmF0aW9uLXNlcnZpY2UnKTtcblxudmFyIHVybENvbmZpZyA9IG5ldyBDb25maWdTZXJ2aWNlKCkuZ2V0KCdzZXJ2ZXInKTtcbnZhciBjdXN0b21EZWZhdWx0cyA9IHt9O1xudmFyIGxpYkRlZmF1bHRzID0ge1xuICAgIC8qKlxuICAgICAqIFRoZSBhY2NvdW50IGlkLiBJbiB0aGUgRXBpY2VudGVyIFVJLCB0aGlzIGlzIHRoZSAqKlRlYW0gSUQqKiAoZm9yIHRlYW0gcHJvamVjdHMpIG9yICoqVXNlciBJRCoqIChmb3IgcGVyc29uYWwgcHJvamVjdHMpLiBEZWZhdWx0cyB0byBlbXB0eSBzdHJpbmcuIElmIGxlZnQgdW5kZWZpbmVkLCB0YWtlbiBmcm9tIHRoZSBVUkwuXG4gICAgICogQHR5cGUge1N0cmluZ31cbiAgICAgKi9cbiAgICBhY2NvdW50OiB1cmxDb25maWcuYWNjb3VudFBhdGgsXG4gICAgLyoqXG4gICAgICogVGhlIGFjY291bnQgaWQuIEluIHRoZSBFcGljZW50ZXIgVUksIHRoaXMgaXMgdGhlICoqVGVhbSBJRCoqIChmb3IgdGVhbSBwcm9qZWN0cykgb3IgKipVc2VyIElEKiogKGZvciBwZXJzb25hbCBwcm9qZWN0cykuIERlZmF1bHRzIHRvIGVtcHR5IHN0cmluZy4gSWYgbGVmdCB1bmRlZmluZWQsIHRha2VuIGZyb20gdGhlIFVSTC5cbiAgICAgKiBAdHlwZSB7U3RyaW5nfVxuICAgICAqL1xuICAgIHByb2plY3Q6IHVybENvbmZpZy5wcm9qZWN0UGF0aCxcbiAgICBpc0xvY2FsOiB1cmxDb25maWcuaXNMb2NhbGhvc3QoKSxcbiAgICBzdG9yZToge31cbn07XG5cbnZhciBvcHRpb25VdGlscyA9IHtcbiAgICAvKipcbiAgICAgKiBHZXRzIHRoZSBmaW5hbCBvcHRpb25zIGJ5IG92ZXJyaWRpbmcgdGhlIGdsb2JhbCBvcHRpb25zIHNldCB3aXRoXG4gICAgICogb3B0aW9uVXRpbHMjc2V0RGVmYXVsdHMoKSBhbmQgdGhlIGxpYiBkZWZhdWx0cy5cbiAgICAgKiBAcGFyYW0ge29iamVjdH0gYG9wdGlvbnNgIFRoZSBmaW5hbCBvcHRpb25zIG9iamVjdC5cbiAgICAgKi9cbiAgICBnZXRPcHRpb25zOiBmdW5jdGlvbiAob3B0aW9ucykge1xuICAgICAgICByZXR1cm4gJC5leHRlbmQodHJ1ZSwge30sIGxpYkRlZmF1bHRzLCBjdXN0b21EZWZhdWx0cywgb3B0aW9ucyk7XG4gICAgfSxcbiAgICAvKipcbiAgICAgKiBTZXRzIHRoZSBnbG9iYWwgZGVmYXVsdHMgZm9yIHRoZSBvcHRpb25VdGlscyNnZXRPcHRpb25zKCkgbWV0aG9kLlxuICAgICAqIEBwYXJhbSB7b2JqZWN0fSBgZGVmYXVsdHNgIFRoZSBkZWZhdWx0cyBvYmplY3QuXG4gICAgICovXG4gICAgc2V0RGVmYXVsdHM6IGZ1bmN0aW9uIChkZWZhdWx0cykge1xuICAgICAgICBjdXN0b21EZWZhdWx0cyA9IGRlZmF1bHRzO1xuICAgIH1cbn07XG5tb2R1bGUuZXhwb3J0cyA9IG9wdGlvblV0aWxzO1xuIiwiLyoqXG4gKiBVdGlsaXRpZXMgZm9yIHdvcmtpbmcgd2l0aCBxdWVyeSBzdHJpbmdzXG4qL1xuJ3VzZSBzdHJpY3QnO1xuXG5tb2R1bGUuZXhwb3J0cyA9IChmdW5jdGlvbiAoKSB7XG5cbiAgICByZXR1cm4ge1xuICAgICAgICAvKipcbiAgICAgICAgICogQ29udmVydHMgdG8gbWF0cml4IGZvcm1hdFxuICAgICAgICAgKiBAcGFyYW0gIHtPYmplY3R9IHFzIE9iamVjdCB0byBjb252ZXJ0IHRvIHF1ZXJ5IHN0cmluZ1xuICAgICAgICAgKiBAcmV0dXJuIHsgc3RyaW5nfSAgICBNYXRyaXgtZm9ybWF0IHF1ZXJ5IHBhcmFtZXRlcnNcbiAgICAgICAgICovXG4gICAgICAgIHRvTWF0cml4Rm9ybWF0OiBmdW5jdGlvbiAocXMpIHtcbiAgICAgICAgICAgIGlmIChxcyA9PT0gbnVsbCB8fCBxcyA9PT0gdW5kZWZpbmVkIHx8IHFzID09PSAnJykge1xuICAgICAgICAgICAgICAgIHJldHVybiAnOyc7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBpZiAodHlwZW9mIHFzID09PSAnc3RyaW5nJyB8fCBxcyBpbnN0YW5jZW9mIFN0cmluZykge1xuICAgICAgICAgICAgICAgIHJldHVybiBxcztcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgdmFyIHJldHVybkFycmF5ID0gW107XG4gICAgICAgICAgICB2YXIgT1BFUkFUT1JTID0gWyc8JywgJz4nLCAnISddO1xuICAgICAgICAgICAgJC5lYWNoKHFzLCBmdW5jdGlvbiAoa2V5LCB2YWx1ZSkge1xuICAgICAgICAgICAgICAgIGlmICh0eXBlb2YgdmFsdWUgIT09ICdzdHJpbmcnIHx8ICQuaW5BcnJheSgkLnRyaW0odmFsdWUpLmNoYXJBdCgwKSwgT1BFUkFUT1JTKSA9PT0gLTEpIHtcbiAgICAgICAgICAgICAgICAgICAgdmFsdWUgPSAnPScgKyB2YWx1ZTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgcmV0dXJuQXJyYXkucHVzaChrZXkgKyB2YWx1ZSk7XG4gICAgICAgICAgICB9KTtcblxuICAgICAgICAgICAgdmFyIG10cnggPSAnOycgKyByZXR1cm5BcnJheS5qb2luKCc7Jyk7XG4gICAgICAgICAgICByZXR1cm4gbXRyeDtcbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgICogQ29udmVydHMgc3RyaW5ncy9hcnJheXMvb2JqZWN0cyB0byB0eXBlICdhPWImYj1jJ1xuICAgICAgICAgKiBAcGFyYW0gIHsgc3RyaW5nfEFycmF5fE9iamVjdH0gcXNcbiAgICAgICAgICogQHJldHVybiB7IHN0cmluZ31cbiAgICAgICAgICovXG4gICAgICAgIHRvUXVlcnlGb3JtYXQ6IGZ1bmN0aW9uIChxcykge1xuICAgICAgICAgICAgaWYgKHFzID09PSBudWxsIHx8IHFzID09PSB1bmRlZmluZWQpIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gJyc7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBpZiAodHlwZW9mIHFzID09PSAnc3RyaW5nJyB8fCBxcyBpbnN0YW5jZW9mIFN0cmluZykge1xuICAgICAgICAgICAgICAgIHJldHVybiBxcztcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgdmFyIHJldHVybkFycmF5ID0gW107XG4gICAgICAgICAgICAkLmVhY2gocXMsIGZ1bmN0aW9uIChrZXksIHZhbHVlKSB7XG4gICAgICAgICAgICAgICAgaWYgKCQuaXNBcnJheSh2YWx1ZSkpIHtcbiAgICAgICAgICAgICAgICAgICAgdmFsdWUgPSB2YWx1ZS5qb2luKCcsJyk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIGlmICgkLmlzUGxhaW5PYmplY3QodmFsdWUpKSB7XG4gICAgICAgICAgICAgICAgICAgIC8vTW9zdGx5IGZvciBkYXRhIGFwaVxuICAgICAgICAgICAgICAgICAgICB2YWx1ZSA9IEpTT04uc3RyaW5naWZ5KHZhbHVlKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgcmV0dXJuQXJyYXkucHVzaChrZXkgKyAnPScgKyB2YWx1ZSk7XG4gICAgICAgICAgICB9KTtcblxuICAgICAgICAgICAgdmFyIHJlc3VsdCA9IHJldHVybkFycmF5LmpvaW4oJyYnKTtcbiAgICAgICAgICAgIHJldHVybiByZXN1bHQ7XG4gICAgICAgIH0sXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIENvbnZlcnRzIHN0cmluZ3Mgb2YgdHlwZSAnYT1iJmI9YycgdG8geyBhOmIsIGI6Y31cbiAgICAgICAgICogQHBhcmFtICB7IHN0cmluZ30gcXNcbiAgICAgICAgICogQHJldHVybiB7b2JqZWN0fVxuICAgICAgICAgKi9cbiAgICAgICAgcXNUb09iamVjdDogZnVuY3Rpb24gKHFzKSB7XG4gICAgICAgICAgICBpZiAocXMgPT09IG51bGwgfHwgcXMgPT09IHVuZGVmaW5lZCB8fCBxcyA9PT0gJycpIHtcbiAgICAgICAgICAgICAgICByZXR1cm4ge307XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIHZhciBxc0FycmF5ID0gcXMuc3BsaXQoJyYnKTtcbiAgICAgICAgICAgIHZhciByZXR1cm5PYmogPSB7fTtcbiAgICAgICAgICAgICQuZWFjaChxc0FycmF5LCBmdW5jdGlvbiAoaW5kZXgsIHZhbHVlKSB7XG4gICAgICAgICAgICAgICAgdmFyIHFLZXkgPSB2YWx1ZS5zcGxpdCgnPScpWzBdO1xuICAgICAgICAgICAgICAgIHZhciBxVmFsID0gdmFsdWUuc3BsaXQoJz0nKVsxXTtcblxuICAgICAgICAgICAgICAgIGlmIChxVmFsLmluZGV4T2YoJywnKSAhPT0gLTEpIHtcbiAgICAgICAgICAgICAgICAgICAgcVZhbCA9IHFWYWwuc3BsaXQoJywnKTtcbiAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICByZXR1cm5PYmpbcUtleV0gPSBxVmFsO1xuICAgICAgICAgICAgfSk7XG5cbiAgICAgICAgICAgIHJldHVybiByZXR1cm5PYmo7XG4gICAgICAgIH0sXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIE5vcm1hbGl6ZXMgYW5kIG1lcmdlcyBzdHJpbmdzIG9mIHR5cGUgJ2E9YicsIHsgYjpjfSB0byB7IGE6YiwgYjpjfVxuICAgICAgICAgKiBAcGFyYW0gIHsgc3RyaW5nfEFycmF5fE9iamVjdH0gcXMxXG4gICAgICAgICAqIEBwYXJhbSAgeyBzdHJpbmd8QXJyYXl8T2JqZWN0fSBxczJcbiAgICAgICAgICogQHJldHVybiB7T2JqZWN0fVxuICAgICAgICAgKi9cbiAgICAgICAgbWVyZ2VRUzogZnVuY3Rpb24gKHFzMSwgcXMyKSB7XG4gICAgICAgICAgICB2YXIgb2JqMSA9IHRoaXMucXNUb09iamVjdCh0aGlzLnRvUXVlcnlGb3JtYXQocXMxKSk7XG4gICAgICAgICAgICB2YXIgb2JqMiA9IHRoaXMucXNUb09iamVjdCh0aGlzLnRvUXVlcnlGb3JtYXQocXMyKSk7XG4gICAgICAgICAgICByZXR1cm4gJC5leHRlbmQodHJ1ZSwge30sIG9iajEsIG9iajIpO1xuICAgICAgICB9LFxuXG4gICAgICAgIGFkZFRyYWlsaW5nU2xhc2g6IGZ1bmN0aW9uICh1cmwpIHtcbiAgICAgICAgICAgIGlmICghdXJsKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuICcnO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgcmV0dXJuICh1cmwuY2hhckF0KHVybC5sZW5ndGggLSAxKSA9PT0gJy8nKSA/IHVybCA6ICh1cmwgKyAnLycpO1xuICAgICAgICB9XG4gICAgfTtcbn0oKSk7XG5cblxuXG4iLCIvKipcbiAqIFV0aWxpdGllcyBmb3Igd29ya2luZyB3aXRoIHRoZSBydW4gc2VydmljZVxuKi9cbid1c2Ugc3RyaWN0JztcbnZhciBxdXRpbCA9IHJlcXVpcmUoJy4vcXVlcnktdXRpbCcpO1xudmFyIE1BWF9VUkxfTEVOR1RIID0gMjA0ODtcblxubW9kdWxlLmV4cG9ydHMgPSAoZnVuY3Rpb24gKCkge1xuICAgIHJldHVybiB7XG4gICAgICAgIC8qKlxuICAgICAgICAgKiByZXR1cm5zIG9wZXJhdGlvbnMgb2YgdGhlIGZvcm0gYFtbb3AxLG9wMl0sIFthcmcxLCBhcmcyXV1gXG4gICAgICAgICAqIEBwYXJhbSAge09iamVjdHxBcnJheXxTdHJpbmd9IGBvcGVyYXRpb25zYCBvcGVyYXRpb25zIHRvIHBlcmZvcm1cbiAgICAgICAgICogQHBhcmFtICB7QXJyYXl9IGBhcmdzYCBhcmd1bWVudHMgZm9yIG9wZXJhdGlvblxuICAgICAgICAgKiBAcmV0dXJuIHtTdHJpbmd9ICAgIE1hdHJpeC1mb3JtYXQgcXVlcnkgcGFyYW1ldGVyc1xuICAgICAgICAgKi9cbiAgICAgICAgbm9ybWFsaXplT3BlcmF0aW9uczogZnVuY3Rpb24gKG9wZXJhdGlvbnMsIGFyZ3MpIHtcbiAgICAgICAgICAgIGlmICghYXJncykge1xuICAgICAgICAgICAgICAgIGFyZ3MgPSBbXTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHZhciByZXR1cm5MaXN0ID0ge1xuICAgICAgICAgICAgICAgIG9wczogW10sXG4gICAgICAgICAgICAgICAgYXJnczogW11cbiAgICAgICAgICAgIH07XG5cbiAgICAgICAgICAgIHZhciBfY29uY2F0ID0gZnVuY3Rpb24gKGFycikge1xuICAgICAgICAgICAgICAgIHJldHVybiAoYXJyICE9PSBudWxsICYmIGFyciAhPT0gdW5kZWZpbmVkKSA/IFtdLmNvbmNhdChhcnIpIDogW107XG4gICAgICAgICAgICB9O1xuXG4gICAgICAgICAgICAvL3sgYWRkOiBbMSwyXSwgc3VidHJhY3Q6IFsyLDRdIH1cbiAgICAgICAgICAgIHZhciBfbm9ybWFsaXplUGxhaW5PYmplY3RzID0gZnVuY3Rpb24gKG9wZXJhdGlvbnMsIHJldHVybkxpc3QpIHtcbiAgICAgICAgICAgICAgICBpZiAoIXJldHVybkxpc3QpIHtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuTGlzdCA9IHsgb3BzOiBbXSwgYXJnczogW10gfTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgJC5lYWNoKG9wZXJhdGlvbnMsIGZ1bmN0aW9uIChvcG4sIGFyZykge1xuICAgICAgICAgICAgICAgICAgICByZXR1cm5MaXN0Lm9wcy5wdXNoKG9wbik7XG4gICAgICAgICAgICAgICAgICAgIHJldHVybkxpc3QuYXJncy5wdXNoKF9jb25jYXQoYXJnKSk7XG4gICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgICAgcmV0dXJuIHJldHVybkxpc3Q7XG4gICAgICAgICAgICB9O1xuICAgICAgICAgICAgLy97IG5hbWU6ICdhZGQnLCBwYXJhbXM6IFsxXSB9XG4gICAgICAgICAgICB2YXIgX25vcm1hbGl6ZVN0cnVjdHVyZWRPYmplY3RzID0gZnVuY3Rpb24gKG9wZXJhdGlvbiwgcmV0dXJuTGlzdCkge1xuICAgICAgICAgICAgICAgIGlmICghcmV0dXJuTGlzdCkge1xuICAgICAgICAgICAgICAgICAgICByZXR1cm5MaXN0ID0geyBvcHM6IFtdLCBhcmdzOiBbXSB9O1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICByZXR1cm5MaXN0Lm9wcy5wdXNoKG9wZXJhdGlvbi5uYW1lKTtcbiAgICAgICAgICAgICAgICByZXR1cm5MaXN0LmFyZ3MucHVzaChfY29uY2F0KG9wZXJhdGlvbi5wYXJhbXMpKTtcbiAgICAgICAgICAgICAgICByZXR1cm4gcmV0dXJuTGlzdDtcbiAgICAgICAgICAgIH07XG5cbiAgICAgICAgICAgIHZhciBfbm9ybWFsaXplT2JqZWN0ID0gZnVuY3Rpb24gKG9wZXJhdGlvbiwgcmV0dXJuTGlzdCkge1xuICAgICAgICAgICAgICAgIHJldHVybiAoKG9wZXJhdGlvbi5uYW1lKSA/IF9ub3JtYWxpemVTdHJ1Y3R1cmVkT2JqZWN0cyA6IF9ub3JtYWxpemVQbGFpbk9iamVjdHMpKG9wZXJhdGlvbiwgcmV0dXJuTGlzdCk7XG4gICAgICAgICAgICB9O1xuXG4gICAgICAgICAgICB2YXIgX25vcm1hbGl6ZUxpdGVyYWxzID0gZnVuY3Rpb24gKG9wZXJhdGlvbiwgYXJncywgcmV0dXJuTGlzdCkge1xuICAgICAgICAgICAgICAgIGlmICghcmV0dXJuTGlzdCkge1xuICAgICAgICAgICAgICAgICAgICByZXR1cm5MaXN0ID0geyBvcHM6IFtdLCBhcmdzOiBbXSB9O1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICByZXR1cm5MaXN0Lm9wcy5wdXNoKG9wZXJhdGlvbik7XG4gICAgICAgICAgICAgICAgcmV0dXJuTGlzdC5hcmdzLnB1c2goX2NvbmNhdChhcmdzKSk7XG4gICAgICAgICAgICAgICAgcmV0dXJuIHJldHVybkxpc3Q7XG4gICAgICAgICAgICB9O1xuXG5cbiAgICAgICAgICAgIHZhciBfbm9ybWFsaXplQXJyYXlzID0gZnVuY3Rpb24gKG9wZXJhdGlvbnMsIGFyZywgcmV0dXJuTGlzdCkge1xuICAgICAgICAgICAgICAgIGlmICghcmV0dXJuTGlzdCkge1xuICAgICAgICAgICAgICAgICAgICByZXR1cm5MaXN0ID0geyBvcHM6IFtdLCBhcmdzOiBbXSB9O1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAkLmVhY2gob3BlcmF0aW9ucywgZnVuY3Rpb24gKGluZGV4LCBvcG4pIHtcbiAgICAgICAgICAgICAgICAgICAgaWYgKCQuaXNQbGFpbk9iamVjdChvcG4pKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBfbm9ybWFsaXplT2JqZWN0KG9wbiwgcmV0dXJuTGlzdCk7XG4gICAgICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBfbm9ybWFsaXplTGl0ZXJhbHMob3BuLCBhcmdzW2luZGV4XSwgcmV0dXJuTGlzdCk7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgICByZXR1cm4gcmV0dXJuTGlzdDtcbiAgICAgICAgICAgIH07XG5cbiAgICAgICAgICAgIGlmICgkLmlzUGxhaW5PYmplY3Qob3BlcmF0aW9ucykpIHtcbiAgICAgICAgICAgICAgICBfbm9ybWFsaXplT2JqZWN0KG9wZXJhdGlvbnMsIHJldHVybkxpc3QpO1xuICAgICAgICAgICAgfSBlbHNlIGlmICgkLmlzQXJyYXkob3BlcmF0aW9ucykpIHtcbiAgICAgICAgICAgICAgICBfbm9ybWFsaXplQXJyYXlzKG9wZXJhdGlvbnMsIGFyZ3MsIHJldHVybkxpc3QpO1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICBfbm9ybWFsaXplTGl0ZXJhbHMob3BlcmF0aW9ucywgYXJncywgcmV0dXJuTGlzdCk7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIHJldHVybiByZXR1cm5MaXN0O1xuICAgICAgICB9LFxuXG4gICAgICAgIHNwbGl0R2V0RmFjdG9yeTogZnVuY3Rpb24gKGh0dHBPcHRpb25zKSB7XG4gICAgICAgICAgICByZXR1cm4gZnVuY3Rpb24gKHBhcmFtcywgb3B0aW9ucykge1xuICAgICAgICAgICAgICAgIHZhciBodHRwID0gdGhpcztcbiAgICAgICAgICAgICAgICB2YXIgZ2V0VmFsdWUgPSBmdW5jdGlvbiAobmFtZSkge1xuICAgICAgICAgICAgICAgICAgICB2YXIgdmFsdWUgPSBvcHRpb25zW25hbWVdIHx8IGh0dHBPcHRpb25zW25hbWVdO1xuICAgICAgICAgICAgICAgICAgICBpZiAodHlwZW9mIHZhbHVlID09PSAnZnVuY3Rpb24nKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICB2YWx1ZSA9IHZhbHVlKCk7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIHZhbHVlO1xuICAgICAgICAgICAgICAgIH07XG4gICAgICAgICAgICAgICAgdmFyIGdldEZpbmFsVXJsID0gZnVuY3Rpb24gKHBhcmFtcykge1xuICAgICAgICAgICAgICAgICAgICB2YXIgdXJsID0gZ2V0VmFsdWUoJ3VybCcsIG9wdGlvbnMpO1xuICAgICAgICAgICAgICAgICAgICB2YXIgZGF0YSA9IHBhcmFtcztcbiAgICAgICAgICAgICAgICAgICAgLy8gVGhlcmUgaXMgZWFzeSAob3Iga25vd24pIHdheSB0byBnZXQgdGhlIGZpbmFsIFVSTCBqcXVlcnkgaXMgZ29pbmcgdG8gc2VuZCBzb1xuICAgICAgICAgICAgICAgICAgICAvLyB3ZSdyZSByZXBsaWNhdGluZyBpdC4gVGhlIHByb2Nlc3MgbWlnaHQgY2hhbmdlIGF0IHNvbWUgcG9pbnQgYnV0IGl0IHByb2JhYmx5IHdpbGwgbm90LlxuICAgICAgICAgICAgICAgICAgICAvLyAxLiBSZW1vdmUgaGFzaFxuICAgICAgICAgICAgICAgICAgICB1cmwgPSB1cmwucmVwbGFjZSgvIy4qJC8sICcnKTtcbiAgICAgICAgICAgICAgICAgICAgLy8gMS4gQXBwZW5kIHF1ZXJ5IHN0cmluZ1xuICAgICAgICAgICAgICAgICAgICB2YXIgcXVlcnlQYXJhbXMgPSBxdXRpbC50b1F1ZXJ5Rm9ybWF0KGRhdGEpO1xuICAgICAgICAgICAgICAgICAgICB2YXIgcXVlc3Rpb25JZHggPSB1cmwuaW5kZXhPZignPycpO1xuICAgICAgICAgICAgICAgICAgICBpZiAocXVlcnlQYXJhbXMgJiYgcXVlc3Rpb25JZHggPiAtMSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIHVybCArICcmJyArIHF1ZXJ5UGFyYW1zO1xuICAgICAgICAgICAgICAgICAgICB9IGVsc2UgaWYgKHF1ZXJ5UGFyYW1zKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICByZXR1cm4gdXJsICsgJz8nICsgcXVlcnlQYXJhbXM7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIHVybDtcbiAgICAgICAgICAgICAgICB9O1xuICAgICAgICAgICAgICAgIHZhciB1cmwgPSBnZXRGaW5hbFVybChwYXJhbXMpO1xuICAgICAgICAgICAgICAgIC8vIFdlIG11c3Qgc3BsaXQgdGhlIEdFVCBpbiBtdWx0aXBsZSBzaG9ydCBVUkwnc1xuICAgICAgICAgICAgICAgIC8vIFRoZSBvbmx5IHByb3BlcnR5IGFsbG93ZWQgdG8gYmUgc3BsaXQgaXMgXCJpbmNsdWRlXCJcbiAgICAgICAgICAgICAgICBpZiAocGFyYW1zICYmIHBhcmFtcy5pbmNsdWRlICYmIGVuY29kZVVSSSh1cmwpLmxlbmd0aCA+IE1BWF9VUkxfTEVOR1RIKSB7XG4gICAgICAgICAgICAgICAgICAgIHZhciBkdGQgPSAkLkRlZmVycmVkKCk7XG4gICAgICAgICAgICAgICAgICAgIHZhciBwYXJhbXNDb3B5ID0gJC5leHRlbmQodHJ1ZSwge30sIHBhcmFtcyk7XG4gICAgICAgICAgICAgICAgICAgIGRlbGV0ZSBwYXJhbXNDb3B5LmluY2x1ZGU7XG4gICAgICAgICAgICAgICAgICAgIHZhciB1cmxOb0luY2x1ZGVzID0gZ2V0RmluYWxVcmwocGFyYW1zQ29weSk7XG4gICAgICAgICAgICAgICAgICAgIHZhciBkaWZmID0gTUFYX1VSTF9MRU5HVEggLSB1cmxOb0luY2x1ZGVzLmxlbmd0aDtcbiAgICAgICAgICAgICAgICAgICAgdmFyIG9sZFN1Y2Nlc3MgPSBvcHRpb25zLnN1Y2Nlc3MgfHwgaHR0cE9wdGlvbnMuc3VjY2VzcyB8fCAkLm5vb3A7XG4gICAgICAgICAgICAgICAgICAgIHZhciBvbGRFcnJvciA9IG9wdGlvbnMuZXJyb3IgfHwgaHR0cE9wdGlvbnMuZXJyb3IgfHwgJC5ub29wO1xuICAgICAgICAgICAgICAgICAgICAvLyByZW1vdmUgdGhlIG9yaWdpbmFsIHN1Y2Nlc3MgYW5kIGVycm9yIGNhbGxiYWNrc1xuICAgICAgICAgICAgICAgICAgICBvcHRpb25zLnN1Y2Nlc3MgPSAkLm5vb3A7XG4gICAgICAgICAgICAgICAgICAgIG9wdGlvbnMuZXJyb3IgPSAkLm5vb3A7XG5cbiAgICAgICAgICAgICAgICAgICAgdmFyIGluY2x1ZGUgPSBwYXJhbXMuaW5jbHVkZTtcbiAgICAgICAgICAgICAgICAgICAgdmFyIGN1cnJJbmNsdWRlcyA9IFtdO1xuICAgICAgICAgICAgICAgICAgICB2YXIgaW5jbHVkZU9wdHMgPSBbY3VyckluY2x1ZGVzXTtcbiAgICAgICAgICAgICAgICAgICAgdmFyIGN1cnJMZW5ndGggPSBlbmNvZGVVUklDb21wb25lbnQoJz9pbmNsdWRlPScpLmxlbmd0aDtcbiAgICAgICAgICAgICAgICAgICAgdmFyIHZhcmlhYmxlID0gaW5jbHVkZS5wb3AoKTtcbiAgICAgICAgICAgICAgICAgICAgd2hpbGUgKHZhcmlhYmxlKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICB2YXIgdmFyTGVuZ2h0ID0gZW5jb2RlVVJJQ29tcG9uZW50KHZhcmlhYmxlKS5sZW5ndGg7XG4gICAgICAgICAgICAgICAgICAgICAgICAvLyBVc2UgYSBncmVlZHkgYXBwcm9hY2ggZm9yIG5vdywgY2FuIGJlIG9wdGltaXplZCB0byBiZSBzb2x2ZWQgaW4gYSBtb3JlXG4gICAgICAgICAgICAgICAgICAgICAgICAvLyBlZmZpY2llbnQgd2F5XG4gICAgICAgICAgICAgICAgICAgICAgICAvLyArIDEgaXMgdGhlIGNvbW1hXG4gICAgICAgICAgICAgICAgICAgICAgICBpZiAoY3Vyckxlbmd0aCArIHZhckxlbmdodCArIDEgPCBkaWZmKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgY3VyckluY2x1ZGVzLnB1c2godmFyaWFibGUpO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGN1cnJMZW5ndGggKz0gdmFyTGVuZ2h0ICsgMTtcbiAgICAgICAgICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgY3VyckluY2x1ZGVzID0gW3ZhcmlhYmxlXTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBpbmNsdWRlT3B0cy5wdXNoKGN1cnJJbmNsdWRlcyk7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgY3Vyckxlbmd0aCA9ICc/aW5jbHVkZT0nLmxlbmd0aCArIHZhckxlbmdodDtcbiAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgICAgIHZhcmlhYmxlID0gaW5jbHVkZS5wb3AoKTtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICB2YXIgcmVxcyA9ICQubWFwKGluY2x1ZGVPcHRzLCBmdW5jdGlvbiAoaW5jbHVkZSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgdmFyIHJlcVBhcmFtcyA9ICQuZXh0ZW5kKHt9LCBwYXJhbXMsIHsgaW5jbHVkZTogaW5jbHVkZSB9KTtcbiAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybiBodHRwLmdldChyZXFQYXJhbXMsIG9wdGlvbnMpO1xuICAgICAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgICAgICAgJC53aGVuLmFwcGx5KCQsIHJlcXMpLnRoZW4oZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgICAgICAgICAgICAgLy8gRWFjaCBhcmd1bWVudCBhcmUgYXJyYXlzIG9mIHRoZSBhcmd1bWVudHMgb2YgZWFjaCBkb25lIHJlcXVlc3RcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIFNvIHRoZSBmaXJzdCBhcmd1bWVudCBvZiB0aGUgZmlyc3QgYXJyYXkgb2YgYXJndW1lbnRzIGlzIHRoZSBkYXRhXG4gICAgICAgICAgICAgICAgICAgICAgICB2YXIgaXNWYWxpZCA9IGFyZ3VtZW50c1swXSAmJiBhcmd1bWVudHNbMF1bMF07XG4gICAgICAgICAgICAgICAgICAgICAgICBpZiAoIWlzVmFsaWQpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBTaG91bGQgbmV2ZXIgaGFwcGVuLi4uXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgb2xkRXJyb3IoKTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICByZXR1cm4gZHRkLnJlamVjdCgpO1xuICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICAgICAgdmFyIGZpcnN0UmVzcG9uc2UgPSBhcmd1bWVudHNbMF1bMF07XG4gICAgICAgICAgICAgICAgICAgICAgICB2YXIgaXNPYmplY3QgPSAkLmlzUGxhaW5PYmplY3QoZmlyc3RSZXNwb25zZSk7XG4gICAgICAgICAgICAgICAgICAgICAgICB2YXIgaXNSdW5BUEkgPSAoaXNPYmplY3QgJiYgJC5pc1BsYWluT2JqZWN0KGZpcnN0UmVzcG9uc2UudmFyaWFibGVzKSkgfHwgIWlzT2JqZWN0O1xuICAgICAgICAgICAgICAgICAgICAgICAgaWYgKGlzUnVuQVBJKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgaWYgKGlzT2JqZWN0KSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIGFnZ3JlZ2F0ZSB0aGUgdmFyaWFibGVzIHByb3BlcnR5IG9ubHlcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdmFyIGFnZ3JlZ2F0ZVJ1biA9IGFyZ3VtZW50c1swXVswXTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJC5lYWNoKGFyZ3VtZW50cywgZnVuY3Rpb24gKGlkeCwgYXJncykge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdmFyIHJ1biA9IGFyZ3NbMF07XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAkLmV4dGVuZCh0cnVlLCBhZ2dyZWdhdGVSdW4udmFyaWFibGVzLCBydW4udmFyaWFibGVzKTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG9sZFN1Y2Nlc3MoYWdncmVnYXRlUnVuLCBhcmd1bWVudHNbMF1bMV0sIGFyZ3VtZW50c1swXVsyXSk7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGR0ZC5yZXNvbHZlKGFnZ3JlZ2F0ZVJ1biwgYXJndW1lbnRzWzBdWzFdLCBhcmd1bWVudHNbMF1bMl0pO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIGFycmF5IG9mIHJ1bnNcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gQWdyZWdhdGUgdmFyaWFibGVzIGluIGVhY2ggcnVuXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHZhciBhZ2dyZWdhdGVkUnVucyA9IHt9O1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAkLmVhY2goYXJndW1lbnRzLCBmdW5jdGlvbiAoaWR4LCBhcmdzKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB2YXIgcnVucyA9IGFyZ3NbMF07XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZiAoISQuaXNBcnJheShydW5zKSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICQuZWFjaChydW5zLCBmdW5jdGlvbiAoaWR4UnVuLCBydW4pIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZiAocnVuLmlkICYmICFhZ2dyZWdhdGVkUnVuc1tydW4uaWRdKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJ1bi52YXJpYWJsZXMgPSBydW4udmFyaWFibGVzIHx8IHt9O1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhZ2dyZWdhdGVkUnVuc1tydW4uaWRdID0gcnVuO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0gZWxzZSBpZiAocnVuLmlkKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICQuZXh0ZW5kKHRydWUsIGFnZ3JlZ2F0ZWRSdW5zW3J1bi5pZF0udmFyaWFibGVzLCBydW4udmFyaWFibGVzKTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIHR1cm4gaXQgaW50byBhbiBhcnJheVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhZ2dyZWdhdGVkUnVucyA9ICQubWFwKGFnZ3JlZ2F0ZWRSdW5zLCBmdW5jdGlvbiAocnVuKSB7IHJldHVybiBydW47IH0pO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBvbGRTdWNjZXNzKGFnZ3JlZ2F0ZWRSdW5zLCBhcmd1bWVudHNbMF1bMV0sIGFyZ3VtZW50c1swXVsyXSk7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGR0ZC5yZXNvbHZlKGFnZ3JlZ2F0ZWRSdW5zLCBhcmd1bWVudHNbMF1bMV0sIGFyZ3VtZW50c1swXVsyXSk7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBpcyB2YXJpYWJsZXMgQVBJXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gYWdncmVnYXRlIHRoZSByZXNwb25zZVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHZhciBhZ2dyZWdhdGVkVmFyaWFibGVzID0ge307XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgJC5lYWNoKGFyZ3VtZW50cywgZnVuY3Rpb24gKGlkeCwgYXJncykge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB2YXIgdmFycyA9IGFyZ3NbMF07XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICQuZXh0ZW5kKHRydWUsIGFnZ3JlZ2F0ZWRWYXJpYWJsZXMsIHZhcnMpO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIG9sZFN1Y2Nlc3MoYWdncmVnYXRlZFZhcmlhYmxlcywgYXJndW1lbnRzWzBdWzFdLCBhcmd1bWVudHNbMF1bMl0pO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGR0ZC5yZXNvbHZlKGFnZ3JlZ2F0ZWRWYXJpYWJsZXMsIGFyZ3VtZW50c1swXVsxXSwgYXJndW1lbnRzWzBdWzJdKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgfSwgZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgICAgICAgICAgICAgb2xkRXJyb3IuYXBwbHkoaHR0cCwgYXJndW1lbnRzKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIGR0ZC5yZWplY3QuYXBwbHkoZHRkLCBhcmd1bWVudHMpO1xuICAgICAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIGR0ZC5wcm9taXNlKCk7XG4gICAgICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIGh0dHAuZ2V0KHBhcmFtcywgb3B0aW9ucyk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfTtcbiAgICAgICAgfVxuICAgIH07XG59KCkpO1xuIl19 +======= +},{"./query-util":48}]},{},[6]) +//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIm5vZGVfbW9kdWxlcy9icm93c2VyLXBhY2svX3ByZWx1ZGUuanMiLCJub2RlX21vZHVsZXMvYmFzZTY0LWpzL2xpYi9iNjQuanMiLCJub2RlX21vZHVsZXMvYnVmZmVyL2luZGV4LmpzIiwibm9kZV9tb2R1bGVzL2llZWU3NTQvaW5kZXguanMiLCJub2RlX21vZHVsZXMvaXNhcnJheS9pbmRleC5qcyIsInNyYy9hcGktdmVyc2lvbi5qc29uIiwic3JjL2FwcC5qcyIsInNyYy9lbnYtbG9hZC5qcyIsInNyYy9tYW5hZ2Vycy9hdXRoLW1hbmFnZXIuanMiLCJzcmMvbWFuYWdlcnMvY2hhbm5lbC1tYW5hZ2VyLmpzIiwic3JjL21hbmFnZXJzL2VwaWNlbnRlci1jaGFubmVsLW1hbmFnZXIuanMiLCJzcmMvbWFuYWdlcnMva2V5LW5hbWVzLmpzIiwic3JjL21hbmFnZXJzL3J1bi1tYW5hZ2VyLmpzIiwic3JjL21hbmFnZXJzL3J1bi1zdHJhdGVnaWVzL2Fsd2F5cy1uZXctc3RyYXRlZ3kuanMiLCJzcmMvbWFuYWdlcnMvcnVuLXN0cmF0ZWdpZXMvY29uZGl0aW9uYWwtY3JlYXRpb24tc3RyYXRlZ3kuanMiLCJzcmMvbWFuYWdlcnMvcnVuLXN0cmF0ZWdpZXMvaWRlbnRpdHktc3RyYXRlZ3kuanMiLCJzcmMvbWFuYWdlcnMvcnVuLXN0cmF0ZWdpZXMvbXVsdGlwbGF5ZXItc3RyYXRlZ3kuanMiLCJzcmMvbWFuYWdlcnMvcnVuLXN0cmF0ZWdpZXMvbmV3LWlmLWluaXRpYWxpemVkLXN0cmF0ZWd5LmpzIiwic3JjL21hbmFnZXJzL3J1bi1zdHJhdGVnaWVzL25ldy1pZi1taXNzaW5nLXN0cmF0ZWd5LmpzIiwic3JjL21hbmFnZXJzL3J1bi1zdHJhdGVnaWVzL25ldy1pZi1wZXJzaXN0ZWQtc3RyYXRlZ3kuanMiLCJzcmMvbWFuYWdlcnMvcnVuLXN0cmF0ZWdpZXMvcGVyc2lzdGVudC1zaW5nbGUtcGxheWVyLXN0cmF0ZWd5LmpzIiwic3JjL21hbmFnZXJzL3J1bi1zdHJhdGVnaWVzL3N0cmF0ZWdpZXMtbWFwLmpzIiwic3JjL21hbmFnZXJzL3NjZW5hcmlvLW1hbmFnZXIuanMiLCJzcmMvbWFuYWdlcnMvc3BlY2lhbC1vcGVyYXRpb25zLmpzIiwic3JjL21hbmFnZXJzL3dvcmxkLW1hbmFnZXIuanMiLCJzcmMvc2VydmljZS9hZG1pbi1maWxlLXNlcnZpY2UuanMiLCJzcmMvc2VydmljZS9hc3NldC1hcGktYWRhcHRlci5qcyIsInNyYy9zZXJ2aWNlL2F1dGgtYXBpLXNlcnZpY2UuanMiLCJzcmMvc2VydmljZS9jaGFubmVsLXNlcnZpY2UuanMiLCJzcmMvc2VydmljZS9jb25maWd1cmF0aW9uLXNlcnZpY2UuanMiLCJzcmMvc2VydmljZS9kYXRhLWFwaS1zZXJ2aWNlLmpzIiwic3JjL3NlcnZpY2UvaW50cm9zcGVjdGlvbi1hcGktc2VydmljZS5qcyIsInNyYy9zZXJ2aWNlL21lbWJlci1hcGktYWRhcHRlci5qcyIsInNyYy9zZXJ2aWNlL3J1bi1hcGktc2VydmljZS5qcyIsInNyYy9zZXJ2aWNlL3N0YXRlLWFwaS1hZGFwdGVyLmpzIiwic3JjL3NlcnZpY2UvdXJsLWNvbmZpZy1zZXJ2aWNlLmpzIiwic3JjL3NlcnZpY2UvdXNlci1hcGktYWRhcHRlci5qcyIsInNyYy9zZXJ2aWNlL3ZhcmlhYmxlcy1hcGktc2VydmljZS5qcyIsInNyYy9zZXJ2aWNlL3dvcmxkLWFwaS1hZGFwdGVyLmpzIiwic3JjL3N0b3JlL2Nvb2tpZS1zdG9yZS5qcyIsInNyYy9zdG9yZS9zZXNzaW9uLW1hbmFnZXIuanMiLCJzcmMvc3RvcmUvc3RvcmUtZmFjdG9yeS5qcyIsInNyYy90cmFuc3BvcnQvYWpheC1odHRwLXRyYW5zcG9ydC5qcyIsInNyYy90cmFuc3BvcnQvaHR0cC10cmFuc3BvcnQtZmFjdG9yeS5qcyIsInNyYy91dGlsL2luaGVyaXQuanMiLCJzcmMvdXRpbC9tYWtlLXNlcXVlbmNlLmpzIiwic3JjL3V0aWwvb2JqZWN0LXV0aWwuanMiLCJzcmMvdXRpbC9vcHRpb24tdXRpbHMuanMiLCJzcmMvdXRpbC9xdWVyeS11dGlsLmpzIiwic3JjL3V0aWwvcnVuLXV0aWwuanMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7QUNBQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOzs7QUM3R0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7OztBQy9xREE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDcEZBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNMQTtBQUNBO0FBQ0E7QUFDQTs7O0FDSEE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7Ozs7QUNsRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUM1QkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUMvV0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNwUEE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDN1hBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNMQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDM0pBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDbkJBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ2xIQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNyQkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUMvRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ2pCQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDdkJBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNqQkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzVGQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNUQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ2pEQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDUkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUN6S0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQy9JQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUMxWEE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3ZIQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNwT0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDeEVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDblFBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDbEZBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUN6TEE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUM1ZkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzFIQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDNUZBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUMzSkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNuS0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDM3VCQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDNUlBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNyR0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNWQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDM0dBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ05BO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3REQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNqRkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ2RBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3ZDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ2hIQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSIsImZpbGUiOiJnZW5lcmF0ZWQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlc0NvbnRlbnQiOlsiKGZ1bmN0aW9uIGUodCxuLHIpe2Z1bmN0aW9uIHMobyx1KXtpZighbltvXSl7aWYoIXRbb10pe3ZhciBhPXR5cGVvZiByZXF1aXJlPT1cImZ1bmN0aW9uXCImJnJlcXVpcmU7aWYoIXUmJmEpcmV0dXJuIGEobywhMCk7aWYoaSlyZXR1cm4gaShvLCEwKTt2YXIgZj1uZXcgRXJyb3IoXCJDYW5ub3QgZmluZCBtb2R1bGUgJ1wiK28rXCInXCIpO3Rocm93IGYuY29kZT1cIk1PRFVMRV9OT1RfRk9VTkRcIixmfXZhciBsPW5bb109e2V4cG9ydHM6e319O3Rbb11bMF0uY2FsbChsLmV4cG9ydHMsZnVuY3Rpb24oZSl7dmFyIG49dFtvXVsxXVtlXTtyZXR1cm4gcyhuP246ZSl9LGwsbC5leHBvcnRzLGUsdCxuLHIpfXJldHVybiBuW29dLmV4cG9ydHN9dmFyIGk9dHlwZW9mIHJlcXVpcmU9PVwiZnVuY3Rpb25cIiYmcmVxdWlyZTtmb3IodmFyIG89MDtvPHIubGVuZ3RoO28rKylzKHJbb10pO3JldHVybiBzfSkiLCIndXNlIHN0cmljdCdcblxuZXhwb3J0cy50b0J5dGVBcnJheSA9IHRvQnl0ZUFycmF5XG5leHBvcnRzLmZyb21CeXRlQXJyYXkgPSBmcm9tQnl0ZUFycmF5XG5cbnZhciBsb29rdXAgPSBbXVxudmFyIHJldkxvb2t1cCA9IFtdXG52YXIgQXJyID0gdHlwZW9mIFVpbnQ4QXJyYXkgIT09ICd1bmRlZmluZWQnID8gVWludDhBcnJheSA6IEFycmF5XG5cbmZ1bmN0aW9uIGluaXQgKCkge1xuICB2YXIgY29kZSA9ICdBQkNERUZHSElKS0xNTk9QUVJTVFVWV1hZWmFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6MDEyMzQ1Njc4OSsvJ1xuICBmb3IgKHZhciBpID0gMCwgbGVuID0gY29kZS5sZW5ndGg7IGkgPCBsZW47ICsraSkge1xuICAgIGxvb2t1cFtpXSA9IGNvZGVbaV1cbiAgICByZXZMb29rdXBbY29kZS5jaGFyQ29kZUF0KGkpXSA9IGlcbiAgfVxuXG4gIHJldkxvb2t1cFsnLScuY2hhckNvZGVBdCgwKV0gPSA2MlxuICByZXZMb29rdXBbJ18nLmNoYXJDb2RlQXQoMCldID0gNjNcbn1cblxuaW5pdCgpXG5cbmZ1bmN0aW9uIHRvQnl0ZUFycmF5IChiNjQpIHtcbiAgdmFyIGksIGosIGwsIHRtcCwgcGxhY2VIb2xkZXJzLCBhcnJcbiAgdmFyIGxlbiA9IGI2NC5sZW5ndGhcblxuICBpZiAobGVuICUgNCA+IDApIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoJ0ludmFsaWQgc3RyaW5nLiBMZW5ndGggbXVzdCBiZSBhIG11bHRpcGxlIG9mIDQnKVxuICB9XG5cbiAgLy8gdGhlIG51bWJlciBvZiBlcXVhbCBzaWducyAocGxhY2UgaG9sZGVycylcbiAgLy8gaWYgdGhlcmUgYXJlIHR3byBwbGFjZWhvbGRlcnMsIHRoYW4gdGhlIHR3byBjaGFyYWN0ZXJzIGJlZm9yZSBpdFxuICAvLyByZXByZXNlbnQgb25lIGJ5dGVcbiAgLy8gaWYgdGhlcmUgaXMgb25seSBvbmUsIHRoZW4gdGhlIHRocmVlIGNoYXJhY3RlcnMgYmVmb3JlIGl0IHJlcHJlc2VudCAyIGJ5dGVzXG4gIC8vIHRoaXMgaXMganVzdCBhIGNoZWFwIGhhY2sgdG8gbm90IGRvIGluZGV4T2YgdHdpY2VcbiAgcGxhY2VIb2xkZXJzID0gYjY0W2xlbiAtIDJdID09PSAnPScgPyAyIDogYjY0W2xlbiAtIDFdID09PSAnPScgPyAxIDogMFxuXG4gIC8vIGJhc2U2NCBpcyA0LzMgKyB1cCB0byB0d28gY2hhcmFjdGVycyBvZiB0aGUgb3JpZ2luYWwgZGF0YVxuICBhcnIgPSBuZXcgQXJyKGxlbiAqIDMgLyA0IC0gcGxhY2VIb2xkZXJzKVxuXG4gIC8vIGlmIHRoZXJlIGFyZSBwbGFjZWhvbGRlcnMsIG9ubHkgZ2V0IHVwIHRvIHRoZSBsYXN0IGNvbXBsZXRlIDQgY2hhcnNcbiAgbCA9IHBsYWNlSG9sZGVycyA+IDAgPyBsZW4gLSA0IDogbGVuXG5cbiAgdmFyIEwgPSAwXG5cbiAgZm9yIChpID0gMCwgaiA9IDA7IGkgPCBsOyBpICs9IDQsIGogKz0gMykge1xuICAgIHRtcCA9IChyZXZMb29rdXBbYjY0LmNoYXJDb2RlQXQoaSldIDw8IDE4KSB8IChyZXZMb29rdXBbYjY0LmNoYXJDb2RlQXQoaSArIDEpXSA8PCAxMikgfCAocmV2TG9va3VwW2I2NC5jaGFyQ29kZUF0KGkgKyAyKV0gPDwgNikgfCByZXZMb29rdXBbYjY0LmNoYXJDb2RlQXQoaSArIDMpXVxuICAgIGFycltMKytdID0gKHRtcCA+PiAxNikgJiAweEZGXG4gICAgYXJyW0wrK10gPSAodG1wID4+IDgpICYgMHhGRlxuICAgIGFycltMKytdID0gdG1wICYgMHhGRlxuICB9XG5cbiAgaWYgKHBsYWNlSG9sZGVycyA9PT0gMikge1xuICAgIHRtcCA9IChyZXZMb29rdXBbYjY0LmNoYXJDb2RlQXQoaSldIDw8IDIpIHwgKHJldkxvb2t1cFtiNjQuY2hhckNvZGVBdChpICsgMSldID4+IDQpXG4gICAgYXJyW0wrK10gPSB0bXAgJiAweEZGXG4gIH0gZWxzZSBpZiAocGxhY2VIb2xkZXJzID09PSAxKSB7XG4gICAgdG1wID0gKHJldkxvb2t1cFtiNjQuY2hhckNvZGVBdChpKV0gPDwgMTApIHwgKHJldkxvb2t1cFtiNjQuY2hhckNvZGVBdChpICsgMSldIDw8IDQpIHwgKHJldkxvb2t1cFtiNjQuY2hhckNvZGVBdChpICsgMildID4+IDIpXG4gICAgYXJyW0wrK10gPSAodG1wID4+IDgpICYgMHhGRlxuICAgIGFycltMKytdID0gdG1wICYgMHhGRlxuICB9XG5cbiAgcmV0dXJuIGFyclxufVxuXG5mdW5jdGlvbiB0cmlwbGV0VG9CYXNlNjQgKG51bSkge1xuICByZXR1cm4gbG9va3VwW251bSA+PiAxOCAmIDB4M0ZdICsgbG9va3VwW251bSA+PiAxMiAmIDB4M0ZdICsgbG9va3VwW251bSA+PiA2ICYgMHgzRl0gKyBsb29rdXBbbnVtICYgMHgzRl1cbn1cblxuZnVuY3Rpb24gZW5jb2RlQ2h1bmsgKHVpbnQ4LCBzdGFydCwgZW5kKSB7XG4gIHZhciB0bXBcbiAgdmFyIG91dHB1dCA9IFtdXG4gIGZvciAodmFyIGkgPSBzdGFydDsgaSA8IGVuZDsgaSArPSAzKSB7XG4gICAgdG1wID0gKHVpbnQ4W2ldIDw8IDE2KSArICh1aW50OFtpICsgMV0gPDwgOCkgKyAodWludDhbaSArIDJdKVxuICAgIG91dHB1dC5wdXNoKHRyaXBsZXRUb0Jhc2U2NCh0bXApKVxuICB9XG4gIHJldHVybiBvdXRwdXQuam9pbignJylcbn1cblxuZnVuY3Rpb24gZnJvbUJ5dGVBcnJheSAodWludDgpIHtcbiAgdmFyIHRtcFxuICB2YXIgbGVuID0gdWludDgubGVuZ3RoXG4gIHZhciBleHRyYUJ5dGVzID0gbGVuICUgMyAvLyBpZiB3ZSBoYXZlIDEgYnl0ZSBsZWZ0LCBwYWQgMiBieXRlc1xuICB2YXIgb3V0cHV0ID0gJydcbiAgdmFyIHBhcnRzID0gW11cbiAgdmFyIG1heENodW5rTGVuZ3RoID0gMTYzODMgLy8gbXVzdCBiZSBtdWx0aXBsZSBvZiAzXG5cbiAgLy8gZ28gdGhyb3VnaCB0aGUgYXJyYXkgZXZlcnkgdGhyZWUgYnl0ZXMsIHdlJ2xsIGRlYWwgd2l0aCB0cmFpbGluZyBzdHVmZiBsYXRlclxuICBmb3IgKHZhciBpID0gMCwgbGVuMiA9IGxlbiAtIGV4dHJhQnl0ZXM7IGkgPCBsZW4yOyBpICs9IG1heENodW5rTGVuZ3RoKSB7XG4gICAgcGFydHMucHVzaChlbmNvZGVDaHVuayh1aW50OCwgaSwgKGkgKyBtYXhDaHVua0xlbmd0aCkgPiBsZW4yID8gbGVuMiA6IChpICsgbWF4Q2h1bmtMZW5ndGgpKSlcbiAgfVxuXG4gIC8vIHBhZCB0aGUgZW5kIHdpdGggemVyb3MsIGJ1dCBtYWtlIHN1cmUgdG8gbm90IGZvcmdldCB0aGUgZXh0cmEgYnl0ZXNcbiAgaWYgKGV4dHJhQnl0ZXMgPT09IDEpIHtcbiAgICB0bXAgPSB1aW50OFtsZW4gLSAxXVxuICAgIG91dHB1dCArPSBsb29rdXBbdG1wID4+IDJdXG4gICAgb3V0cHV0ICs9IGxvb2t1cFsodG1wIDw8IDQpICYgMHgzRl1cbiAgICBvdXRwdXQgKz0gJz09J1xuICB9IGVsc2UgaWYgKGV4dHJhQnl0ZXMgPT09IDIpIHtcbiAgICB0bXAgPSAodWludDhbbGVuIC0gMl0gPDwgOCkgKyAodWludDhbbGVuIC0gMV0pXG4gICAgb3V0cHV0ICs9IGxvb2t1cFt0bXAgPj4gMTBdXG4gICAgb3V0cHV0ICs9IGxvb2t1cFsodG1wID4+IDQpICYgMHgzRl1cbiAgICBvdXRwdXQgKz0gbG9va3VwWyh0bXAgPDwgMikgJiAweDNGXVxuICAgIG91dHB1dCArPSAnPSdcbiAgfVxuXG4gIHBhcnRzLnB1c2gob3V0cHV0KVxuXG4gIHJldHVybiBwYXJ0cy5qb2luKCcnKVxufVxuIiwiLyohXG4gKiBUaGUgYnVmZmVyIG1vZHVsZSBmcm9tIG5vZGUuanMsIGZvciB0aGUgYnJvd3Nlci5cbiAqXG4gKiBAYXV0aG9yICAgRmVyb3NzIEFib3VraGFkaWplaCA8ZmVyb3NzQGZlcm9zcy5vcmc+IDxodHRwOi8vZmVyb3NzLm9yZz5cbiAqIEBsaWNlbnNlICBNSVRcbiAqL1xuLyogZXNsaW50LWRpc2FibGUgbm8tcHJvdG8gKi9cblxuJ3VzZSBzdHJpY3QnXG5cbnZhciBiYXNlNjQgPSByZXF1aXJlKCdiYXNlNjQtanMnKVxudmFyIGllZWU3NTQgPSByZXF1aXJlKCdpZWVlNzU0JylcbnZhciBpc0FycmF5ID0gcmVxdWlyZSgnaXNhcnJheScpXG5cbmV4cG9ydHMuQnVmZmVyID0gQnVmZmVyXG5leHBvcnRzLlNsb3dCdWZmZXIgPSBTbG93QnVmZmVyXG5leHBvcnRzLklOU1BFQ1RfTUFYX0JZVEVTID0gNTBcblxuLyoqXG4gKiBJZiBgQnVmZmVyLlRZUEVEX0FSUkFZX1NVUFBPUlRgOlxuICogICA9PT0gdHJ1ZSAgICBVc2UgVWludDhBcnJheSBpbXBsZW1lbnRhdGlvbiAoZmFzdGVzdClcbiAqICAgPT09IGZhbHNlICAgVXNlIE9iamVjdCBpbXBsZW1lbnRhdGlvbiAobW9zdCBjb21wYXRpYmxlLCBldmVuIElFNilcbiAqXG4gKiBCcm93c2VycyB0aGF0IHN1cHBvcnQgdHlwZWQgYXJyYXlzIGFyZSBJRSAxMCssIEZpcmVmb3ggNCssIENocm9tZSA3KywgU2FmYXJpIDUuMSssXG4gKiBPcGVyYSAxMS42KywgaU9TIDQuMisuXG4gKlxuICogRHVlIHRvIHZhcmlvdXMgYnJvd3NlciBidWdzLCBzb21ldGltZXMgdGhlIE9iamVjdCBpbXBsZW1lbnRhdGlvbiB3aWxsIGJlIHVzZWQgZXZlblxuICogd2hlbiB0aGUgYnJvd3NlciBzdXBwb3J0cyB0eXBlZCBhcnJheXMuXG4gKlxuICogTm90ZTpcbiAqXG4gKiAgIC0gRmlyZWZveCA0LTI5IGxhY2tzIHN1cHBvcnQgZm9yIGFkZGluZyBuZXcgcHJvcGVydGllcyB0byBgVWludDhBcnJheWAgaW5zdGFuY2VzLFxuICogICAgIFNlZTogaHR0cHM6Ly9idWd6aWxsYS5tb3ppbGxhLm9yZy9zaG93X2J1Zy5jZ2k/aWQ9Njk1NDM4LlxuICpcbiAqICAgLSBDaHJvbWUgOS0xMCBpcyBtaXNzaW5nIHRoZSBgVHlwZWRBcnJheS5wcm90b3R5cGUuc3ViYXJyYXlgIGZ1bmN0aW9uLlxuICpcbiAqICAgLSBJRTEwIGhhcyBhIGJyb2tlbiBgVHlwZWRBcnJheS5wcm90b3R5cGUuc3ViYXJyYXlgIGZ1bmN0aW9uIHdoaWNoIHJldHVybnMgYXJyYXlzIG9mXG4gKiAgICAgaW5jb3JyZWN0IGxlbmd0aCBpbiBzb21lIHNpdHVhdGlvbnMuXG5cbiAqIFdlIGRldGVjdCB0aGVzZSBidWdneSBicm93c2VycyBhbmQgc2V0IGBCdWZmZXIuVFlQRURfQVJSQVlfU1VQUE9SVGAgdG8gYGZhbHNlYCBzbyB0aGV5XG4gKiBnZXQgdGhlIE9iamVjdCBpbXBsZW1lbnRhdGlvbiwgd2hpY2ggaXMgc2xvd2VyIGJ1dCBiZWhhdmVzIGNvcnJlY3RseS5cbiAqL1xuQnVmZmVyLlRZUEVEX0FSUkFZX1NVUFBPUlQgPSBnbG9iYWwuVFlQRURfQVJSQVlfU1VQUE9SVCAhPT0gdW5kZWZpbmVkXG4gID8gZ2xvYmFsLlRZUEVEX0FSUkFZX1NVUFBPUlRcbiAgOiB0eXBlZEFycmF5U3VwcG9ydCgpXG5cbi8qXG4gKiBFeHBvcnQga01heExlbmd0aCBhZnRlciB0eXBlZCBhcnJheSBzdXBwb3J0IGlzIGRldGVybWluZWQuXG4gKi9cbmV4cG9ydHMua01heExlbmd0aCA9IGtNYXhMZW5ndGgoKVxuXG5mdW5jdGlvbiB0eXBlZEFycmF5U3VwcG9ydCAoKSB7XG4gIHRyeSB7XG4gICAgdmFyIGFyciA9IG5ldyBVaW50OEFycmF5KDEpXG4gICAgYXJyLl9fcHJvdG9fXyA9IHtfX3Byb3RvX186IFVpbnQ4QXJyYXkucHJvdG90eXBlLCBmb286IGZ1bmN0aW9uICgpIHsgcmV0dXJuIDQyIH19XG4gICAgcmV0dXJuIGFyci5mb28oKSA9PT0gNDIgJiYgLy8gdHlwZWQgYXJyYXkgaW5zdGFuY2VzIGNhbiBiZSBhdWdtZW50ZWRcbiAgICAgICAgdHlwZW9mIGFyci5zdWJhcnJheSA9PT0gJ2Z1bmN0aW9uJyAmJiAvLyBjaHJvbWUgOS0xMCBsYWNrIGBzdWJhcnJheWBcbiAgICAgICAgYXJyLnN1YmFycmF5KDEsIDEpLmJ5dGVMZW5ndGggPT09IDAgLy8gaWUxMCBoYXMgYnJva2VuIGBzdWJhcnJheWBcbiAgfSBjYXRjaCAoZSkge1xuICAgIHJldHVybiBmYWxzZVxuICB9XG59XG5cbmZ1bmN0aW9uIGtNYXhMZW5ndGggKCkge1xuICByZXR1cm4gQnVmZmVyLlRZUEVEX0FSUkFZX1NVUFBPUlRcbiAgICA/IDB4N2ZmZmZmZmZcbiAgICA6IDB4M2ZmZmZmZmZcbn1cblxuZnVuY3Rpb24gY3JlYXRlQnVmZmVyICh0aGF0LCBsZW5ndGgpIHtcbiAgaWYgKGtNYXhMZW5ndGgoKSA8IGxlbmd0aCkge1xuICAgIHRocm93IG5ldyBSYW5nZUVycm9yKCdJbnZhbGlkIHR5cGVkIGFycmF5IGxlbmd0aCcpXG4gIH1cbiAgaWYgKEJ1ZmZlci5UWVBFRF9BUlJBWV9TVVBQT1JUKSB7XG4gICAgLy8gUmV0dXJuIGFuIGF1Z21lbnRlZCBgVWludDhBcnJheWAgaW5zdGFuY2UsIGZvciBiZXN0IHBlcmZvcm1hbmNlXG4gICAgdGhhdCA9IG5ldyBVaW50OEFycmF5KGxlbmd0aClcbiAgICB0aGF0Ll9fcHJvdG9fXyA9IEJ1ZmZlci5wcm90b3R5cGVcbiAgfSBlbHNlIHtcbiAgICAvLyBGYWxsYmFjazogUmV0dXJuIGFuIG9iamVjdCBpbnN0YW5jZSBvZiB0aGUgQnVmZmVyIGNsYXNzXG4gICAgaWYgKHRoYXQgPT09IG51bGwpIHtcbiAgICAgIHRoYXQgPSBuZXcgQnVmZmVyKGxlbmd0aClcbiAgICB9XG4gICAgdGhhdC5sZW5ndGggPSBsZW5ndGhcbiAgfVxuXG4gIHJldHVybiB0aGF0XG59XG5cbi8qKlxuICogVGhlIEJ1ZmZlciBjb25zdHJ1Y3RvciByZXR1cm5zIGluc3RhbmNlcyBvZiBgVWludDhBcnJheWAgdGhhdCBoYXZlIHRoZWlyXG4gKiBwcm90b3R5cGUgY2hhbmdlZCB0byBgQnVmZmVyLnByb3RvdHlwZWAuIEZ1cnRoZXJtb3JlLCBgQnVmZmVyYCBpcyBhIHN1YmNsYXNzIG9mXG4gKiBgVWludDhBcnJheWAsIHNvIHRoZSByZXR1cm5lZCBpbnN0YW5jZXMgd2lsbCBoYXZlIGFsbCB0aGUgbm9kZSBgQnVmZmVyYCBtZXRob2RzXG4gKiBhbmQgdGhlIGBVaW50OEFycmF5YCBtZXRob2RzLiBTcXVhcmUgYnJhY2tldCBub3RhdGlvbiB3b3JrcyBhcyBleHBlY3RlZCAtLSBpdFxuICogcmV0dXJucyBhIHNpbmdsZSBvY3RldC5cbiAqXG4gKiBUaGUgYFVpbnQ4QXJyYXlgIHByb3RvdHlwZSByZW1haW5zIHVubW9kaWZpZWQuXG4gKi9cblxuZnVuY3Rpb24gQnVmZmVyIChhcmcsIGVuY29kaW5nT3JPZmZzZXQsIGxlbmd0aCkge1xuICBpZiAoIUJ1ZmZlci5UWVBFRF9BUlJBWV9TVVBQT1JUICYmICEodGhpcyBpbnN0YW5jZW9mIEJ1ZmZlcikpIHtcbiAgICByZXR1cm4gbmV3IEJ1ZmZlcihhcmcsIGVuY29kaW5nT3JPZmZzZXQsIGxlbmd0aClcbiAgfVxuXG4gIC8vIENvbW1vbiBjYXNlLlxuICBpZiAodHlwZW9mIGFyZyA9PT0gJ251bWJlcicpIHtcbiAgICBpZiAodHlwZW9mIGVuY29kaW5nT3JPZmZzZXQgPT09ICdzdHJpbmcnKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoXG4gICAgICAgICdJZiBlbmNvZGluZyBpcyBzcGVjaWZpZWQgdGhlbiB0aGUgZmlyc3QgYXJndW1lbnQgbXVzdCBiZSBhIHN0cmluZydcbiAgICAgIClcbiAgICB9XG4gICAgcmV0dXJuIGFsbG9jVW5zYWZlKHRoaXMsIGFyZylcbiAgfVxuICByZXR1cm4gZnJvbSh0aGlzLCBhcmcsIGVuY29kaW5nT3JPZmZzZXQsIGxlbmd0aClcbn1cblxuQnVmZmVyLnBvb2xTaXplID0gODE5MiAvLyBub3QgdXNlZCBieSB0aGlzIGltcGxlbWVudGF0aW9uXG5cbi8vIFRPRE86IExlZ2FjeSwgbm90IG5lZWRlZCBhbnltb3JlLiBSZW1vdmUgaW4gbmV4dCBtYWpvciB2ZXJzaW9uLlxuQnVmZmVyLl9hdWdtZW50ID0gZnVuY3Rpb24gKGFycikge1xuICBhcnIuX19wcm90b19fID0gQnVmZmVyLnByb3RvdHlwZVxuICByZXR1cm4gYXJyXG59XG5cbmZ1bmN0aW9uIGZyb20gKHRoYXQsIHZhbHVlLCBlbmNvZGluZ09yT2Zmc2V0LCBsZW5ndGgpIHtcbiAgaWYgKHR5cGVvZiB2YWx1ZSA9PT0gJ251bWJlcicpIHtcbiAgICB0aHJvdyBuZXcgVHlwZUVycm9yKCdcInZhbHVlXCIgYXJndW1lbnQgbXVzdCBub3QgYmUgYSBudW1iZXInKVxuICB9XG5cbiAgaWYgKHR5cGVvZiBBcnJheUJ1ZmZlciAhPT0gJ3VuZGVmaW5lZCcgJiYgdmFsdWUgaW5zdGFuY2VvZiBBcnJheUJ1ZmZlcikge1xuICAgIHJldHVybiBmcm9tQXJyYXlCdWZmZXIodGhhdCwgdmFsdWUsIGVuY29kaW5nT3JPZmZzZXQsIGxlbmd0aClcbiAgfVxuXG4gIGlmICh0eXBlb2YgdmFsdWUgPT09ICdzdHJpbmcnKSB7XG4gICAgcmV0dXJuIGZyb21TdHJpbmcodGhhdCwgdmFsdWUsIGVuY29kaW5nT3JPZmZzZXQpXG4gIH1cblxuICByZXR1cm4gZnJvbU9iamVjdCh0aGF0LCB2YWx1ZSlcbn1cblxuLyoqXG4gKiBGdW5jdGlvbmFsbHkgZXF1aXZhbGVudCB0byBCdWZmZXIoYXJnLCBlbmNvZGluZykgYnV0IHRocm93cyBhIFR5cGVFcnJvclxuICogaWYgdmFsdWUgaXMgYSBudW1iZXIuXG4gKiBCdWZmZXIuZnJvbShzdHJbLCBlbmNvZGluZ10pXG4gKiBCdWZmZXIuZnJvbShhcnJheSlcbiAqIEJ1ZmZlci5mcm9tKGJ1ZmZlcilcbiAqIEJ1ZmZlci5mcm9tKGFycmF5QnVmZmVyWywgYnl0ZU9mZnNldFssIGxlbmd0aF1dKVxuICoqL1xuQnVmZmVyLmZyb20gPSBmdW5jdGlvbiAodmFsdWUsIGVuY29kaW5nT3JPZmZzZXQsIGxlbmd0aCkge1xuICByZXR1cm4gZnJvbShudWxsLCB2YWx1ZSwgZW5jb2RpbmdPck9mZnNldCwgbGVuZ3RoKVxufVxuXG5pZiAoQnVmZmVyLlRZUEVEX0FSUkFZX1NVUFBPUlQpIHtcbiAgQnVmZmVyLnByb3RvdHlwZS5fX3Byb3RvX18gPSBVaW50OEFycmF5LnByb3RvdHlwZVxuICBCdWZmZXIuX19wcm90b19fID0gVWludDhBcnJheVxuICBpZiAodHlwZW9mIFN5bWJvbCAhPT0gJ3VuZGVmaW5lZCcgJiYgU3ltYm9sLnNwZWNpZXMgJiZcbiAgICAgIEJ1ZmZlcltTeW1ib2wuc3BlY2llc10gPT09IEJ1ZmZlcikge1xuICAgIC8vIEZpeCBzdWJhcnJheSgpIGluIEVTMjAxNi4gU2VlOiBodHRwczovL2dpdGh1Yi5jb20vZmVyb3NzL2J1ZmZlci9wdWxsLzk3XG4gICAgT2JqZWN0LmRlZmluZVByb3BlcnR5KEJ1ZmZlciwgU3ltYm9sLnNwZWNpZXMsIHtcbiAgICAgIHZhbHVlOiBudWxsLFxuICAgICAgY29uZmlndXJhYmxlOiB0cnVlXG4gICAgfSlcbiAgfVxufVxuXG5mdW5jdGlvbiBhc3NlcnRTaXplIChzaXplKSB7XG4gIGlmICh0eXBlb2Ygc2l6ZSAhPT0gJ251bWJlcicpIHtcbiAgICB0aHJvdyBuZXcgVHlwZUVycm9yKCdcInNpemVcIiBhcmd1bWVudCBtdXN0IGJlIGEgbnVtYmVyJylcbiAgfVxufVxuXG5mdW5jdGlvbiBhbGxvYyAodGhhdCwgc2l6ZSwgZmlsbCwgZW5jb2RpbmcpIHtcbiAgYXNzZXJ0U2l6ZShzaXplKVxuICBpZiAoc2l6ZSA8PSAwKSB7XG4gICAgcmV0dXJuIGNyZWF0ZUJ1ZmZlcih0aGF0LCBzaXplKVxuICB9XG4gIGlmIChmaWxsICE9PSB1bmRlZmluZWQpIHtcbiAgICAvLyBPbmx5IHBheSBhdHRlbnRpb24gdG8gZW5jb2RpbmcgaWYgaXQncyBhIHN0cmluZy4gVGhpc1xuICAgIC8vIHByZXZlbnRzIGFjY2lkZW50YWxseSBzZW5kaW5nIGluIGEgbnVtYmVyIHRoYXQgd291bGRcbiAgICAvLyBiZSBpbnRlcnByZXR0ZWQgYXMgYSBzdGFydCBvZmZzZXQuXG4gICAgcmV0dXJuIHR5cGVvZiBlbmNvZGluZyA9PT0gJ3N0cmluZydcbiAgICAgID8gY3JlYXRlQnVmZmVyKHRoYXQsIHNpemUpLmZpbGwoZmlsbCwgZW5jb2RpbmcpXG4gICAgICA6IGNyZWF0ZUJ1ZmZlcih0aGF0LCBzaXplKS5maWxsKGZpbGwpXG4gIH1cbiAgcmV0dXJuIGNyZWF0ZUJ1ZmZlcih0aGF0LCBzaXplKVxufVxuXG4vKipcbiAqIENyZWF0ZXMgYSBuZXcgZmlsbGVkIEJ1ZmZlciBpbnN0YW5jZS5cbiAqIGFsbG9jKHNpemVbLCBmaWxsWywgZW5jb2RpbmddXSlcbiAqKi9cbkJ1ZmZlci5hbGxvYyA9IGZ1bmN0aW9uIChzaXplLCBmaWxsLCBlbmNvZGluZykge1xuICByZXR1cm4gYWxsb2MobnVsbCwgc2l6ZSwgZmlsbCwgZW5jb2RpbmcpXG59XG5cbmZ1bmN0aW9uIGFsbG9jVW5zYWZlICh0aGF0LCBzaXplKSB7XG4gIGFzc2VydFNpemUoc2l6ZSlcbiAgdGhhdCA9IGNyZWF0ZUJ1ZmZlcih0aGF0LCBzaXplIDwgMCA/IDAgOiBjaGVja2VkKHNpemUpIHwgMClcbiAgaWYgKCFCdWZmZXIuVFlQRURfQVJSQVlfU1VQUE9SVCkge1xuICAgIGZvciAodmFyIGkgPSAwOyBpIDwgc2l6ZTsgKytpKSB7XG4gICAgICB0aGF0W2ldID0gMFxuICAgIH1cbiAgfVxuICByZXR1cm4gdGhhdFxufVxuXG4vKipcbiAqIEVxdWl2YWxlbnQgdG8gQnVmZmVyKG51bSksIGJ5IGRlZmF1bHQgY3JlYXRlcyBhIG5vbi16ZXJvLWZpbGxlZCBCdWZmZXIgaW5zdGFuY2UuXG4gKiAqL1xuQnVmZmVyLmFsbG9jVW5zYWZlID0gZnVuY3Rpb24gKHNpemUpIHtcbiAgcmV0dXJuIGFsbG9jVW5zYWZlKG51bGwsIHNpemUpXG59XG4vKipcbiAqIEVxdWl2YWxlbnQgdG8gU2xvd0J1ZmZlcihudW0pLCBieSBkZWZhdWx0IGNyZWF0ZXMgYSBub24temVyby1maWxsZWQgQnVmZmVyIGluc3RhbmNlLlxuICovXG5CdWZmZXIuYWxsb2NVbnNhZmVTbG93ID0gZnVuY3Rpb24gKHNpemUpIHtcbiAgcmV0dXJuIGFsbG9jVW5zYWZlKG51bGwsIHNpemUpXG59XG5cbmZ1bmN0aW9uIGZyb21TdHJpbmcgKHRoYXQsIHN0cmluZywgZW5jb2RpbmcpIHtcbiAgaWYgKHR5cGVvZiBlbmNvZGluZyAhPT0gJ3N0cmluZycgfHwgZW5jb2RpbmcgPT09ICcnKSB7XG4gICAgZW5jb2RpbmcgPSAndXRmOCdcbiAgfVxuXG4gIGlmICghQnVmZmVyLmlzRW5jb2RpbmcoZW5jb2RpbmcpKSB7XG4gICAgdGhyb3cgbmV3IFR5cGVFcnJvcignXCJlbmNvZGluZ1wiIG11c3QgYmUgYSB2YWxpZCBzdHJpbmcgZW5jb2RpbmcnKVxuICB9XG5cbiAgdmFyIGxlbmd0aCA9IGJ5dGVMZW5ndGgoc3RyaW5nLCBlbmNvZGluZykgfCAwXG4gIHRoYXQgPSBjcmVhdGVCdWZmZXIodGhhdCwgbGVuZ3RoKVxuXG4gIHRoYXQud3JpdGUoc3RyaW5nLCBlbmNvZGluZylcbiAgcmV0dXJuIHRoYXRcbn1cblxuZnVuY3Rpb24gZnJvbUFycmF5TGlrZSAodGhhdCwgYXJyYXkpIHtcbiAgdmFyIGxlbmd0aCA9IGNoZWNrZWQoYXJyYXkubGVuZ3RoKSB8IDBcbiAgdGhhdCA9IGNyZWF0ZUJ1ZmZlcih0aGF0LCBsZW5ndGgpXG4gIGZvciAodmFyIGkgPSAwOyBpIDwgbGVuZ3RoOyBpICs9IDEpIHtcbiAgICB0aGF0W2ldID0gYXJyYXlbaV0gJiAyNTVcbiAgfVxuICByZXR1cm4gdGhhdFxufVxuXG5mdW5jdGlvbiBmcm9tQXJyYXlCdWZmZXIgKHRoYXQsIGFycmF5LCBieXRlT2Zmc2V0LCBsZW5ndGgpIHtcbiAgYXJyYXkuYnl0ZUxlbmd0aCAvLyB0aGlzIHRocm93cyBpZiBgYXJyYXlgIGlzIG5vdCBhIHZhbGlkIEFycmF5QnVmZmVyXG5cbiAgaWYgKGJ5dGVPZmZzZXQgPCAwIHx8IGFycmF5LmJ5dGVMZW5ndGggPCBieXRlT2Zmc2V0KSB7XG4gICAgdGhyb3cgbmV3IFJhbmdlRXJyb3IoJ1xcJ29mZnNldFxcJyBpcyBvdXQgb2YgYm91bmRzJylcbiAgfVxuXG4gIGlmIChhcnJheS5ieXRlTGVuZ3RoIDwgYnl0ZU9mZnNldCArIChsZW5ndGggfHwgMCkpIHtcbiAgICB0aHJvdyBuZXcgUmFuZ2VFcnJvcignXFwnbGVuZ3RoXFwnIGlzIG91dCBvZiBib3VuZHMnKVxuICB9XG5cbiAgaWYgKGxlbmd0aCA9PT0gdW5kZWZpbmVkKSB7XG4gICAgYXJyYXkgPSBuZXcgVWludDhBcnJheShhcnJheSwgYnl0ZU9mZnNldClcbiAgfSBlbHNlIHtcbiAgICBhcnJheSA9IG5ldyBVaW50OEFycmF5KGFycmF5LCBieXRlT2Zmc2V0LCBsZW5ndGgpXG4gIH1cblxuICBpZiAoQnVmZmVyLlRZUEVEX0FSUkFZX1NVUFBPUlQpIHtcbiAgICAvLyBSZXR1cm4gYW4gYXVnbWVudGVkIGBVaW50OEFycmF5YCBpbnN0YW5jZSwgZm9yIGJlc3QgcGVyZm9ybWFuY2VcbiAgICB0aGF0ID0gYXJyYXlcbiAgICB0aGF0Ll9fcHJvdG9fXyA9IEJ1ZmZlci5wcm90b3R5cGVcbiAgfSBlbHNlIHtcbiAgICAvLyBGYWxsYmFjazogUmV0dXJuIGFuIG9iamVjdCBpbnN0YW5jZSBvZiB0aGUgQnVmZmVyIGNsYXNzXG4gICAgdGhhdCA9IGZyb21BcnJheUxpa2UodGhhdCwgYXJyYXkpXG4gIH1cbiAgcmV0dXJuIHRoYXRcbn1cblxuZnVuY3Rpb24gZnJvbU9iamVjdCAodGhhdCwgb2JqKSB7XG4gIGlmIChCdWZmZXIuaXNCdWZmZXIob2JqKSkge1xuICAgIHZhciBsZW4gPSBjaGVja2VkKG9iai5sZW5ndGgpIHwgMFxuICAgIHRoYXQgPSBjcmVhdGVCdWZmZXIodGhhdCwgbGVuKVxuXG4gICAgaWYgKHRoYXQubGVuZ3RoID09PSAwKSB7XG4gICAgICByZXR1cm4gdGhhdFxuICAgIH1cblxuICAgIG9iai5jb3B5KHRoYXQsIDAsIDAsIGxlbilcbiAgICByZXR1cm4gdGhhdFxuICB9XG5cbiAgaWYgKG9iaikge1xuICAgIGlmICgodHlwZW9mIEFycmF5QnVmZmVyICE9PSAndW5kZWZpbmVkJyAmJlxuICAgICAgICBvYmouYnVmZmVyIGluc3RhbmNlb2YgQXJyYXlCdWZmZXIpIHx8ICdsZW5ndGgnIGluIG9iaikge1xuICAgICAgaWYgKHR5cGVvZiBvYmoubGVuZ3RoICE9PSAnbnVtYmVyJyB8fCBpc25hbihvYmoubGVuZ3RoKSkge1xuICAgICAgICByZXR1cm4gY3JlYXRlQnVmZmVyKHRoYXQsIDApXG4gICAgICB9XG4gICAgICByZXR1cm4gZnJvbUFycmF5TGlrZSh0aGF0LCBvYmopXG4gICAgfVxuXG4gICAgaWYgKG9iai50eXBlID09PSAnQnVmZmVyJyAmJiBpc0FycmF5KG9iai5kYXRhKSkge1xuICAgICAgcmV0dXJuIGZyb21BcnJheUxpa2UodGhhdCwgb2JqLmRhdGEpXG4gICAgfVxuICB9XG5cbiAgdGhyb3cgbmV3IFR5cGVFcnJvcignRmlyc3QgYXJndW1lbnQgbXVzdCBiZSBhIHN0cmluZywgQnVmZmVyLCBBcnJheUJ1ZmZlciwgQXJyYXksIG9yIGFycmF5LWxpa2Ugb2JqZWN0LicpXG59XG5cbmZ1bmN0aW9uIGNoZWNrZWQgKGxlbmd0aCkge1xuICAvLyBOb3RlOiBjYW5ub3QgdXNlIGBsZW5ndGggPCBrTWF4TGVuZ3RoYCBoZXJlIGJlY2F1c2UgdGhhdCBmYWlscyB3aGVuXG4gIC8vIGxlbmd0aCBpcyBOYU4gKHdoaWNoIGlzIG90aGVyd2lzZSBjb2VyY2VkIHRvIHplcm8uKVxuICBpZiAobGVuZ3RoID49IGtNYXhMZW5ndGgoKSkge1xuICAgIHRocm93IG5ldyBSYW5nZUVycm9yKCdBdHRlbXB0IHRvIGFsbG9jYXRlIEJ1ZmZlciBsYXJnZXIgdGhhbiBtYXhpbXVtICcgK1xuICAgICAgICAgICAgICAgICAgICAgICAgICdzaXplOiAweCcgKyBrTWF4TGVuZ3RoKCkudG9TdHJpbmcoMTYpICsgJyBieXRlcycpXG4gIH1cbiAgcmV0dXJuIGxlbmd0aCB8IDBcbn1cblxuZnVuY3Rpb24gU2xvd0J1ZmZlciAobGVuZ3RoKSB7XG4gIGlmICgrbGVuZ3RoICE9IGxlbmd0aCkgeyAvLyBlc2xpbnQtZGlzYWJsZS1saW5lIGVxZXFlcVxuICAgIGxlbmd0aCA9IDBcbiAgfVxuICByZXR1cm4gQnVmZmVyLmFsbG9jKCtsZW5ndGgpXG59XG5cbkJ1ZmZlci5pc0J1ZmZlciA9IGZ1bmN0aW9uIGlzQnVmZmVyIChiKSB7XG4gIHJldHVybiAhIShiICE9IG51bGwgJiYgYi5faXNCdWZmZXIpXG59XG5cbkJ1ZmZlci5jb21wYXJlID0gZnVuY3Rpb24gY29tcGFyZSAoYSwgYikge1xuICBpZiAoIUJ1ZmZlci5pc0J1ZmZlcihhKSB8fCAhQnVmZmVyLmlzQnVmZmVyKGIpKSB7XG4gICAgdGhyb3cgbmV3IFR5cGVFcnJvcignQXJndW1lbnRzIG11c3QgYmUgQnVmZmVycycpXG4gIH1cblxuICBpZiAoYSA9PT0gYikgcmV0dXJuIDBcblxuICB2YXIgeCA9IGEubGVuZ3RoXG4gIHZhciB5ID0gYi5sZW5ndGhcblxuICBmb3IgKHZhciBpID0gMCwgbGVuID0gTWF0aC5taW4oeCwgeSk7IGkgPCBsZW47ICsraSkge1xuICAgIGlmIChhW2ldICE9PSBiW2ldKSB7XG4gICAgICB4ID0gYVtpXVxuICAgICAgeSA9IGJbaV1cbiAgICAgIGJyZWFrXG4gICAgfVxuICB9XG5cbiAgaWYgKHggPCB5KSByZXR1cm4gLTFcbiAgaWYgKHkgPCB4KSByZXR1cm4gMVxuICByZXR1cm4gMFxufVxuXG5CdWZmZXIuaXNFbmNvZGluZyA9IGZ1bmN0aW9uIGlzRW5jb2RpbmcgKGVuY29kaW5nKSB7XG4gIHN3aXRjaCAoU3RyaW5nKGVuY29kaW5nKS50b0xvd2VyQ2FzZSgpKSB7XG4gICAgY2FzZSAnaGV4JzpcbiAgICBjYXNlICd1dGY4JzpcbiAgICBjYXNlICd1dGYtOCc6XG4gICAgY2FzZSAnYXNjaWknOlxuICAgIGNhc2UgJ2JpbmFyeSc6XG4gICAgY2FzZSAnYmFzZTY0JzpcbiAgICBjYXNlICdyYXcnOlxuICAgIGNhc2UgJ3VjczInOlxuICAgIGNhc2UgJ3Vjcy0yJzpcbiAgICBjYXNlICd1dGYxNmxlJzpcbiAgICBjYXNlICd1dGYtMTZsZSc6XG4gICAgICByZXR1cm4gdHJ1ZVxuICAgIGRlZmF1bHQ6XG4gICAgICByZXR1cm4gZmFsc2VcbiAgfVxufVxuXG5CdWZmZXIuY29uY2F0ID0gZnVuY3Rpb24gY29uY2F0IChsaXN0LCBsZW5ndGgpIHtcbiAgaWYgKCFpc0FycmF5KGxpc3QpKSB7XG4gICAgdGhyb3cgbmV3IFR5cGVFcnJvcignXCJsaXN0XCIgYXJndW1lbnQgbXVzdCBiZSBhbiBBcnJheSBvZiBCdWZmZXJzJylcbiAgfVxuXG4gIGlmIChsaXN0Lmxlbmd0aCA9PT0gMCkge1xuICAgIHJldHVybiBCdWZmZXIuYWxsb2MoMClcbiAgfVxuXG4gIHZhciBpXG4gIGlmIChsZW5ndGggPT09IHVuZGVmaW5lZCkge1xuICAgIGxlbmd0aCA9IDBcbiAgICBmb3IgKGkgPSAwOyBpIDwgbGlzdC5sZW5ndGg7ICsraSkge1xuICAgICAgbGVuZ3RoICs9IGxpc3RbaV0ubGVuZ3RoXG4gICAgfVxuICB9XG5cbiAgdmFyIGJ1ZmZlciA9IEJ1ZmZlci5hbGxvY1Vuc2FmZShsZW5ndGgpXG4gIHZhciBwb3MgPSAwXG4gIGZvciAoaSA9IDA7IGkgPCBsaXN0Lmxlbmd0aDsgKytpKSB7XG4gICAgdmFyIGJ1ZiA9IGxpc3RbaV1cbiAgICBpZiAoIUJ1ZmZlci5pc0J1ZmZlcihidWYpKSB7XG4gICAgICB0aHJvdyBuZXcgVHlwZUVycm9yKCdcImxpc3RcIiBhcmd1bWVudCBtdXN0IGJlIGFuIEFycmF5IG9mIEJ1ZmZlcnMnKVxuICAgIH1cbiAgICBidWYuY29weShidWZmZXIsIHBvcylcbiAgICBwb3MgKz0gYnVmLmxlbmd0aFxuICB9XG4gIHJldHVybiBidWZmZXJcbn1cblxuZnVuY3Rpb24gYnl0ZUxlbmd0aCAoc3RyaW5nLCBlbmNvZGluZykge1xuICBpZiAoQnVmZmVyLmlzQnVmZmVyKHN0cmluZykpIHtcbiAgICByZXR1cm4gc3RyaW5nLmxlbmd0aFxuICB9XG4gIGlmICh0eXBlb2YgQXJyYXlCdWZmZXIgIT09ICd1bmRlZmluZWQnICYmIHR5cGVvZiBBcnJheUJ1ZmZlci5pc1ZpZXcgPT09ICdmdW5jdGlvbicgJiZcbiAgICAgIChBcnJheUJ1ZmZlci5pc1ZpZXcoc3RyaW5nKSB8fCBzdHJpbmcgaW5zdGFuY2VvZiBBcnJheUJ1ZmZlcikpIHtcbiAgICByZXR1cm4gc3RyaW5nLmJ5dGVMZW5ndGhcbiAgfVxuICBpZiAodHlwZW9mIHN0cmluZyAhPT0gJ3N0cmluZycpIHtcbiAgICBzdHJpbmcgPSAnJyArIHN0cmluZ1xuICB9XG5cbiAgdmFyIGxlbiA9IHN0cmluZy5sZW5ndGhcbiAgaWYgKGxlbiA9PT0gMCkgcmV0dXJuIDBcblxuICAvLyBVc2UgYSBmb3IgbG9vcCB0byBhdm9pZCByZWN1cnNpb25cbiAgdmFyIGxvd2VyZWRDYXNlID0gZmFsc2VcbiAgZm9yICg7Oykge1xuICAgIHN3aXRjaCAoZW5jb2RpbmcpIHtcbiAgICAgIGNhc2UgJ2FzY2lpJzpcbiAgICAgIGNhc2UgJ2JpbmFyeSc6XG4gICAgICBjYXNlICdyYXcnOlxuICAgICAgY2FzZSAncmF3cyc6XG4gICAgICAgIHJldHVybiBsZW5cbiAgICAgIGNhc2UgJ3V0ZjgnOlxuICAgICAgY2FzZSAndXRmLTgnOlxuICAgICAgY2FzZSB1bmRlZmluZWQ6XG4gICAgICAgIHJldHVybiB1dGY4VG9CeXRlcyhzdHJpbmcpLmxlbmd0aFxuICAgICAgY2FzZSAndWNzMic6XG4gICAgICBjYXNlICd1Y3MtMic6XG4gICAgICBjYXNlICd1dGYxNmxlJzpcbiAgICAgIGNhc2UgJ3V0Zi0xNmxlJzpcbiAgICAgICAgcmV0dXJuIGxlbiAqIDJcbiAgICAgIGNhc2UgJ2hleCc6XG4gICAgICAgIHJldHVybiBsZW4gPj4+IDFcbiAgICAgIGNhc2UgJ2Jhc2U2NCc6XG4gICAgICAgIHJldHVybiBiYXNlNjRUb0J5dGVzKHN0cmluZykubGVuZ3RoXG4gICAgICBkZWZhdWx0OlxuICAgICAgICBpZiAobG93ZXJlZENhc2UpIHJldHVybiB1dGY4VG9CeXRlcyhzdHJpbmcpLmxlbmd0aCAvLyBhc3N1bWUgdXRmOFxuICAgICAgICBlbmNvZGluZyA9ICgnJyArIGVuY29kaW5nKS50b0xvd2VyQ2FzZSgpXG4gICAgICAgIGxvd2VyZWRDYXNlID0gdHJ1ZVxuICAgIH1cbiAgfVxufVxuQnVmZmVyLmJ5dGVMZW5ndGggPSBieXRlTGVuZ3RoXG5cbmZ1bmN0aW9uIHNsb3dUb1N0cmluZyAoZW5jb2RpbmcsIHN0YXJ0LCBlbmQpIHtcbiAgdmFyIGxvd2VyZWRDYXNlID0gZmFsc2VcblxuICAvLyBObyBuZWVkIHRvIHZlcmlmeSB0aGF0IFwidGhpcy5sZW5ndGggPD0gTUFYX1VJTlQzMlwiIHNpbmNlIGl0J3MgYSByZWFkLW9ubHlcbiAgLy8gcHJvcGVydHkgb2YgYSB0eXBlZCBhcnJheS5cblxuICAvLyBUaGlzIGJlaGF2ZXMgbmVpdGhlciBsaWtlIFN0cmluZyBub3IgVWludDhBcnJheSBpbiB0aGF0IHdlIHNldCBzdGFydC9lbmRcbiAgLy8gdG8gdGhlaXIgdXBwZXIvbG93ZXIgYm91bmRzIGlmIHRoZSB2YWx1ZSBwYXNzZWQgaXMgb3V0IG9mIHJhbmdlLlxuICAvLyB1bmRlZmluZWQgaXMgaGFuZGxlZCBzcGVjaWFsbHkgYXMgcGVyIEVDTUEtMjYyIDZ0aCBFZGl0aW9uLFxuICAvLyBTZWN0aW9uIDEzLjMuMy43IFJ1bnRpbWUgU2VtYW50aWNzOiBLZXllZEJpbmRpbmdJbml0aWFsaXphdGlvbi5cbiAgaWYgKHN0YXJ0ID09PSB1bmRlZmluZWQgfHwgc3RhcnQgPCAwKSB7XG4gICAgc3RhcnQgPSAwXG4gIH1cbiAgLy8gUmV0dXJuIGVhcmx5IGlmIHN0YXJ0ID4gdGhpcy5sZW5ndGguIERvbmUgaGVyZSB0byBwcmV2ZW50IHBvdGVudGlhbCB1aW50MzJcbiAgLy8gY29lcmNpb24gZmFpbCBiZWxvdy5cbiAgaWYgKHN0YXJ0ID4gdGhpcy5sZW5ndGgpIHtcbiAgICByZXR1cm4gJydcbiAgfVxuXG4gIGlmIChlbmQgPT09IHVuZGVmaW5lZCB8fCBlbmQgPiB0aGlzLmxlbmd0aCkge1xuICAgIGVuZCA9IHRoaXMubGVuZ3RoXG4gIH1cblxuICBpZiAoZW5kIDw9IDApIHtcbiAgICByZXR1cm4gJydcbiAgfVxuXG4gIC8vIEZvcmNlIGNvZXJzaW9uIHRvIHVpbnQzMi4gVGhpcyB3aWxsIGFsc28gY29lcmNlIGZhbHNleS9OYU4gdmFsdWVzIHRvIDAuXG4gIGVuZCA+Pj49IDBcbiAgc3RhcnQgPj4+PSAwXG5cbiAgaWYgKGVuZCA8PSBzdGFydCkge1xuICAgIHJldHVybiAnJ1xuICB9XG5cbiAgaWYgKCFlbmNvZGluZykgZW5jb2RpbmcgPSAndXRmOCdcblxuICB3aGlsZSAodHJ1ZSkge1xuICAgIHN3aXRjaCAoZW5jb2RpbmcpIHtcbiAgICAgIGNhc2UgJ2hleCc6XG4gICAgICAgIHJldHVybiBoZXhTbGljZSh0aGlzLCBzdGFydCwgZW5kKVxuXG4gICAgICBjYXNlICd1dGY4JzpcbiAgICAgIGNhc2UgJ3V0Zi04JzpcbiAgICAgICAgcmV0dXJuIHV0ZjhTbGljZSh0aGlzLCBzdGFydCwgZW5kKVxuXG4gICAgICBjYXNlICdhc2NpaSc6XG4gICAgICAgIHJldHVybiBhc2NpaVNsaWNlKHRoaXMsIHN0YXJ0LCBlbmQpXG5cbiAgICAgIGNhc2UgJ2JpbmFyeSc6XG4gICAgICAgIHJldHVybiBiaW5hcnlTbGljZSh0aGlzLCBzdGFydCwgZW5kKVxuXG4gICAgICBjYXNlICdiYXNlNjQnOlxuICAgICAgICByZXR1cm4gYmFzZTY0U2xpY2UodGhpcywgc3RhcnQsIGVuZClcblxuICAgICAgY2FzZSAndWNzMic6XG4gICAgICBjYXNlICd1Y3MtMic6XG4gICAgICBjYXNlICd1dGYxNmxlJzpcbiAgICAgIGNhc2UgJ3V0Zi0xNmxlJzpcbiAgICAgICAgcmV0dXJuIHV0ZjE2bGVTbGljZSh0aGlzLCBzdGFydCwgZW5kKVxuXG4gICAgICBkZWZhdWx0OlxuICAgICAgICBpZiAobG93ZXJlZENhc2UpIHRocm93IG5ldyBUeXBlRXJyb3IoJ1Vua25vd24gZW5jb2Rpbmc6ICcgKyBlbmNvZGluZylcbiAgICAgICAgZW5jb2RpbmcgPSAoZW5jb2RpbmcgKyAnJykudG9Mb3dlckNhc2UoKVxuICAgICAgICBsb3dlcmVkQ2FzZSA9IHRydWVcbiAgICB9XG4gIH1cbn1cblxuLy8gVGhlIHByb3BlcnR5IGlzIHVzZWQgYnkgYEJ1ZmZlci5pc0J1ZmZlcmAgYW5kIGBpcy1idWZmZXJgIChpbiBTYWZhcmkgNS03KSB0byBkZXRlY3Rcbi8vIEJ1ZmZlciBpbnN0YW5jZXMuXG5CdWZmZXIucHJvdG90eXBlLl9pc0J1ZmZlciA9IHRydWVcblxuZnVuY3Rpb24gc3dhcCAoYiwgbiwgbSkge1xuICB2YXIgaSA9IGJbbl1cbiAgYltuXSA9IGJbbV1cbiAgYlttXSA9IGlcbn1cblxuQnVmZmVyLnByb3RvdHlwZS5zd2FwMTYgPSBmdW5jdGlvbiBzd2FwMTYgKCkge1xuICB2YXIgbGVuID0gdGhpcy5sZW5ndGhcbiAgaWYgKGxlbiAlIDIgIT09IDApIHtcbiAgICB0aHJvdyBuZXcgUmFuZ2VFcnJvcignQnVmZmVyIHNpemUgbXVzdCBiZSBhIG11bHRpcGxlIG9mIDE2LWJpdHMnKVxuICB9XG4gIGZvciAodmFyIGkgPSAwOyBpIDwgbGVuOyBpICs9IDIpIHtcbiAgICBzd2FwKHRoaXMsIGksIGkgKyAxKVxuICB9XG4gIHJldHVybiB0aGlzXG59XG5cbkJ1ZmZlci5wcm90b3R5cGUuc3dhcDMyID0gZnVuY3Rpb24gc3dhcDMyICgpIHtcbiAgdmFyIGxlbiA9IHRoaXMubGVuZ3RoXG4gIGlmIChsZW4gJSA0ICE9PSAwKSB7XG4gICAgdGhyb3cgbmV3IFJhbmdlRXJyb3IoJ0J1ZmZlciBzaXplIG11c3QgYmUgYSBtdWx0aXBsZSBvZiAzMi1iaXRzJylcbiAgfVxuICBmb3IgKHZhciBpID0gMDsgaSA8IGxlbjsgaSArPSA0KSB7XG4gICAgc3dhcCh0aGlzLCBpLCBpICsgMylcbiAgICBzd2FwKHRoaXMsIGkgKyAxLCBpICsgMilcbiAgfVxuICByZXR1cm4gdGhpc1xufVxuXG5CdWZmZXIucHJvdG90eXBlLnRvU3RyaW5nID0gZnVuY3Rpb24gdG9TdHJpbmcgKCkge1xuICB2YXIgbGVuZ3RoID0gdGhpcy5sZW5ndGggfCAwXG4gIGlmIChsZW5ndGggPT09IDApIHJldHVybiAnJ1xuICBpZiAoYXJndW1lbnRzLmxlbmd0aCA9PT0gMCkgcmV0dXJuIHV0ZjhTbGljZSh0aGlzLCAwLCBsZW5ndGgpXG4gIHJldHVybiBzbG93VG9TdHJpbmcuYXBwbHkodGhpcywgYXJndW1lbnRzKVxufVxuXG5CdWZmZXIucHJvdG90eXBlLmVxdWFscyA9IGZ1bmN0aW9uIGVxdWFscyAoYikge1xuICBpZiAoIUJ1ZmZlci5pc0J1ZmZlcihiKSkgdGhyb3cgbmV3IFR5cGVFcnJvcignQXJndW1lbnQgbXVzdCBiZSBhIEJ1ZmZlcicpXG4gIGlmICh0aGlzID09PSBiKSByZXR1cm4gdHJ1ZVxuICByZXR1cm4gQnVmZmVyLmNvbXBhcmUodGhpcywgYikgPT09IDBcbn1cblxuQnVmZmVyLnByb3RvdHlwZS5pbnNwZWN0ID0gZnVuY3Rpb24gaW5zcGVjdCAoKSB7XG4gIHZhciBzdHIgPSAnJ1xuICB2YXIgbWF4ID0gZXhwb3J0cy5JTlNQRUNUX01BWF9CWVRFU1xuICBpZiAodGhpcy5sZW5ndGggPiAwKSB7XG4gICAgc3RyID0gdGhpcy50b1N0cmluZygnaGV4JywgMCwgbWF4KS5tYXRjaCgvLnsyfS9nKS5qb2luKCcgJylcbiAgICBpZiAodGhpcy5sZW5ndGggPiBtYXgpIHN0ciArPSAnIC4uLiAnXG4gIH1cbiAgcmV0dXJuICc8QnVmZmVyICcgKyBzdHIgKyAnPidcbn1cblxuQnVmZmVyLnByb3RvdHlwZS5jb21wYXJlID0gZnVuY3Rpb24gY29tcGFyZSAodGFyZ2V0LCBzdGFydCwgZW5kLCB0aGlzU3RhcnQsIHRoaXNFbmQpIHtcbiAgaWYgKCFCdWZmZXIuaXNCdWZmZXIodGFyZ2V0KSkge1xuICAgIHRocm93IG5ldyBUeXBlRXJyb3IoJ0FyZ3VtZW50IG11c3QgYmUgYSBCdWZmZXInKVxuICB9XG5cbiAgaWYgKHN0YXJ0ID09PSB1bmRlZmluZWQpIHtcbiAgICBzdGFydCA9IDBcbiAgfVxuICBpZiAoZW5kID09PSB1bmRlZmluZWQpIHtcbiAgICBlbmQgPSB0YXJnZXQgPyB0YXJnZXQubGVuZ3RoIDogMFxuICB9XG4gIGlmICh0aGlzU3RhcnQgPT09IHVuZGVmaW5lZCkge1xuICAgIHRoaXNTdGFydCA9IDBcbiAgfVxuICBpZiAodGhpc0VuZCA9PT0gdW5kZWZpbmVkKSB7XG4gICAgdGhpc0VuZCA9IHRoaXMubGVuZ3RoXG4gIH1cblxuICBpZiAoc3RhcnQgPCAwIHx8IGVuZCA+IHRhcmdldC5sZW5ndGggfHwgdGhpc1N0YXJ0IDwgMCB8fCB0aGlzRW5kID4gdGhpcy5sZW5ndGgpIHtcbiAgICB0aHJvdyBuZXcgUmFuZ2VFcnJvcignb3V0IG9mIHJhbmdlIGluZGV4JylcbiAgfVxuXG4gIGlmICh0aGlzU3RhcnQgPj0gdGhpc0VuZCAmJiBzdGFydCA+PSBlbmQpIHtcbiAgICByZXR1cm4gMFxuICB9XG4gIGlmICh0aGlzU3RhcnQgPj0gdGhpc0VuZCkge1xuICAgIHJldHVybiAtMVxuICB9XG4gIGlmIChzdGFydCA+PSBlbmQpIHtcbiAgICByZXR1cm4gMVxuICB9XG5cbiAgc3RhcnQgPj4+PSAwXG4gIGVuZCA+Pj49IDBcbiAgdGhpc1N0YXJ0ID4+Pj0gMFxuICB0aGlzRW5kID4+Pj0gMFxuXG4gIGlmICh0aGlzID09PSB0YXJnZXQpIHJldHVybiAwXG5cbiAgdmFyIHggPSB0aGlzRW5kIC0gdGhpc1N0YXJ0XG4gIHZhciB5ID0gZW5kIC0gc3RhcnRcbiAgdmFyIGxlbiA9IE1hdGgubWluKHgsIHkpXG5cbiAgdmFyIHRoaXNDb3B5ID0gdGhpcy5zbGljZSh0aGlzU3RhcnQsIHRoaXNFbmQpXG4gIHZhciB0YXJnZXRDb3B5ID0gdGFyZ2V0LnNsaWNlKHN0YXJ0LCBlbmQpXG5cbiAgZm9yICh2YXIgaSA9IDA7IGkgPCBsZW47ICsraSkge1xuICAgIGlmICh0aGlzQ29weVtpXSAhPT0gdGFyZ2V0Q29weVtpXSkge1xuICAgICAgeCA9IHRoaXNDb3B5W2ldXG4gICAgICB5ID0gdGFyZ2V0Q29weVtpXVxuICAgICAgYnJlYWtcbiAgICB9XG4gIH1cblxuICBpZiAoeCA8IHkpIHJldHVybiAtMVxuICBpZiAoeSA8IHgpIHJldHVybiAxXG4gIHJldHVybiAwXG59XG5cbmZ1bmN0aW9uIGFycmF5SW5kZXhPZiAoYXJyLCB2YWwsIGJ5dGVPZmZzZXQsIGVuY29kaW5nKSB7XG4gIHZhciBpbmRleFNpemUgPSAxXG4gIHZhciBhcnJMZW5ndGggPSBhcnIubGVuZ3RoXG4gIHZhciB2YWxMZW5ndGggPSB2YWwubGVuZ3RoXG5cbiAgaWYgKGVuY29kaW5nICE9PSB1bmRlZmluZWQpIHtcbiAgICBlbmNvZGluZyA9IFN0cmluZyhlbmNvZGluZykudG9Mb3dlckNhc2UoKVxuICAgIGlmIChlbmNvZGluZyA9PT0gJ3VjczInIHx8IGVuY29kaW5nID09PSAndWNzLTInIHx8XG4gICAgICAgIGVuY29kaW5nID09PSAndXRmMTZsZScgfHwgZW5jb2RpbmcgPT09ICd1dGYtMTZsZScpIHtcbiAgICAgIGlmIChhcnIubGVuZ3RoIDwgMiB8fCB2YWwubGVuZ3RoIDwgMikge1xuICAgICAgICByZXR1cm4gLTFcbiAgICAgIH1cbiAgICAgIGluZGV4U2l6ZSA9IDJcbiAgICAgIGFyckxlbmd0aCAvPSAyXG4gICAgICB2YWxMZW5ndGggLz0gMlxuICAgICAgYnl0ZU9mZnNldCAvPSAyXG4gICAgfVxuICB9XG5cbiAgZnVuY3Rpb24gcmVhZCAoYnVmLCBpKSB7XG4gICAgaWYgKGluZGV4U2l6ZSA9PT0gMSkge1xuICAgICAgcmV0dXJuIGJ1ZltpXVxuICAgIH0gZWxzZSB7XG4gICAgICByZXR1cm4gYnVmLnJlYWRVSW50MTZCRShpICogaW5kZXhTaXplKVxuICAgIH1cbiAgfVxuXG4gIHZhciBmb3VuZEluZGV4ID0gLTFcbiAgZm9yICh2YXIgaSA9IGJ5dGVPZmZzZXQ7IGkgPCBhcnJMZW5ndGg7ICsraSkge1xuICAgIGlmIChyZWFkKGFyciwgaSkgPT09IHJlYWQodmFsLCBmb3VuZEluZGV4ID09PSAtMSA/IDAgOiBpIC0gZm91bmRJbmRleCkpIHtcbiAgICAgIGlmIChmb3VuZEluZGV4ID09PSAtMSkgZm91bmRJbmRleCA9IGlcbiAgICAgIGlmIChpIC0gZm91bmRJbmRleCArIDEgPT09IHZhbExlbmd0aCkgcmV0dXJuIGZvdW5kSW5kZXggKiBpbmRleFNpemVcbiAgICB9IGVsc2Uge1xuICAgICAgaWYgKGZvdW5kSW5kZXggIT09IC0xKSBpIC09IGkgLSBmb3VuZEluZGV4XG4gICAgICBmb3VuZEluZGV4ID0gLTFcbiAgICB9XG4gIH1cblxuICByZXR1cm4gLTFcbn1cblxuQnVmZmVyLnByb3RvdHlwZS5pbmRleE9mID0gZnVuY3Rpb24gaW5kZXhPZiAodmFsLCBieXRlT2Zmc2V0LCBlbmNvZGluZykge1xuICBpZiAodHlwZW9mIGJ5dGVPZmZzZXQgPT09ICdzdHJpbmcnKSB7XG4gICAgZW5jb2RpbmcgPSBieXRlT2Zmc2V0XG4gICAgYnl0ZU9mZnNldCA9IDBcbiAgfSBlbHNlIGlmIChieXRlT2Zmc2V0ID4gMHg3ZmZmZmZmZikge1xuICAgIGJ5dGVPZmZzZXQgPSAweDdmZmZmZmZmXG4gIH0gZWxzZSBpZiAoYnl0ZU9mZnNldCA8IC0weDgwMDAwMDAwKSB7XG4gICAgYnl0ZU9mZnNldCA9IC0weDgwMDAwMDAwXG4gIH1cbiAgYnl0ZU9mZnNldCA+Pj0gMFxuXG4gIGlmICh0aGlzLmxlbmd0aCA9PT0gMCkgcmV0dXJuIC0xXG4gIGlmIChieXRlT2Zmc2V0ID49IHRoaXMubGVuZ3RoKSByZXR1cm4gLTFcblxuICAvLyBOZWdhdGl2ZSBvZmZzZXRzIHN0YXJ0IGZyb20gdGhlIGVuZCBvZiB0aGUgYnVmZmVyXG4gIGlmIChieXRlT2Zmc2V0IDwgMCkgYnl0ZU9mZnNldCA9IE1hdGgubWF4KHRoaXMubGVuZ3RoICsgYnl0ZU9mZnNldCwgMClcblxuICBpZiAodHlwZW9mIHZhbCA9PT0gJ3N0cmluZycpIHtcbiAgICB2YWwgPSBCdWZmZXIuZnJvbSh2YWwsIGVuY29kaW5nKVxuICB9XG5cbiAgaWYgKEJ1ZmZlci5pc0J1ZmZlcih2YWwpKSB7XG4gICAgLy8gc3BlY2lhbCBjYXNlOiBsb29raW5nIGZvciBlbXB0eSBzdHJpbmcvYnVmZmVyIGFsd2F5cyBmYWlsc1xuICAgIGlmICh2YWwubGVuZ3RoID09PSAwKSB7XG4gICAgICByZXR1cm4gLTFcbiAgICB9XG4gICAgcmV0dXJuIGFycmF5SW5kZXhPZih0aGlzLCB2YWwsIGJ5dGVPZmZzZXQsIGVuY29kaW5nKVxuICB9XG4gIGlmICh0eXBlb2YgdmFsID09PSAnbnVtYmVyJykge1xuICAgIGlmIChCdWZmZXIuVFlQRURfQVJSQVlfU1VQUE9SVCAmJiBVaW50OEFycmF5LnByb3RvdHlwZS5pbmRleE9mID09PSAnZnVuY3Rpb24nKSB7XG4gICAgICByZXR1cm4gVWludDhBcnJheS5wcm90b3R5cGUuaW5kZXhPZi5jYWxsKHRoaXMsIHZhbCwgYnl0ZU9mZnNldClcbiAgICB9XG4gICAgcmV0dXJuIGFycmF5SW5kZXhPZih0aGlzLCBbIHZhbCBdLCBieXRlT2Zmc2V0LCBlbmNvZGluZylcbiAgfVxuXG4gIHRocm93IG5ldyBUeXBlRXJyb3IoJ3ZhbCBtdXN0IGJlIHN0cmluZywgbnVtYmVyIG9yIEJ1ZmZlcicpXG59XG5cbkJ1ZmZlci5wcm90b3R5cGUuaW5jbHVkZXMgPSBmdW5jdGlvbiBpbmNsdWRlcyAodmFsLCBieXRlT2Zmc2V0LCBlbmNvZGluZykge1xuICByZXR1cm4gdGhpcy5pbmRleE9mKHZhbCwgYnl0ZU9mZnNldCwgZW5jb2RpbmcpICE9PSAtMVxufVxuXG5mdW5jdGlvbiBoZXhXcml0ZSAoYnVmLCBzdHJpbmcsIG9mZnNldCwgbGVuZ3RoKSB7XG4gIG9mZnNldCA9IE51bWJlcihvZmZzZXQpIHx8IDBcbiAgdmFyIHJlbWFpbmluZyA9IGJ1Zi5sZW5ndGggLSBvZmZzZXRcbiAgaWYgKCFsZW5ndGgpIHtcbiAgICBsZW5ndGggPSByZW1haW5pbmdcbiAgfSBlbHNlIHtcbiAgICBsZW5ndGggPSBOdW1iZXIobGVuZ3RoKVxuICAgIGlmIChsZW5ndGggPiByZW1haW5pbmcpIHtcbiAgICAgIGxlbmd0aCA9IHJlbWFpbmluZ1xuICAgIH1cbiAgfVxuXG4gIC8vIG11c3QgYmUgYW4gZXZlbiBudW1iZXIgb2YgZGlnaXRzXG4gIHZhciBzdHJMZW4gPSBzdHJpbmcubGVuZ3RoXG4gIGlmIChzdHJMZW4gJSAyICE9PSAwKSB0aHJvdyBuZXcgRXJyb3IoJ0ludmFsaWQgaGV4IHN0cmluZycpXG5cbiAgaWYgKGxlbmd0aCA+IHN0ckxlbiAvIDIpIHtcbiAgICBsZW5ndGggPSBzdHJMZW4gLyAyXG4gIH1cbiAgZm9yICh2YXIgaSA9IDA7IGkgPCBsZW5ndGg7ICsraSkge1xuICAgIHZhciBwYXJzZWQgPSBwYXJzZUludChzdHJpbmcuc3Vic3RyKGkgKiAyLCAyKSwgMTYpXG4gICAgaWYgKGlzTmFOKHBhcnNlZCkpIHJldHVybiBpXG4gICAgYnVmW29mZnNldCArIGldID0gcGFyc2VkXG4gIH1cbiAgcmV0dXJuIGlcbn1cblxuZnVuY3Rpb24gdXRmOFdyaXRlIChidWYsIHN0cmluZywgb2Zmc2V0LCBsZW5ndGgpIHtcbiAgcmV0dXJuIGJsaXRCdWZmZXIodXRmOFRvQnl0ZXMoc3RyaW5nLCBidWYubGVuZ3RoIC0gb2Zmc2V0KSwgYnVmLCBvZmZzZXQsIGxlbmd0aClcbn1cblxuZnVuY3Rpb24gYXNjaWlXcml0ZSAoYnVmLCBzdHJpbmcsIG9mZnNldCwgbGVuZ3RoKSB7XG4gIHJldHVybiBibGl0QnVmZmVyKGFzY2lpVG9CeXRlcyhzdHJpbmcpLCBidWYsIG9mZnNldCwgbGVuZ3RoKVxufVxuXG5mdW5jdGlvbiBiaW5hcnlXcml0ZSAoYnVmLCBzdHJpbmcsIG9mZnNldCwgbGVuZ3RoKSB7XG4gIHJldHVybiBhc2NpaVdyaXRlKGJ1Ziwgc3RyaW5nLCBvZmZzZXQsIGxlbmd0aClcbn1cblxuZnVuY3Rpb24gYmFzZTY0V3JpdGUgKGJ1Ziwgc3RyaW5nLCBvZmZzZXQsIGxlbmd0aCkge1xuICByZXR1cm4gYmxpdEJ1ZmZlcihiYXNlNjRUb0J5dGVzKHN0cmluZyksIGJ1Ziwgb2Zmc2V0LCBsZW5ndGgpXG59XG5cbmZ1bmN0aW9uIHVjczJXcml0ZSAoYnVmLCBzdHJpbmcsIG9mZnNldCwgbGVuZ3RoKSB7XG4gIHJldHVybiBibGl0QnVmZmVyKHV0ZjE2bGVUb0J5dGVzKHN0cmluZywgYnVmLmxlbmd0aCAtIG9mZnNldCksIGJ1Ziwgb2Zmc2V0LCBsZW5ndGgpXG59XG5cbkJ1ZmZlci5wcm90b3R5cGUud3JpdGUgPSBmdW5jdGlvbiB3cml0ZSAoc3RyaW5nLCBvZmZzZXQsIGxlbmd0aCwgZW5jb2RpbmcpIHtcbiAgLy8gQnVmZmVyI3dyaXRlKHN0cmluZylcbiAgaWYgKG9mZnNldCA9PT0gdW5kZWZpbmVkKSB7XG4gICAgZW5jb2RpbmcgPSAndXRmOCdcbiAgICBsZW5ndGggPSB0aGlzLmxlbmd0aFxuICAgIG9mZnNldCA9IDBcbiAgLy8gQnVmZmVyI3dyaXRlKHN0cmluZywgZW5jb2RpbmcpXG4gIH0gZWxzZSBpZiAobGVuZ3RoID09PSB1bmRlZmluZWQgJiYgdHlwZW9mIG9mZnNldCA9PT0gJ3N0cmluZycpIHtcbiAgICBlbmNvZGluZyA9IG9mZnNldFxuICAgIGxlbmd0aCA9IHRoaXMubGVuZ3RoXG4gICAgb2Zmc2V0ID0gMFxuICAvLyBCdWZmZXIjd3JpdGUoc3RyaW5nLCBvZmZzZXRbLCBsZW5ndGhdWywgZW5jb2RpbmddKVxuICB9IGVsc2UgaWYgKGlzRmluaXRlKG9mZnNldCkpIHtcbiAgICBvZmZzZXQgPSBvZmZzZXQgfCAwXG4gICAgaWYgKGlzRmluaXRlKGxlbmd0aCkpIHtcbiAgICAgIGxlbmd0aCA9IGxlbmd0aCB8IDBcbiAgICAgIGlmIChlbmNvZGluZyA9PT0gdW5kZWZpbmVkKSBlbmNvZGluZyA9ICd1dGY4J1xuICAgIH0gZWxzZSB7XG4gICAgICBlbmNvZGluZyA9IGxlbmd0aFxuICAgICAgbGVuZ3RoID0gdW5kZWZpbmVkXG4gICAgfVxuICAvLyBsZWdhY3kgd3JpdGUoc3RyaW5nLCBlbmNvZGluZywgb2Zmc2V0LCBsZW5ndGgpIC0gcmVtb3ZlIGluIHYwLjEzXG4gIH0gZWxzZSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKFxuICAgICAgJ0J1ZmZlci53cml0ZShzdHJpbmcsIGVuY29kaW5nLCBvZmZzZXRbLCBsZW5ndGhdKSBpcyBubyBsb25nZXIgc3VwcG9ydGVkJ1xuICAgIClcbiAgfVxuXG4gIHZhciByZW1haW5pbmcgPSB0aGlzLmxlbmd0aCAtIG9mZnNldFxuICBpZiAobGVuZ3RoID09PSB1bmRlZmluZWQgfHwgbGVuZ3RoID4gcmVtYWluaW5nKSBsZW5ndGggPSByZW1haW5pbmdcblxuICBpZiAoKHN0cmluZy5sZW5ndGggPiAwICYmIChsZW5ndGggPCAwIHx8IG9mZnNldCA8IDApKSB8fCBvZmZzZXQgPiB0aGlzLmxlbmd0aCkge1xuICAgIHRocm93IG5ldyBSYW5nZUVycm9yKCdBdHRlbXB0IHRvIHdyaXRlIG91dHNpZGUgYnVmZmVyIGJvdW5kcycpXG4gIH1cblxuICBpZiAoIWVuY29kaW5nKSBlbmNvZGluZyA9ICd1dGY4J1xuXG4gIHZhciBsb3dlcmVkQ2FzZSA9IGZhbHNlXG4gIGZvciAoOzspIHtcbiAgICBzd2l0Y2ggKGVuY29kaW5nKSB7XG4gICAgICBjYXNlICdoZXgnOlxuICAgICAgICByZXR1cm4gaGV4V3JpdGUodGhpcywgc3RyaW5nLCBvZmZzZXQsIGxlbmd0aClcblxuICAgICAgY2FzZSAndXRmOCc6XG4gICAgICBjYXNlICd1dGYtOCc6XG4gICAgICAgIHJldHVybiB1dGY4V3JpdGUodGhpcywgc3RyaW5nLCBvZmZzZXQsIGxlbmd0aClcblxuICAgICAgY2FzZSAnYXNjaWknOlxuICAgICAgICByZXR1cm4gYXNjaWlXcml0ZSh0aGlzLCBzdHJpbmcsIG9mZnNldCwgbGVuZ3RoKVxuXG4gICAgICBjYXNlICdiaW5hcnknOlxuICAgICAgICByZXR1cm4gYmluYXJ5V3JpdGUodGhpcywgc3RyaW5nLCBvZmZzZXQsIGxlbmd0aClcblxuICAgICAgY2FzZSAnYmFzZTY0JzpcbiAgICAgICAgLy8gV2FybmluZzogbWF4TGVuZ3RoIG5vdCB0YWtlbiBpbnRvIGFjY291bnQgaW4gYmFzZTY0V3JpdGVcbiAgICAgICAgcmV0dXJuIGJhc2U2NFdyaXRlKHRoaXMsIHN0cmluZywgb2Zmc2V0LCBsZW5ndGgpXG5cbiAgICAgIGNhc2UgJ3VjczInOlxuICAgICAgY2FzZSAndWNzLTInOlxuICAgICAgY2FzZSAndXRmMTZsZSc6XG4gICAgICBjYXNlICd1dGYtMTZsZSc6XG4gICAgICAgIHJldHVybiB1Y3MyV3JpdGUodGhpcywgc3RyaW5nLCBvZmZzZXQsIGxlbmd0aClcblxuICAgICAgZGVmYXVsdDpcbiAgICAgICAgaWYgKGxvd2VyZWRDYXNlKSB0aHJvdyBuZXcgVHlwZUVycm9yKCdVbmtub3duIGVuY29kaW5nOiAnICsgZW5jb2RpbmcpXG4gICAgICAgIGVuY29kaW5nID0gKCcnICsgZW5jb2RpbmcpLnRvTG93ZXJDYXNlKClcbiAgICAgICAgbG93ZXJlZENhc2UgPSB0cnVlXG4gICAgfVxuICB9XG59XG5cbkJ1ZmZlci5wcm90b3R5cGUudG9KU09OID0gZnVuY3Rpb24gdG9KU09OICgpIHtcbiAgcmV0dXJuIHtcbiAgICB0eXBlOiAnQnVmZmVyJyxcbiAgICBkYXRhOiBBcnJheS5wcm90b3R5cGUuc2xpY2UuY2FsbCh0aGlzLl9hcnIgfHwgdGhpcywgMClcbiAgfVxufVxuXG5mdW5jdGlvbiBiYXNlNjRTbGljZSAoYnVmLCBzdGFydCwgZW5kKSB7XG4gIGlmIChzdGFydCA9PT0gMCAmJiBlbmQgPT09IGJ1Zi5sZW5ndGgpIHtcbiAgICByZXR1cm4gYmFzZTY0LmZyb21CeXRlQXJyYXkoYnVmKVxuICB9IGVsc2Uge1xuICAgIHJldHVybiBiYXNlNjQuZnJvbUJ5dGVBcnJheShidWYuc2xpY2Uoc3RhcnQsIGVuZCkpXG4gIH1cbn1cblxuZnVuY3Rpb24gdXRmOFNsaWNlIChidWYsIHN0YXJ0LCBlbmQpIHtcbiAgZW5kID0gTWF0aC5taW4oYnVmLmxlbmd0aCwgZW5kKVxuICB2YXIgcmVzID0gW11cblxuICB2YXIgaSA9IHN0YXJ0XG4gIHdoaWxlIChpIDwgZW5kKSB7XG4gICAgdmFyIGZpcnN0Qnl0ZSA9IGJ1ZltpXVxuICAgIHZhciBjb2RlUG9pbnQgPSBudWxsXG4gICAgdmFyIGJ5dGVzUGVyU2VxdWVuY2UgPSAoZmlyc3RCeXRlID4gMHhFRikgPyA0XG4gICAgICA6IChmaXJzdEJ5dGUgPiAweERGKSA/IDNcbiAgICAgIDogKGZpcnN0Qnl0ZSA+IDB4QkYpID8gMlxuICAgICAgOiAxXG5cbiAgICBpZiAoaSArIGJ5dGVzUGVyU2VxdWVuY2UgPD0gZW5kKSB7XG4gICAgICB2YXIgc2Vjb25kQnl0ZSwgdGhpcmRCeXRlLCBmb3VydGhCeXRlLCB0ZW1wQ29kZVBvaW50XG5cbiAgICAgIHN3aXRjaCAoYnl0ZXNQZXJTZXF1ZW5jZSkge1xuICAgICAgICBjYXNlIDE6XG4gICAgICAgICAgaWYgKGZpcnN0Qnl0ZSA8IDB4ODApIHtcbiAgICAgICAgICAgIGNvZGVQb2ludCA9IGZpcnN0Qnl0ZVxuICAgICAgICAgIH1cbiAgICAgICAgICBicmVha1xuICAgICAgICBjYXNlIDI6XG4gICAgICAgICAgc2Vjb25kQnl0ZSA9IGJ1ZltpICsgMV1cbiAgICAgICAgICBpZiAoKHNlY29uZEJ5dGUgJiAweEMwKSA9PT0gMHg4MCkge1xuICAgICAgICAgICAgdGVtcENvZGVQb2ludCA9IChmaXJzdEJ5dGUgJiAweDFGKSA8PCAweDYgfCAoc2Vjb25kQnl0ZSAmIDB4M0YpXG4gICAgICAgICAgICBpZiAodGVtcENvZGVQb2ludCA+IDB4N0YpIHtcbiAgICAgICAgICAgICAgY29kZVBvaW50ID0gdGVtcENvZGVQb2ludFxuICAgICAgICAgICAgfVxuICAgICAgICAgIH1cbiAgICAgICAgICBicmVha1xuICAgICAgICBjYXNlIDM6XG4gICAgICAgICAgc2Vjb25kQnl0ZSA9IGJ1ZltpICsgMV1cbiAgICAgICAgICB0aGlyZEJ5dGUgPSBidWZbaSArIDJdXG4gICAgICAgICAgaWYgKChzZWNvbmRCeXRlICYgMHhDMCkgPT09IDB4ODAgJiYgKHRoaXJkQnl0ZSAmIDB4QzApID09PSAweDgwKSB7XG4gICAgICAgICAgICB0ZW1wQ29kZVBvaW50ID0gKGZpcnN0Qnl0ZSAmIDB4RikgPDwgMHhDIHwgKHNlY29uZEJ5dGUgJiAweDNGKSA8PCAweDYgfCAodGhpcmRCeXRlICYgMHgzRilcbiAgICAgICAgICAgIGlmICh0ZW1wQ29kZVBvaW50ID4gMHg3RkYgJiYgKHRlbXBDb2RlUG9pbnQgPCAweEQ4MDAgfHwgdGVtcENvZGVQb2ludCA+IDB4REZGRikpIHtcbiAgICAgICAgICAgICAgY29kZVBvaW50ID0gdGVtcENvZGVQb2ludFxuICAgICAgICAgICAgfVxuICAgICAgICAgIH1cbiAgICAgICAgICBicmVha1xuICAgICAgICBjYXNlIDQ6XG4gICAgICAgICAgc2Vjb25kQnl0ZSA9IGJ1ZltpICsgMV1cbiAgICAgICAgICB0aGlyZEJ5dGUgPSBidWZbaSArIDJdXG4gICAgICAgICAgZm91cnRoQnl0ZSA9IGJ1ZltpICsgM11cbiAgICAgICAgICBpZiAoKHNlY29uZEJ5dGUgJiAweEMwKSA9PT0gMHg4MCAmJiAodGhpcmRCeXRlICYgMHhDMCkgPT09IDB4ODAgJiYgKGZvdXJ0aEJ5dGUgJiAweEMwKSA9PT0gMHg4MCkge1xuICAgICAgICAgICAgdGVtcENvZGVQb2ludCA9IChmaXJzdEJ5dGUgJiAweEYpIDw8IDB4MTIgfCAoc2Vjb25kQnl0ZSAmIDB4M0YpIDw8IDB4QyB8ICh0aGlyZEJ5dGUgJiAweDNGKSA8PCAweDYgfCAoZm91cnRoQnl0ZSAmIDB4M0YpXG4gICAgICAgICAgICBpZiAodGVtcENvZGVQb2ludCA+IDB4RkZGRiAmJiB0ZW1wQ29kZVBvaW50IDwgMHgxMTAwMDApIHtcbiAgICAgICAgICAgICAgY29kZVBvaW50ID0gdGVtcENvZGVQb2ludFxuICAgICAgICAgICAgfVxuICAgICAgICAgIH1cbiAgICAgIH1cbiAgICB9XG5cbiAgICBpZiAoY29kZVBvaW50ID09PSBudWxsKSB7XG4gICAgICAvLyB3ZSBkaWQgbm90IGdlbmVyYXRlIGEgdmFsaWQgY29kZVBvaW50IHNvIGluc2VydCBhXG4gICAgICAvLyByZXBsYWNlbWVudCBjaGFyIChVK0ZGRkQpIGFuZCBhZHZhbmNlIG9ubHkgMSBieXRlXG4gICAgICBjb2RlUG9pbnQgPSAweEZGRkRcbiAgICAgIGJ5dGVzUGVyU2VxdWVuY2UgPSAxXG4gICAgfSBlbHNlIGlmIChjb2RlUG9pbnQgPiAweEZGRkYpIHtcbiAgICAgIC8vIGVuY29kZSB0byB1dGYxNiAoc3Vycm9nYXRlIHBhaXIgZGFuY2UpXG4gICAgICBjb2RlUG9pbnQgLT0gMHgxMDAwMFxuICAgICAgcmVzLnB1c2goY29kZVBvaW50ID4+PiAxMCAmIDB4M0ZGIHwgMHhEODAwKVxuICAgICAgY29kZVBvaW50ID0gMHhEQzAwIHwgY29kZVBvaW50ICYgMHgzRkZcbiAgICB9XG5cbiAgICByZXMucHVzaChjb2RlUG9pbnQpXG4gICAgaSArPSBieXRlc1BlclNlcXVlbmNlXG4gIH1cblxuICByZXR1cm4gZGVjb2RlQ29kZVBvaW50c0FycmF5KHJlcylcbn1cblxuLy8gQmFzZWQgb24gaHR0cDovL3N0YWNrb3ZlcmZsb3cuY29tL2EvMjI3NDcyNzIvNjgwNzQyLCB0aGUgYnJvd3NlciB3aXRoXG4vLyB0aGUgbG93ZXN0IGxpbWl0IGlzIENocm9tZSwgd2l0aCAweDEwMDAwIGFyZ3MuXG4vLyBXZSBnbyAxIG1hZ25pdHVkZSBsZXNzLCBmb3Igc2FmZXR5XG52YXIgTUFYX0FSR1VNRU5UU19MRU5HVEggPSAweDEwMDBcblxuZnVuY3Rpb24gZGVjb2RlQ29kZVBvaW50c0FycmF5IChjb2RlUG9pbnRzKSB7XG4gIHZhciBsZW4gPSBjb2RlUG9pbnRzLmxlbmd0aFxuICBpZiAobGVuIDw9IE1BWF9BUkdVTUVOVFNfTEVOR1RIKSB7XG4gICAgcmV0dXJuIFN0cmluZy5mcm9tQ2hhckNvZGUuYXBwbHkoU3RyaW5nLCBjb2RlUG9pbnRzKSAvLyBhdm9pZCBleHRyYSBzbGljZSgpXG4gIH1cblxuICAvLyBEZWNvZGUgaW4gY2h1bmtzIHRvIGF2b2lkIFwiY2FsbCBzdGFjayBzaXplIGV4Y2VlZGVkXCIuXG4gIHZhciByZXMgPSAnJ1xuICB2YXIgaSA9IDBcbiAgd2hpbGUgKGkgPCBsZW4pIHtcbiAgICByZXMgKz0gU3RyaW5nLmZyb21DaGFyQ29kZS5hcHBseShcbiAgICAgIFN0cmluZyxcbiAgICAgIGNvZGVQb2ludHMuc2xpY2UoaSwgaSArPSBNQVhfQVJHVU1FTlRTX0xFTkdUSClcbiAgICApXG4gIH1cbiAgcmV0dXJuIHJlc1xufVxuXG5mdW5jdGlvbiBhc2NpaVNsaWNlIChidWYsIHN0YXJ0LCBlbmQpIHtcbiAgdmFyIHJldCA9ICcnXG4gIGVuZCA9IE1hdGgubWluKGJ1Zi5sZW5ndGgsIGVuZClcblxuICBmb3IgKHZhciBpID0gc3RhcnQ7IGkgPCBlbmQ7ICsraSkge1xuICAgIHJldCArPSBTdHJpbmcuZnJvbUNoYXJDb2RlKGJ1ZltpXSAmIDB4N0YpXG4gIH1cbiAgcmV0dXJuIHJldFxufVxuXG5mdW5jdGlvbiBiaW5hcnlTbGljZSAoYnVmLCBzdGFydCwgZW5kKSB7XG4gIHZhciByZXQgPSAnJ1xuICBlbmQgPSBNYXRoLm1pbihidWYubGVuZ3RoLCBlbmQpXG5cbiAgZm9yICh2YXIgaSA9IHN0YXJ0OyBpIDwgZW5kOyArK2kpIHtcbiAgICByZXQgKz0gU3RyaW5nLmZyb21DaGFyQ29kZShidWZbaV0pXG4gIH1cbiAgcmV0dXJuIHJldFxufVxuXG5mdW5jdGlvbiBoZXhTbGljZSAoYnVmLCBzdGFydCwgZW5kKSB7XG4gIHZhciBsZW4gPSBidWYubGVuZ3RoXG5cbiAgaWYgKCFzdGFydCB8fCBzdGFydCA8IDApIHN0YXJ0ID0gMFxuICBpZiAoIWVuZCB8fCBlbmQgPCAwIHx8IGVuZCA+IGxlbikgZW5kID0gbGVuXG5cbiAgdmFyIG91dCA9ICcnXG4gIGZvciAodmFyIGkgPSBzdGFydDsgaSA8IGVuZDsgKytpKSB7XG4gICAgb3V0ICs9IHRvSGV4KGJ1ZltpXSlcbiAgfVxuICByZXR1cm4gb3V0XG59XG5cbmZ1bmN0aW9uIHV0ZjE2bGVTbGljZSAoYnVmLCBzdGFydCwgZW5kKSB7XG4gIHZhciBieXRlcyA9IGJ1Zi5zbGljZShzdGFydCwgZW5kKVxuICB2YXIgcmVzID0gJydcbiAgZm9yICh2YXIgaSA9IDA7IGkgPCBieXRlcy5sZW5ndGg7IGkgKz0gMikge1xuICAgIHJlcyArPSBTdHJpbmcuZnJvbUNoYXJDb2RlKGJ5dGVzW2ldICsgYnl0ZXNbaSArIDFdICogMjU2KVxuICB9XG4gIHJldHVybiByZXNcbn1cblxuQnVmZmVyLnByb3RvdHlwZS5zbGljZSA9IGZ1bmN0aW9uIHNsaWNlIChzdGFydCwgZW5kKSB7XG4gIHZhciBsZW4gPSB0aGlzLmxlbmd0aFxuICBzdGFydCA9IH5+c3RhcnRcbiAgZW5kID0gZW5kID09PSB1bmRlZmluZWQgPyBsZW4gOiB+fmVuZFxuXG4gIGlmIChzdGFydCA8IDApIHtcbiAgICBzdGFydCArPSBsZW5cbiAgICBpZiAoc3RhcnQgPCAwKSBzdGFydCA9IDBcbiAgfSBlbHNlIGlmIChzdGFydCA+IGxlbikge1xuICAgIHN0YXJ0ID0gbGVuXG4gIH1cblxuICBpZiAoZW5kIDwgMCkge1xuICAgIGVuZCArPSBsZW5cbiAgICBpZiAoZW5kIDwgMCkgZW5kID0gMFxuICB9IGVsc2UgaWYgKGVuZCA+IGxlbikge1xuICAgIGVuZCA9IGxlblxuICB9XG5cbiAgaWYgKGVuZCA8IHN0YXJ0KSBlbmQgPSBzdGFydFxuXG4gIHZhciBuZXdCdWZcbiAgaWYgKEJ1ZmZlci5UWVBFRF9BUlJBWV9TVVBQT1JUKSB7XG4gICAgbmV3QnVmID0gdGhpcy5zdWJhcnJheShzdGFydCwgZW5kKVxuICAgIG5ld0J1Zi5fX3Byb3RvX18gPSBCdWZmZXIucHJvdG90eXBlXG4gIH0gZWxzZSB7XG4gICAgdmFyIHNsaWNlTGVuID0gZW5kIC0gc3RhcnRcbiAgICBuZXdCdWYgPSBuZXcgQnVmZmVyKHNsaWNlTGVuLCB1bmRlZmluZWQpXG4gICAgZm9yICh2YXIgaSA9IDA7IGkgPCBzbGljZUxlbjsgKytpKSB7XG4gICAgICBuZXdCdWZbaV0gPSB0aGlzW2kgKyBzdGFydF1cbiAgICB9XG4gIH1cblxuICByZXR1cm4gbmV3QnVmXG59XG5cbi8qXG4gKiBOZWVkIHRvIG1ha2Ugc3VyZSB0aGF0IGJ1ZmZlciBpc24ndCB0cnlpbmcgdG8gd3JpdGUgb3V0IG9mIGJvdW5kcy5cbiAqL1xuZnVuY3Rpb24gY2hlY2tPZmZzZXQgKG9mZnNldCwgZXh0LCBsZW5ndGgpIHtcbiAgaWYgKChvZmZzZXQgJSAxKSAhPT0gMCB8fCBvZmZzZXQgPCAwKSB0aHJvdyBuZXcgUmFuZ2VFcnJvcignb2Zmc2V0IGlzIG5vdCB1aW50JylcbiAgaWYgKG9mZnNldCArIGV4dCA+IGxlbmd0aCkgdGhyb3cgbmV3IFJhbmdlRXJyb3IoJ1RyeWluZyB0byBhY2Nlc3MgYmV5b25kIGJ1ZmZlciBsZW5ndGgnKVxufVxuXG5CdWZmZXIucHJvdG90eXBlLnJlYWRVSW50TEUgPSBmdW5jdGlvbiByZWFkVUludExFIChvZmZzZXQsIGJ5dGVMZW5ndGgsIG5vQXNzZXJ0KSB7XG4gIG9mZnNldCA9IG9mZnNldCB8IDBcbiAgYnl0ZUxlbmd0aCA9IGJ5dGVMZW5ndGggfCAwXG4gIGlmICghbm9Bc3NlcnQpIGNoZWNrT2Zmc2V0KG9mZnNldCwgYnl0ZUxlbmd0aCwgdGhpcy5sZW5ndGgpXG5cbiAgdmFyIHZhbCA9IHRoaXNbb2Zmc2V0XVxuICB2YXIgbXVsID0gMVxuICB2YXIgaSA9IDBcbiAgd2hpbGUgKCsraSA8IGJ5dGVMZW5ndGggJiYgKG11bCAqPSAweDEwMCkpIHtcbiAgICB2YWwgKz0gdGhpc1tvZmZzZXQgKyBpXSAqIG11bFxuICB9XG5cbiAgcmV0dXJuIHZhbFxufVxuXG5CdWZmZXIucHJvdG90eXBlLnJlYWRVSW50QkUgPSBmdW5jdGlvbiByZWFkVUludEJFIChvZmZzZXQsIGJ5dGVMZW5ndGgsIG5vQXNzZXJ0KSB7XG4gIG9mZnNldCA9IG9mZnNldCB8IDBcbiAgYnl0ZUxlbmd0aCA9IGJ5dGVMZW5ndGggfCAwXG4gIGlmICghbm9Bc3NlcnQpIHtcbiAgICBjaGVja09mZnNldChvZmZzZXQsIGJ5dGVMZW5ndGgsIHRoaXMubGVuZ3RoKVxuICB9XG5cbiAgdmFyIHZhbCA9IHRoaXNbb2Zmc2V0ICsgLS1ieXRlTGVuZ3RoXVxuICB2YXIgbXVsID0gMVxuICB3aGlsZSAoYnl0ZUxlbmd0aCA+IDAgJiYgKG11bCAqPSAweDEwMCkpIHtcbiAgICB2YWwgKz0gdGhpc1tvZmZzZXQgKyAtLWJ5dGVMZW5ndGhdICogbXVsXG4gIH1cblxuICByZXR1cm4gdmFsXG59XG5cbkJ1ZmZlci5wcm90b3R5cGUucmVhZFVJbnQ4ID0gZnVuY3Rpb24gcmVhZFVJbnQ4IChvZmZzZXQsIG5vQXNzZXJ0KSB7XG4gIGlmICghbm9Bc3NlcnQpIGNoZWNrT2Zmc2V0KG9mZnNldCwgMSwgdGhpcy5sZW5ndGgpXG4gIHJldHVybiB0aGlzW29mZnNldF1cbn1cblxuQnVmZmVyLnByb3RvdHlwZS5yZWFkVUludDE2TEUgPSBmdW5jdGlvbiByZWFkVUludDE2TEUgKG9mZnNldCwgbm9Bc3NlcnQpIHtcbiAgaWYgKCFub0Fzc2VydCkgY2hlY2tPZmZzZXQob2Zmc2V0LCAyLCB0aGlzLmxlbmd0aClcbiAgcmV0dXJuIHRoaXNbb2Zmc2V0XSB8ICh0aGlzW29mZnNldCArIDFdIDw8IDgpXG59XG5cbkJ1ZmZlci5wcm90b3R5cGUucmVhZFVJbnQxNkJFID0gZnVuY3Rpb24gcmVhZFVJbnQxNkJFIChvZmZzZXQsIG5vQXNzZXJ0KSB7XG4gIGlmICghbm9Bc3NlcnQpIGNoZWNrT2Zmc2V0KG9mZnNldCwgMiwgdGhpcy5sZW5ndGgpXG4gIHJldHVybiAodGhpc1tvZmZzZXRdIDw8IDgpIHwgdGhpc1tvZmZzZXQgKyAxXVxufVxuXG5CdWZmZXIucHJvdG90eXBlLnJlYWRVSW50MzJMRSA9IGZ1bmN0aW9uIHJlYWRVSW50MzJMRSAob2Zmc2V0LCBub0Fzc2VydCkge1xuICBpZiAoIW5vQXNzZXJ0KSBjaGVja09mZnNldChvZmZzZXQsIDQsIHRoaXMubGVuZ3RoKVxuXG4gIHJldHVybiAoKHRoaXNbb2Zmc2V0XSkgfFxuICAgICAgKHRoaXNbb2Zmc2V0ICsgMV0gPDwgOCkgfFxuICAgICAgKHRoaXNbb2Zmc2V0ICsgMl0gPDwgMTYpKSArXG4gICAgICAodGhpc1tvZmZzZXQgKyAzXSAqIDB4MTAwMDAwMClcbn1cblxuQnVmZmVyLnByb3RvdHlwZS5yZWFkVUludDMyQkUgPSBmdW5jdGlvbiByZWFkVUludDMyQkUgKG9mZnNldCwgbm9Bc3NlcnQpIHtcbiAgaWYgKCFub0Fzc2VydCkgY2hlY2tPZmZzZXQob2Zmc2V0LCA0LCB0aGlzLmxlbmd0aClcblxuICByZXR1cm4gKHRoaXNbb2Zmc2V0XSAqIDB4MTAwMDAwMCkgK1xuICAgICgodGhpc1tvZmZzZXQgKyAxXSA8PCAxNikgfFxuICAgICh0aGlzW29mZnNldCArIDJdIDw8IDgpIHxcbiAgICB0aGlzW29mZnNldCArIDNdKVxufVxuXG5CdWZmZXIucHJvdG90eXBlLnJlYWRJbnRMRSA9IGZ1bmN0aW9uIHJlYWRJbnRMRSAob2Zmc2V0LCBieXRlTGVuZ3RoLCBub0Fzc2VydCkge1xuICBvZmZzZXQgPSBvZmZzZXQgfCAwXG4gIGJ5dGVMZW5ndGggPSBieXRlTGVuZ3RoIHwgMFxuICBpZiAoIW5vQXNzZXJ0KSBjaGVja09mZnNldChvZmZzZXQsIGJ5dGVMZW5ndGgsIHRoaXMubGVuZ3RoKVxuXG4gIHZhciB2YWwgPSB0aGlzW29mZnNldF1cbiAgdmFyIG11bCA9IDFcbiAgdmFyIGkgPSAwXG4gIHdoaWxlICgrK2kgPCBieXRlTGVuZ3RoICYmIChtdWwgKj0gMHgxMDApKSB7XG4gICAgdmFsICs9IHRoaXNbb2Zmc2V0ICsgaV0gKiBtdWxcbiAgfVxuICBtdWwgKj0gMHg4MFxuXG4gIGlmICh2YWwgPj0gbXVsKSB2YWwgLT0gTWF0aC5wb3coMiwgOCAqIGJ5dGVMZW5ndGgpXG5cbiAgcmV0dXJuIHZhbFxufVxuXG5CdWZmZXIucHJvdG90eXBlLnJlYWRJbnRCRSA9IGZ1bmN0aW9uIHJlYWRJbnRCRSAob2Zmc2V0LCBieXRlTGVuZ3RoLCBub0Fzc2VydCkge1xuICBvZmZzZXQgPSBvZmZzZXQgfCAwXG4gIGJ5dGVMZW5ndGggPSBieXRlTGVuZ3RoIHwgMFxuICBpZiAoIW5vQXNzZXJ0KSBjaGVja09mZnNldChvZmZzZXQsIGJ5dGVMZW5ndGgsIHRoaXMubGVuZ3RoKVxuXG4gIHZhciBpID0gYnl0ZUxlbmd0aFxuICB2YXIgbXVsID0gMVxuICB2YXIgdmFsID0gdGhpc1tvZmZzZXQgKyAtLWldXG4gIHdoaWxlIChpID4gMCAmJiAobXVsICo9IDB4MTAwKSkge1xuICAgIHZhbCArPSB0aGlzW29mZnNldCArIC0taV0gKiBtdWxcbiAgfVxuICBtdWwgKj0gMHg4MFxuXG4gIGlmICh2YWwgPj0gbXVsKSB2YWwgLT0gTWF0aC5wb3coMiwgOCAqIGJ5dGVMZW5ndGgpXG5cbiAgcmV0dXJuIHZhbFxufVxuXG5CdWZmZXIucHJvdG90eXBlLnJlYWRJbnQ4ID0gZnVuY3Rpb24gcmVhZEludDggKG9mZnNldCwgbm9Bc3NlcnQpIHtcbiAgaWYgKCFub0Fzc2VydCkgY2hlY2tPZmZzZXQob2Zmc2V0LCAxLCB0aGlzLmxlbmd0aClcbiAgaWYgKCEodGhpc1tvZmZzZXRdICYgMHg4MCkpIHJldHVybiAodGhpc1tvZmZzZXRdKVxuICByZXR1cm4gKCgweGZmIC0gdGhpc1tvZmZzZXRdICsgMSkgKiAtMSlcbn1cblxuQnVmZmVyLnByb3RvdHlwZS5yZWFkSW50MTZMRSA9IGZ1bmN0aW9uIHJlYWRJbnQxNkxFIChvZmZzZXQsIG5vQXNzZXJ0KSB7XG4gIGlmICghbm9Bc3NlcnQpIGNoZWNrT2Zmc2V0KG9mZnNldCwgMiwgdGhpcy5sZW5ndGgpXG4gIHZhciB2YWwgPSB0aGlzW29mZnNldF0gfCAodGhpc1tvZmZzZXQgKyAxXSA8PCA4KVxuICByZXR1cm4gKHZhbCAmIDB4ODAwMCkgPyB2YWwgfCAweEZGRkYwMDAwIDogdmFsXG59XG5cbkJ1ZmZlci5wcm90b3R5cGUucmVhZEludDE2QkUgPSBmdW5jdGlvbiByZWFkSW50MTZCRSAob2Zmc2V0LCBub0Fzc2VydCkge1xuICBpZiAoIW5vQXNzZXJ0KSBjaGVja09mZnNldChvZmZzZXQsIDIsIHRoaXMubGVuZ3RoKVxuICB2YXIgdmFsID0gdGhpc1tvZmZzZXQgKyAxXSB8ICh0aGlzW29mZnNldF0gPDwgOClcbiAgcmV0dXJuICh2YWwgJiAweDgwMDApID8gdmFsIHwgMHhGRkZGMDAwMCA6IHZhbFxufVxuXG5CdWZmZXIucHJvdG90eXBlLnJlYWRJbnQzMkxFID0gZnVuY3Rpb24gcmVhZEludDMyTEUgKG9mZnNldCwgbm9Bc3NlcnQpIHtcbiAgaWYgKCFub0Fzc2VydCkgY2hlY2tPZmZzZXQob2Zmc2V0LCA0LCB0aGlzLmxlbmd0aClcblxuICByZXR1cm4gKHRoaXNbb2Zmc2V0XSkgfFxuICAgICh0aGlzW29mZnNldCArIDFdIDw8IDgpIHxcbiAgICAodGhpc1tvZmZzZXQgKyAyXSA8PCAxNikgfFxuICAgICh0aGlzW29mZnNldCArIDNdIDw8IDI0KVxufVxuXG5CdWZmZXIucHJvdG90eXBlLnJlYWRJbnQzMkJFID0gZnVuY3Rpb24gcmVhZEludDMyQkUgKG9mZnNldCwgbm9Bc3NlcnQpIHtcbiAgaWYgKCFub0Fzc2VydCkgY2hlY2tPZmZzZXQob2Zmc2V0LCA0LCB0aGlzLmxlbmd0aClcblxuICByZXR1cm4gKHRoaXNbb2Zmc2V0XSA8PCAyNCkgfFxuICAgICh0aGlzW29mZnNldCArIDFdIDw8IDE2KSB8XG4gICAgKHRoaXNbb2Zmc2V0ICsgMl0gPDwgOCkgfFxuICAgICh0aGlzW29mZnNldCArIDNdKVxufVxuXG5CdWZmZXIucHJvdG90eXBlLnJlYWRGbG9hdExFID0gZnVuY3Rpb24gcmVhZEZsb2F0TEUgKG9mZnNldCwgbm9Bc3NlcnQpIHtcbiAgaWYgKCFub0Fzc2VydCkgY2hlY2tPZmZzZXQob2Zmc2V0LCA0LCB0aGlzLmxlbmd0aClcbiAgcmV0dXJuIGllZWU3NTQucmVhZCh0aGlzLCBvZmZzZXQsIHRydWUsIDIzLCA0KVxufVxuXG5CdWZmZXIucHJvdG90eXBlLnJlYWRGbG9hdEJFID0gZnVuY3Rpb24gcmVhZEZsb2F0QkUgKG9mZnNldCwgbm9Bc3NlcnQpIHtcbiAgaWYgKCFub0Fzc2VydCkgY2hlY2tPZmZzZXQob2Zmc2V0LCA0LCB0aGlzLmxlbmd0aClcbiAgcmV0dXJuIGllZWU3NTQucmVhZCh0aGlzLCBvZmZzZXQsIGZhbHNlLCAyMywgNClcbn1cblxuQnVmZmVyLnByb3RvdHlwZS5yZWFkRG91YmxlTEUgPSBmdW5jdGlvbiByZWFkRG91YmxlTEUgKG9mZnNldCwgbm9Bc3NlcnQpIHtcbiAgaWYgKCFub0Fzc2VydCkgY2hlY2tPZmZzZXQob2Zmc2V0LCA4LCB0aGlzLmxlbmd0aClcbiAgcmV0dXJuIGllZWU3NTQucmVhZCh0aGlzLCBvZmZzZXQsIHRydWUsIDUyLCA4KVxufVxuXG5CdWZmZXIucHJvdG90eXBlLnJlYWREb3VibGVCRSA9IGZ1bmN0aW9uIHJlYWREb3VibGVCRSAob2Zmc2V0LCBub0Fzc2VydCkge1xuICBpZiAoIW5vQXNzZXJ0KSBjaGVja09mZnNldChvZmZzZXQsIDgsIHRoaXMubGVuZ3RoKVxuICByZXR1cm4gaWVlZTc1NC5yZWFkKHRoaXMsIG9mZnNldCwgZmFsc2UsIDUyLCA4KVxufVxuXG5mdW5jdGlvbiBjaGVja0ludCAoYnVmLCB2YWx1ZSwgb2Zmc2V0LCBleHQsIG1heCwgbWluKSB7XG4gIGlmICghQnVmZmVyLmlzQnVmZmVyKGJ1ZikpIHRocm93IG5ldyBUeXBlRXJyb3IoJ1wiYnVmZmVyXCIgYXJndW1lbnQgbXVzdCBiZSBhIEJ1ZmZlciBpbnN0YW5jZScpXG4gIGlmICh2YWx1ZSA+IG1heCB8fCB2YWx1ZSA8IG1pbikgdGhyb3cgbmV3IFJhbmdlRXJyb3IoJ1widmFsdWVcIiBhcmd1bWVudCBpcyBvdXQgb2YgYm91bmRzJylcbiAgaWYgKG9mZnNldCArIGV4dCA+IGJ1Zi5sZW5ndGgpIHRocm93IG5ldyBSYW5nZUVycm9yKCdJbmRleCBvdXQgb2YgcmFuZ2UnKVxufVxuXG5CdWZmZXIucHJvdG90eXBlLndyaXRlVUludExFID0gZnVuY3Rpb24gd3JpdGVVSW50TEUgKHZhbHVlLCBvZmZzZXQsIGJ5dGVMZW5ndGgsIG5vQXNzZXJ0KSB7XG4gIHZhbHVlID0gK3ZhbHVlXG4gIG9mZnNldCA9IG9mZnNldCB8IDBcbiAgYnl0ZUxlbmd0aCA9IGJ5dGVMZW5ndGggfCAwXG4gIGlmICghbm9Bc3NlcnQpIHtcbiAgICB2YXIgbWF4Qnl0ZXMgPSBNYXRoLnBvdygyLCA4ICogYnl0ZUxlbmd0aCkgLSAxXG4gICAgY2hlY2tJbnQodGhpcywgdmFsdWUsIG9mZnNldCwgYnl0ZUxlbmd0aCwgbWF4Qnl0ZXMsIDApXG4gIH1cblxuICB2YXIgbXVsID0gMVxuICB2YXIgaSA9IDBcbiAgdGhpc1tvZmZzZXRdID0gdmFsdWUgJiAweEZGXG4gIHdoaWxlICgrK2kgPCBieXRlTGVuZ3RoICYmIChtdWwgKj0gMHgxMDApKSB7XG4gICAgdGhpc1tvZmZzZXQgKyBpXSA9ICh2YWx1ZSAvIG11bCkgJiAweEZGXG4gIH1cblxuICByZXR1cm4gb2Zmc2V0ICsgYnl0ZUxlbmd0aFxufVxuXG5CdWZmZXIucHJvdG90eXBlLndyaXRlVUludEJFID0gZnVuY3Rpb24gd3JpdGVVSW50QkUgKHZhbHVlLCBvZmZzZXQsIGJ5dGVMZW5ndGgsIG5vQXNzZXJ0KSB7XG4gIHZhbHVlID0gK3ZhbHVlXG4gIG9mZnNldCA9IG9mZnNldCB8IDBcbiAgYnl0ZUxlbmd0aCA9IGJ5dGVMZW5ndGggfCAwXG4gIGlmICghbm9Bc3NlcnQpIHtcbiAgICB2YXIgbWF4Qnl0ZXMgPSBNYXRoLnBvdygyLCA4ICogYnl0ZUxlbmd0aCkgLSAxXG4gICAgY2hlY2tJbnQodGhpcywgdmFsdWUsIG9mZnNldCwgYnl0ZUxlbmd0aCwgbWF4Qnl0ZXMsIDApXG4gIH1cblxuICB2YXIgaSA9IGJ5dGVMZW5ndGggLSAxXG4gIHZhciBtdWwgPSAxXG4gIHRoaXNbb2Zmc2V0ICsgaV0gPSB2YWx1ZSAmIDB4RkZcbiAgd2hpbGUgKC0taSA+PSAwICYmIChtdWwgKj0gMHgxMDApKSB7XG4gICAgdGhpc1tvZmZzZXQgKyBpXSA9ICh2YWx1ZSAvIG11bCkgJiAweEZGXG4gIH1cblxuICByZXR1cm4gb2Zmc2V0ICsgYnl0ZUxlbmd0aFxufVxuXG5CdWZmZXIucHJvdG90eXBlLndyaXRlVUludDggPSBmdW5jdGlvbiB3cml0ZVVJbnQ4ICh2YWx1ZSwgb2Zmc2V0LCBub0Fzc2VydCkge1xuICB2YWx1ZSA9ICt2YWx1ZVxuICBvZmZzZXQgPSBvZmZzZXQgfCAwXG4gIGlmICghbm9Bc3NlcnQpIGNoZWNrSW50KHRoaXMsIHZhbHVlLCBvZmZzZXQsIDEsIDB4ZmYsIDApXG4gIGlmICghQnVmZmVyLlRZUEVEX0FSUkFZX1NVUFBPUlQpIHZhbHVlID0gTWF0aC5mbG9vcih2YWx1ZSlcbiAgdGhpc1tvZmZzZXRdID0gKHZhbHVlICYgMHhmZilcbiAgcmV0dXJuIG9mZnNldCArIDFcbn1cblxuZnVuY3Rpb24gb2JqZWN0V3JpdGVVSW50MTYgKGJ1ZiwgdmFsdWUsIG9mZnNldCwgbGl0dGxlRW5kaWFuKSB7XG4gIGlmICh2YWx1ZSA8IDApIHZhbHVlID0gMHhmZmZmICsgdmFsdWUgKyAxXG4gIGZvciAodmFyIGkgPSAwLCBqID0gTWF0aC5taW4oYnVmLmxlbmd0aCAtIG9mZnNldCwgMik7IGkgPCBqOyArK2kpIHtcbiAgICBidWZbb2Zmc2V0ICsgaV0gPSAodmFsdWUgJiAoMHhmZiA8PCAoOCAqIChsaXR0bGVFbmRpYW4gPyBpIDogMSAtIGkpKSkpID4+PlxuICAgICAgKGxpdHRsZUVuZGlhbiA/IGkgOiAxIC0gaSkgKiA4XG4gIH1cbn1cblxuQnVmZmVyLnByb3RvdHlwZS53cml0ZVVJbnQxNkxFID0gZnVuY3Rpb24gd3JpdGVVSW50MTZMRSAodmFsdWUsIG9mZnNldCwgbm9Bc3NlcnQpIHtcbiAgdmFsdWUgPSArdmFsdWVcbiAgb2Zmc2V0ID0gb2Zmc2V0IHwgMFxuICBpZiAoIW5vQXNzZXJ0KSBjaGVja0ludCh0aGlzLCB2YWx1ZSwgb2Zmc2V0LCAyLCAweGZmZmYsIDApXG4gIGlmIChCdWZmZXIuVFlQRURfQVJSQVlfU1VQUE9SVCkge1xuICAgIHRoaXNbb2Zmc2V0XSA9ICh2YWx1ZSAmIDB4ZmYpXG4gICAgdGhpc1tvZmZzZXQgKyAxXSA9ICh2YWx1ZSA+Pj4gOClcbiAgfSBlbHNlIHtcbiAgICBvYmplY3RXcml0ZVVJbnQxNih0aGlzLCB2YWx1ZSwgb2Zmc2V0LCB0cnVlKVxuICB9XG4gIHJldHVybiBvZmZzZXQgKyAyXG59XG5cbkJ1ZmZlci5wcm90b3R5cGUud3JpdGVVSW50MTZCRSA9IGZ1bmN0aW9uIHdyaXRlVUludDE2QkUgKHZhbHVlLCBvZmZzZXQsIG5vQXNzZXJ0KSB7XG4gIHZhbHVlID0gK3ZhbHVlXG4gIG9mZnNldCA9IG9mZnNldCB8IDBcbiAgaWYgKCFub0Fzc2VydCkgY2hlY2tJbnQodGhpcywgdmFsdWUsIG9mZnNldCwgMiwgMHhmZmZmLCAwKVxuICBpZiAoQnVmZmVyLlRZUEVEX0FSUkFZX1NVUFBPUlQpIHtcbiAgICB0aGlzW29mZnNldF0gPSAodmFsdWUgPj4+IDgpXG4gICAgdGhpc1tvZmZzZXQgKyAxXSA9ICh2YWx1ZSAmIDB4ZmYpXG4gIH0gZWxzZSB7XG4gICAgb2JqZWN0V3JpdGVVSW50MTYodGhpcywgdmFsdWUsIG9mZnNldCwgZmFsc2UpXG4gIH1cbiAgcmV0dXJuIG9mZnNldCArIDJcbn1cblxuZnVuY3Rpb24gb2JqZWN0V3JpdGVVSW50MzIgKGJ1ZiwgdmFsdWUsIG9mZnNldCwgbGl0dGxlRW5kaWFuKSB7XG4gIGlmICh2YWx1ZSA8IDApIHZhbHVlID0gMHhmZmZmZmZmZiArIHZhbHVlICsgMVxuICBmb3IgKHZhciBpID0gMCwgaiA9IE1hdGgubWluKGJ1Zi5sZW5ndGggLSBvZmZzZXQsIDQpOyBpIDwgajsgKytpKSB7XG4gICAgYnVmW29mZnNldCArIGldID0gKHZhbHVlID4+PiAobGl0dGxlRW5kaWFuID8gaSA6IDMgLSBpKSAqIDgpICYgMHhmZlxuICB9XG59XG5cbkJ1ZmZlci5wcm90b3R5cGUud3JpdGVVSW50MzJMRSA9IGZ1bmN0aW9uIHdyaXRlVUludDMyTEUgKHZhbHVlLCBvZmZzZXQsIG5vQXNzZXJ0KSB7XG4gIHZhbHVlID0gK3ZhbHVlXG4gIG9mZnNldCA9IG9mZnNldCB8IDBcbiAgaWYgKCFub0Fzc2VydCkgY2hlY2tJbnQodGhpcywgdmFsdWUsIG9mZnNldCwgNCwgMHhmZmZmZmZmZiwgMClcbiAgaWYgKEJ1ZmZlci5UWVBFRF9BUlJBWV9TVVBQT1JUKSB7XG4gICAgdGhpc1tvZmZzZXQgKyAzXSA9ICh2YWx1ZSA+Pj4gMjQpXG4gICAgdGhpc1tvZmZzZXQgKyAyXSA9ICh2YWx1ZSA+Pj4gMTYpXG4gICAgdGhpc1tvZmZzZXQgKyAxXSA9ICh2YWx1ZSA+Pj4gOClcbiAgICB0aGlzW29mZnNldF0gPSAodmFsdWUgJiAweGZmKVxuICB9IGVsc2Uge1xuICAgIG9iamVjdFdyaXRlVUludDMyKHRoaXMsIHZhbHVlLCBvZmZzZXQsIHRydWUpXG4gIH1cbiAgcmV0dXJuIG9mZnNldCArIDRcbn1cblxuQnVmZmVyLnByb3RvdHlwZS53cml0ZVVJbnQzMkJFID0gZnVuY3Rpb24gd3JpdGVVSW50MzJCRSAodmFsdWUsIG9mZnNldCwgbm9Bc3NlcnQpIHtcbiAgdmFsdWUgPSArdmFsdWVcbiAgb2Zmc2V0ID0gb2Zmc2V0IHwgMFxuICBpZiAoIW5vQXNzZXJ0KSBjaGVja0ludCh0aGlzLCB2YWx1ZSwgb2Zmc2V0LCA0LCAweGZmZmZmZmZmLCAwKVxuICBpZiAoQnVmZmVyLlRZUEVEX0FSUkFZX1NVUFBPUlQpIHtcbiAgICB0aGlzW29mZnNldF0gPSAodmFsdWUgPj4+IDI0KVxuICAgIHRoaXNbb2Zmc2V0ICsgMV0gPSAodmFsdWUgPj4+IDE2KVxuICAgIHRoaXNbb2Zmc2V0ICsgMl0gPSAodmFsdWUgPj4+IDgpXG4gICAgdGhpc1tvZmZzZXQgKyAzXSA9ICh2YWx1ZSAmIDB4ZmYpXG4gIH0gZWxzZSB7XG4gICAgb2JqZWN0V3JpdGVVSW50MzIodGhpcywgdmFsdWUsIG9mZnNldCwgZmFsc2UpXG4gIH1cbiAgcmV0dXJuIG9mZnNldCArIDRcbn1cblxuQnVmZmVyLnByb3RvdHlwZS53cml0ZUludExFID0gZnVuY3Rpb24gd3JpdGVJbnRMRSAodmFsdWUsIG9mZnNldCwgYnl0ZUxlbmd0aCwgbm9Bc3NlcnQpIHtcbiAgdmFsdWUgPSArdmFsdWVcbiAgb2Zmc2V0ID0gb2Zmc2V0IHwgMFxuICBpZiAoIW5vQXNzZXJ0KSB7XG4gICAgdmFyIGxpbWl0ID0gTWF0aC5wb3coMiwgOCAqIGJ5dGVMZW5ndGggLSAxKVxuXG4gICAgY2hlY2tJbnQodGhpcywgdmFsdWUsIG9mZnNldCwgYnl0ZUxlbmd0aCwgbGltaXQgLSAxLCAtbGltaXQpXG4gIH1cblxuICB2YXIgaSA9IDBcbiAgdmFyIG11bCA9IDFcbiAgdmFyIHN1YiA9IDBcbiAgdGhpc1tvZmZzZXRdID0gdmFsdWUgJiAweEZGXG4gIHdoaWxlICgrK2kgPCBieXRlTGVuZ3RoICYmIChtdWwgKj0gMHgxMDApKSB7XG4gICAgaWYgKHZhbHVlIDwgMCAmJiBzdWIgPT09IDAgJiYgdGhpc1tvZmZzZXQgKyBpIC0gMV0gIT09IDApIHtcbiAgICAgIHN1YiA9IDFcbiAgICB9XG4gICAgdGhpc1tvZmZzZXQgKyBpXSA9ICgodmFsdWUgLyBtdWwpID4+IDApIC0gc3ViICYgMHhGRlxuICB9XG5cbiAgcmV0dXJuIG9mZnNldCArIGJ5dGVMZW5ndGhcbn1cblxuQnVmZmVyLnByb3RvdHlwZS53cml0ZUludEJFID0gZnVuY3Rpb24gd3JpdGVJbnRCRSAodmFsdWUsIG9mZnNldCwgYnl0ZUxlbmd0aCwgbm9Bc3NlcnQpIHtcbiAgdmFsdWUgPSArdmFsdWVcbiAgb2Zmc2V0ID0gb2Zmc2V0IHwgMFxuICBpZiAoIW5vQXNzZXJ0KSB7XG4gICAgdmFyIGxpbWl0ID0gTWF0aC5wb3coMiwgOCAqIGJ5dGVMZW5ndGggLSAxKVxuXG4gICAgY2hlY2tJbnQodGhpcywgdmFsdWUsIG9mZnNldCwgYnl0ZUxlbmd0aCwgbGltaXQgLSAxLCAtbGltaXQpXG4gIH1cblxuICB2YXIgaSA9IGJ5dGVMZW5ndGggLSAxXG4gIHZhciBtdWwgPSAxXG4gIHZhciBzdWIgPSAwXG4gIHRoaXNbb2Zmc2V0ICsgaV0gPSB2YWx1ZSAmIDB4RkZcbiAgd2hpbGUgKC0taSA+PSAwICYmIChtdWwgKj0gMHgxMDApKSB7XG4gICAgaWYgKHZhbHVlIDwgMCAmJiBzdWIgPT09IDAgJiYgdGhpc1tvZmZzZXQgKyBpICsgMV0gIT09IDApIHtcbiAgICAgIHN1YiA9IDFcbiAgICB9XG4gICAgdGhpc1tvZmZzZXQgKyBpXSA9ICgodmFsdWUgLyBtdWwpID4+IDApIC0gc3ViICYgMHhGRlxuICB9XG5cbiAgcmV0dXJuIG9mZnNldCArIGJ5dGVMZW5ndGhcbn1cblxuQnVmZmVyLnByb3RvdHlwZS53cml0ZUludDggPSBmdW5jdGlvbiB3cml0ZUludDggKHZhbHVlLCBvZmZzZXQsIG5vQXNzZXJ0KSB7XG4gIHZhbHVlID0gK3ZhbHVlXG4gIG9mZnNldCA9IG9mZnNldCB8IDBcbiAgaWYgKCFub0Fzc2VydCkgY2hlY2tJbnQodGhpcywgdmFsdWUsIG9mZnNldCwgMSwgMHg3ZiwgLTB4ODApXG4gIGlmICghQnVmZmVyLlRZUEVEX0FSUkFZX1NVUFBPUlQpIHZhbHVlID0gTWF0aC5mbG9vcih2YWx1ZSlcbiAgaWYgKHZhbHVlIDwgMCkgdmFsdWUgPSAweGZmICsgdmFsdWUgKyAxXG4gIHRoaXNbb2Zmc2V0XSA9ICh2YWx1ZSAmIDB4ZmYpXG4gIHJldHVybiBvZmZzZXQgKyAxXG59XG5cbkJ1ZmZlci5wcm90b3R5cGUud3JpdGVJbnQxNkxFID0gZnVuY3Rpb24gd3JpdGVJbnQxNkxFICh2YWx1ZSwgb2Zmc2V0LCBub0Fzc2VydCkge1xuICB2YWx1ZSA9ICt2YWx1ZVxuICBvZmZzZXQgPSBvZmZzZXQgfCAwXG4gIGlmICghbm9Bc3NlcnQpIGNoZWNrSW50KHRoaXMsIHZhbHVlLCBvZmZzZXQsIDIsIDB4N2ZmZiwgLTB4ODAwMClcbiAgaWYgKEJ1ZmZlci5UWVBFRF9BUlJBWV9TVVBQT1JUKSB7XG4gICAgdGhpc1tvZmZzZXRdID0gKHZhbHVlICYgMHhmZilcbiAgICB0aGlzW29mZnNldCArIDFdID0gKHZhbHVlID4+PiA4KVxuICB9IGVsc2Uge1xuICAgIG9iamVjdFdyaXRlVUludDE2KHRoaXMsIHZhbHVlLCBvZmZzZXQsIHRydWUpXG4gIH1cbiAgcmV0dXJuIG9mZnNldCArIDJcbn1cblxuQnVmZmVyLnByb3RvdHlwZS53cml0ZUludDE2QkUgPSBmdW5jdGlvbiB3cml0ZUludDE2QkUgKHZhbHVlLCBvZmZzZXQsIG5vQXNzZXJ0KSB7XG4gIHZhbHVlID0gK3ZhbHVlXG4gIG9mZnNldCA9IG9mZnNldCB8IDBcbiAgaWYgKCFub0Fzc2VydCkgY2hlY2tJbnQodGhpcywgdmFsdWUsIG9mZnNldCwgMiwgMHg3ZmZmLCAtMHg4MDAwKVxuICBpZiAoQnVmZmVyLlRZUEVEX0FSUkFZX1NVUFBPUlQpIHtcbiAgICB0aGlzW29mZnNldF0gPSAodmFsdWUgPj4+IDgpXG4gICAgdGhpc1tvZmZzZXQgKyAxXSA9ICh2YWx1ZSAmIDB4ZmYpXG4gIH0gZWxzZSB7XG4gICAgb2JqZWN0V3JpdGVVSW50MTYodGhpcywgdmFsdWUsIG9mZnNldCwgZmFsc2UpXG4gIH1cbiAgcmV0dXJuIG9mZnNldCArIDJcbn1cblxuQnVmZmVyLnByb3RvdHlwZS53cml0ZUludDMyTEUgPSBmdW5jdGlvbiB3cml0ZUludDMyTEUgKHZhbHVlLCBvZmZzZXQsIG5vQXNzZXJ0KSB7XG4gIHZhbHVlID0gK3ZhbHVlXG4gIG9mZnNldCA9IG9mZnNldCB8IDBcbiAgaWYgKCFub0Fzc2VydCkgY2hlY2tJbnQodGhpcywgdmFsdWUsIG9mZnNldCwgNCwgMHg3ZmZmZmZmZiwgLTB4ODAwMDAwMDApXG4gIGlmIChCdWZmZXIuVFlQRURfQVJSQVlfU1VQUE9SVCkge1xuICAgIHRoaXNbb2Zmc2V0XSA9ICh2YWx1ZSAmIDB4ZmYpXG4gICAgdGhpc1tvZmZzZXQgKyAxXSA9ICh2YWx1ZSA+Pj4gOClcbiAgICB0aGlzW29mZnNldCArIDJdID0gKHZhbHVlID4+PiAxNilcbiAgICB0aGlzW29mZnNldCArIDNdID0gKHZhbHVlID4+PiAyNClcbiAgfSBlbHNlIHtcbiAgICBvYmplY3RXcml0ZVVJbnQzMih0aGlzLCB2YWx1ZSwgb2Zmc2V0LCB0cnVlKVxuICB9XG4gIHJldHVybiBvZmZzZXQgKyA0XG59XG5cbkJ1ZmZlci5wcm90b3R5cGUud3JpdGVJbnQzMkJFID0gZnVuY3Rpb24gd3JpdGVJbnQzMkJFICh2YWx1ZSwgb2Zmc2V0LCBub0Fzc2VydCkge1xuICB2YWx1ZSA9ICt2YWx1ZVxuICBvZmZzZXQgPSBvZmZzZXQgfCAwXG4gIGlmICghbm9Bc3NlcnQpIGNoZWNrSW50KHRoaXMsIHZhbHVlLCBvZmZzZXQsIDQsIDB4N2ZmZmZmZmYsIC0weDgwMDAwMDAwKVxuICBpZiAodmFsdWUgPCAwKSB2YWx1ZSA9IDB4ZmZmZmZmZmYgKyB2YWx1ZSArIDFcbiAgaWYgKEJ1ZmZlci5UWVBFRF9BUlJBWV9TVVBQT1JUKSB7XG4gICAgdGhpc1tvZmZzZXRdID0gKHZhbHVlID4+PiAyNClcbiAgICB0aGlzW29mZnNldCArIDFdID0gKHZhbHVlID4+PiAxNilcbiAgICB0aGlzW29mZnNldCArIDJdID0gKHZhbHVlID4+PiA4KVxuICAgIHRoaXNbb2Zmc2V0ICsgM10gPSAodmFsdWUgJiAweGZmKVxuICB9IGVsc2Uge1xuICAgIG9iamVjdFdyaXRlVUludDMyKHRoaXMsIHZhbHVlLCBvZmZzZXQsIGZhbHNlKVxuICB9XG4gIHJldHVybiBvZmZzZXQgKyA0XG59XG5cbmZ1bmN0aW9uIGNoZWNrSUVFRTc1NCAoYnVmLCB2YWx1ZSwgb2Zmc2V0LCBleHQsIG1heCwgbWluKSB7XG4gIGlmIChvZmZzZXQgKyBleHQgPiBidWYubGVuZ3RoKSB0aHJvdyBuZXcgUmFuZ2VFcnJvcignSW5kZXggb3V0IG9mIHJhbmdlJylcbiAgaWYgKG9mZnNldCA8IDApIHRocm93IG5ldyBSYW5nZUVycm9yKCdJbmRleCBvdXQgb2YgcmFuZ2UnKVxufVxuXG5mdW5jdGlvbiB3cml0ZUZsb2F0IChidWYsIHZhbHVlLCBvZmZzZXQsIGxpdHRsZUVuZGlhbiwgbm9Bc3NlcnQpIHtcbiAgaWYgKCFub0Fzc2VydCkge1xuICAgIGNoZWNrSUVFRTc1NChidWYsIHZhbHVlLCBvZmZzZXQsIDQsIDMuNDAyODIzNDY2Mzg1Mjg4NmUrMzgsIC0zLjQwMjgyMzQ2NjM4NTI4ODZlKzM4KVxuICB9XG4gIGllZWU3NTQud3JpdGUoYnVmLCB2YWx1ZSwgb2Zmc2V0LCBsaXR0bGVFbmRpYW4sIDIzLCA0KVxuICByZXR1cm4gb2Zmc2V0ICsgNFxufVxuXG5CdWZmZXIucHJvdG90eXBlLndyaXRlRmxvYXRMRSA9IGZ1bmN0aW9uIHdyaXRlRmxvYXRMRSAodmFsdWUsIG9mZnNldCwgbm9Bc3NlcnQpIHtcbiAgcmV0dXJuIHdyaXRlRmxvYXQodGhpcywgdmFsdWUsIG9mZnNldCwgdHJ1ZSwgbm9Bc3NlcnQpXG59XG5cbkJ1ZmZlci5wcm90b3R5cGUud3JpdGVGbG9hdEJFID0gZnVuY3Rpb24gd3JpdGVGbG9hdEJFICh2YWx1ZSwgb2Zmc2V0LCBub0Fzc2VydCkge1xuICByZXR1cm4gd3JpdGVGbG9hdCh0aGlzLCB2YWx1ZSwgb2Zmc2V0LCBmYWxzZSwgbm9Bc3NlcnQpXG59XG5cbmZ1bmN0aW9uIHdyaXRlRG91YmxlIChidWYsIHZhbHVlLCBvZmZzZXQsIGxpdHRsZUVuZGlhbiwgbm9Bc3NlcnQpIHtcbiAgaWYgKCFub0Fzc2VydCkge1xuICAgIGNoZWNrSUVFRTc1NChidWYsIHZhbHVlLCBvZmZzZXQsIDgsIDEuNzk3NjkzMTM0ODYyMzE1N0UrMzA4LCAtMS43OTc2OTMxMzQ4NjIzMTU3RSszMDgpXG4gIH1cbiAgaWVlZTc1NC53cml0ZShidWYsIHZhbHVlLCBvZmZzZXQsIGxpdHRsZUVuZGlhbiwgNTIsIDgpXG4gIHJldHVybiBvZmZzZXQgKyA4XG59XG5cbkJ1ZmZlci5wcm90b3R5cGUud3JpdGVEb3VibGVMRSA9IGZ1bmN0aW9uIHdyaXRlRG91YmxlTEUgKHZhbHVlLCBvZmZzZXQsIG5vQXNzZXJ0KSB7XG4gIHJldHVybiB3cml0ZURvdWJsZSh0aGlzLCB2YWx1ZSwgb2Zmc2V0LCB0cnVlLCBub0Fzc2VydClcbn1cblxuQnVmZmVyLnByb3RvdHlwZS53cml0ZURvdWJsZUJFID0gZnVuY3Rpb24gd3JpdGVEb3VibGVCRSAodmFsdWUsIG9mZnNldCwgbm9Bc3NlcnQpIHtcbiAgcmV0dXJuIHdyaXRlRG91YmxlKHRoaXMsIHZhbHVlLCBvZmZzZXQsIGZhbHNlLCBub0Fzc2VydClcbn1cblxuLy8gY29weSh0YXJnZXRCdWZmZXIsIHRhcmdldFN0YXJ0PTAsIHNvdXJjZVN0YXJ0PTAsIHNvdXJjZUVuZD1idWZmZXIubGVuZ3RoKVxuQnVmZmVyLnByb3RvdHlwZS5jb3B5ID0gZnVuY3Rpb24gY29weSAodGFyZ2V0LCB0YXJnZXRTdGFydCwgc3RhcnQsIGVuZCkge1xuICBpZiAoIXN0YXJ0KSBzdGFydCA9IDBcbiAgaWYgKCFlbmQgJiYgZW5kICE9PSAwKSBlbmQgPSB0aGlzLmxlbmd0aFxuICBpZiAodGFyZ2V0U3RhcnQgPj0gdGFyZ2V0Lmxlbmd0aCkgdGFyZ2V0U3RhcnQgPSB0YXJnZXQubGVuZ3RoXG4gIGlmICghdGFyZ2V0U3RhcnQpIHRhcmdldFN0YXJ0ID0gMFxuICBpZiAoZW5kID4gMCAmJiBlbmQgPCBzdGFydCkgZW5kID0gc3RhcnRcblxuICAvLyBDb3B5IDAgYnl0ZXM7IHdlJ3JlIGRvbmVcbiAgaWYgKGVuZCA9PT0gc3RhcnQpIHJldHVybiAwXG4gIGlmICh0YXJnZXQubGVuZ3RoID09PSAwIHx8IHRoaXMubGVuZ3RoID09PSAwKSByZXR1cm4gMFxuXG4gIC8vIEZhdGFsIGVycm9yIGNvbmRpdGlvbnNcbiAgaWYgKHRhcmdldFN0YXJ0IDwgMCkge1xuICAgIHRocm93IG5ldyBSYW5nZUVycm9yKCd0YXJnZXRTdGFydCBvdXQgb2YgYm91bmRzJylcbiAgfVxuICBpZiAoc3RhcnQgPCAwIHx8IHN0YXJ0ID49IHRoaXMubGVuZ3RoKSB0aHJvdyBuZXcgUmFuZ2VFcnJvcignc291cmNlU3RhcnQgb3V0IG9mIGJvdW5kcycpXG4gIGlmIChlbmQgPCAwKSB0aHJvdyBuZXcgUmFuZ2VFcnJvcignc291cmNlRW5kIG91dCBvZiBib3VuZHMnKVxuXG4gIC8vIEFyZSB3ZSBvb2I/XG4gIGlmIChlbmQgPiB0aGlzLmxlbmd0aCkgZW5kID0gdGhpcy5sZW5ndGhcbiAgaWYgKHRhcmdldC5sZW5ndGggLSB0YXJnZXRTdGFydCA8IGVuZCAtIHN0YXJ0KSB7XG4gICAgZW5kID0gdGFyZ2V0Lmxlbmd0aCAtIHRhcmdldFN0YXJ0ICsgc3RhcnRcbiAgfVxuXG4gIHZhciBsZW4gPSBlbmQgLSBzdGFydFxuICB2YXIgaVxuXG4gIGlmICh0aGlzID09PSB0YXJnZXQgJiYgc3RhcnQgPCB0YXJnZXRTdGFydCAmJiB0YXJnZXRTdGFydCA8IGVuZCkge1xuICAgIC8vIGRlc2NlbmRpbmcgY29weSBmcm9tIGVuZFxuICAgIGZvciAoaSA9IGxlbiAtIDE7IGkgPj0gMDsgLS1pKSB7XG4gICAgICB0YXJnZXRbaSArIHRhcmdldFN0YXJ0XSA9IHRoaXNbaSArIHN0YXJ0XVxuICAgIH1cbiAgfSBlbHNlIGlmIChsZW4gPCAxMDAwIHx8ICFCdWZmZXIuVFlQRURfQVJSQVlfU1VQUE9SVCkge1xuICAgIC8vIGFzY2VuZGluZyBjb3B5IGZyb20gc3RhcnRcbiAgICBmb3IgKGkgPSAwOyBpIDwgbGVuOyArK2kpIHtcbiAgICAgIHRhcmdldFtpICsgdGFyZ2V0U3RhcnRdID0gdGhpc1tpICsgc3RhcnRdXG4gICAgfVxuICB9IGVsc2Uge1xuICAgIFVpbnQ4QXJyYXkucHJvdG90eXBlLnNldC5jYWxsKFxuICAgICAgdGFyZ2V0LFxuICAgICAgdGhpcy5zdWJhcnJheShzdGFydCwgc3RhcnQgKyBsZW4pLFxuICAgICAgdGFyZ2V0U3RhcnRcbiAgICApXG4gIH1cblxuICByZXR1cm4gbGVuXG59XG5cbi8vIFVzYWdlOlxuLy8gICAgYnVmZmVyLmZpbGwobnVtYmVyWywgb2Zmc2V0WywgZW5kXV0pXG4vLyAgICBidWZmZXIuZmlsbChidWZmZXJbLCBvZmZzZXRbLCBlbmRdXSlcbi8vICAgIGJ1ZmZlci5maWxsKHN0cmluZ1ssIG9mZnNldFssIGVuZF1dWywgZW5jb2RpbmddKVxuQnVmZmVyLnByb3RvdHlwZS5maWxsID0gZnVuY3Rpb24gZmlsbCAodmFsLCBzdGFydCwgZW5kLCBlbmNvZGluZykge1xuICAvLyBIYW5kbGUgc3RyaW5nIGNhc2VzOlxuICBpZiAodHlwZW9mIHZhbCA9PT0gJ3N0cmluZycpIHtcbiAgICBpZiAodHlwZW9mIHN0YXJ0ID09PSAnc3RyaW5nJykge1xuICAgICAgZW5jb2RpbmcgPSBzdGFydFxuICAgICAgc3RhcnQgPSAwXG4gICAgICBlbmQgPSB0aGlzLmxlbmd0aFxuICAgIH0gZWxzZSBpZiAodHlwZW9mIGVuZCA9PT0gJ3N0cmluZycpIHtcbiAgICAgIGVuY29kaW5nID0gZW5kXG4gICAgICBlbmQgPSB0aGlzLmxlbmd0aFxuICAgIH1cbiAgICBpZiAodmFsLmxlbmd0aCA9PT0gMSkge1xuICAgICAgdmFyIGNvZGUgPSB2YWwuY2hhckNvZGVBdCgwKVxuICAgICAgaWYgKGNvZGUgPCAyNTYpIHtcbiAgICAgICAgdmFsID0gY29kZVxuICAgICAgfVxuICAgIH1cbiAgICBpZiAoZW5jb2RpbmcgIT09IHVuZGVmaW5lZCAmJiB0eXBlb2YgZW5jb2RpbmcgIT09ICdzdHJpbmcnKSB7XG4gICAgICB0aHJvdyBuZXcgVHlwZUVycm9yKCdlbmNvZGluZyBtdXN0IGJlIGEgc3RyaW5nJylcbiAgICB9XG4gICAgaWYgKHR5cGVvZiBlbmNvZGluZyA9PT0gJ3N0cmluZycgJiYgIUJ1ZmZlci5pc0VuY29kaW5nKGVuY29kaW5nKSkge1xuICAgICAgdGhyb3cgbmV3IFR5cGVFcnJvcignVW5rbm93biBlbmNvZGluZzogJyArIGVuY29kaW5nKVxuICAgIH1cbiAgfSBlbHNlIGlmICh0eXBlb2YgdmFsID09PSAnbnVtYmVyJykge1xuICAgIHZhbCA9IHZhbCAmIDI1NVxuICB9XG5cbiAgLy8gSW52YWxpZCByYW5nZXMgYXJlIG5vdCBzZXQgdG8gYSBkZWZhdWx0LCBzbyBjYW4gcmFuZ2UgY2hlY2sgZWFybHkuXG4gIGlmIChzdGFydCA8IDAgfHwgdGhpcy5sZW5ndGggPCBzdGFydCB8fCB0aGlzLmxlbmd0aCA8IGVuZCkge1xuICAgIHRocm93IG5ldyBSYW5nZUVycm9yKCdPdXQgb2YgcmFuZ2UgaW5kZXgnKVxuICB9XG5cbiAgaWYgKGVuZCA8PSBzdGFydCkge1xuICAgIHJldHVybiB0aGlzXG4gIH1cblxuICBzdGFydCA9IHN0YXJ0ID4+PiAwXG4gIGVuZCA9IGVuZCA9PT0gdW5kZWZpbmVkID8gdGhpcy5sZW5ndGggOiBlbmQgPj4+IDBcblxuICBpZiAoIXZhbCkgdmFsID0gMFxuXG4gIHZhciBpXG4gIGlmICh0eXBlb2YgdmFsID09PSAnbnVtYmVyJykge1xuICAgIGZvciAoaSA9IHN0YXJ0OyBpIDwgZW5kOyArK2kpIHtcbiAgICAgIHRoaXNbaV0gPSB2YWxcbiAgICB9XG4gIH0gZWxzZSB7XG4gICAgdmFyIGJ5dGVzID0gQnVmZmVyLmlzQnVmZmVyKHZhbClcbiAgICAgID8gdmFsXG4gICAgICA6IHV0ZjhUb0J5dGVzKG5ldyBCdWZmZXIodmFsLCBlbmNvZGluZykudG9TdHJpbmcoKSlcbiAgICB2YXIgbGVuID0gYnl0ZXMubGVuZ3RoXG4gICAgZm9yIChpID0gMDsgaSA8IGVuZCAtIHN0YXJ0OyArK2kpIHtcbiAgICAgIHRoaXNbaSArIHN0YXJ0XSA9IGJ5dGVzW2kgJSBsZW5dXG4gICAgfVxuICB9XG5cbiAgcmV0dXJuIHRoaXNcbn1cblxuLy8gSEVMUEVSIEZVTkNUSU9OU1xuLy8gPT09PT09PT09PT09PT09PVxuXG52YXIgSU5WQUxJRF9CQVNFNjRfUkUgPSAvW14rXFwvMC05QS1aYS16LV9dL2dcblxuZnVuY3Rpb24gYmFzZTY0Y2xlYW4gKHN0cikge1xuICAvLyBOb2RlIHN0cmlwcyBvdXQgaW52YWxpZCBjaGFyYWN0ZXJzIGxpa2UgXFxuIGFuZCBcXHQgZnJvbSB0aGUgc3RyaW5nLCBiYXNlNjQtanMgZG9lcyBub3RcbiAgc3RyID0gc3RyaW5ndHJpbShzdHIpLnJlcGxhY2UoSU5WQUxJRF9CQVNFNjRfUkUsICcnKVxuICAvLyBOb2RlIGNvbnZlcnRzIHN0cmluZ3Mgd2l0aCBsZW5ndGggPCAyIHRvICcnXG4gIGlmIChzdHIubGVuZ3RoIDwgMikgcmV0dXJuICcnXG4gIC8vIE5vZGUgYWxsb3dzIGZvciBub24tcGFkZGVkIGJhc2U2NCBzdHJpbmdzIChtaXNzaW5nIHRyYWlsaW5nID09PSksIGJhc2U2NC1qcyBkb2VzIG5vdFxuICB3aGlsZSAoc3RyLmxlbmd0aCAlIDQgIT09IDApIHtcbiAgICBzdHIgPSBzdHIgKyAnPSdcbiAgfVxuICByZXR1cm4gc3RyXG59XG5cbmZ1bmN0aW9uIHN0cmluZ3RyaW0gKHN0cikge1xuICBpZiAoc3RyLnRyaW0pIHJldHVybiBzdHIudHJpbSgpXG4gIHJldHVybiBzdHIucmVwbGFjZSgvXlxccyt8XFxzKyQvZywgJycpXG59XG5cbmZ1bmN0aW9uIHRvSGV4IChuKSB7XG4gIGlmIChuIDwgMTYpIHJldHVybiAnMCcgKyBuLnRvU3RyaW5nKDE2KVxuICByZXR1cm4gbi50b1N0cmluZygxNilcbn1cblxuZnVuY3Rpb24gdXRmOFRvQnl0ZXMgKHN0cmluZywgdW5pdHMpIHtcbiAgdW5pdHMgPSB1bml0cyB8fCBJbmZpbml0eVxuICB2YXIgY29kZVBvaW50XG4gIHZhciBsZW5ndGggPSBzdHJpbmcubGVuZ3RoXG4gIHZhciBsZWFkU3Vycm9nYXRlID0gbnVsbFxuICB2YXIgYnl0ZXMgPSBbXVxuXG4gIGZvciAodmFyIGkgPSAwOyBpIDwgbGVuZ3RoOyArK2kpIHtcbiAgICBjb2RlUG9pbnQgPSBzdHJpbmcuY2hhckNvZGVBdChpKVxuXG4gICAgLy8gaXMgc3Vycm9nYXRlIGNvbXBvbmVudFxuICAgIGlmIChjb2RlUG9pbnQgPiAweEQ3RkYgJiYgY29kZVBvaW50IDwgMHhFMDAwKSB7XG4gICAgICAvLyBsYXN0IGNoYXIgd2FzIGEgbGVhZFxuICAgICAgaWYgKCFsZWFkU3Vycm9nYXRlKSB7XG4gICAgICAgIC8vIG5vIGxlYWQgeWV0XG4gICAgICAgIGlmIChjb2RlUG9pbnQgPiAweERCRkYpIHtcbiAgICAgICAgICAvLyB1bmV4cGVjdGVkIHRyYWlsXG4gICAgICAgICAgaWYgKCh1bml0cyAtPSAzKSA+IC0xKSBieXRlcy5wdXNoKDB4RUYsIDB4QkYsIDB4QkQpXG4gICAgICAgICAgY29udGludWVcbiAgICAgICAgfSBlbHNlIGlmIChpICsgMSA9PT0gbGVuZ3RoKSB7XG4gICAgICAgICAgLy8gdW5wYWlyZWQgbGVhZFxuICAgICAgICAgIGlmICgodW5pdHMgLT0gMykgPiAtMSkgYnl0ZXMucHVzaCgweEVGLCAweEJGLCAweEJEKVxuICAgICAgICAgIGNvbnRpbnVlXG4gICAgICAgIH1cblxuICAgICAgICAvLyB2YWxpZCBsZWFkXG4gICAgICAgIGxlYWRTdXJyb2dhdGUgPSBjb2RlUG9pbnRcblxuICAgICAgICBjb250aW51ZVxuICAgICAgfVxuXG4gICAgICAvLyAyIGxlYWRzIGluIGEgcm93XG4gICAgICBpZiAoY29kZVBvaW50IDwgMHhEQzAwKSB7XG4gICAgICAgIGlmICgodW5pdHMgLT0gMykgPiAtMSkgYnl0ZXMucHVzaCgweEVGLCAweEJGLCAweEJEKVxuICAgICAgICBsZWFkU3Vycm9nYXRlID0gY29kZVBvaW50XG4gICAgICAgIGNvbnRpbnVlXG4gICAgICB9XG5cbiAgICAgIC8vIHZhbGlkIHN1cnJvZ2F0ZSBwYWlyXG4gICAgICBjb2RlUG9pbnQgPSAobGVhZFN1cnJvZ2F0ZSAtIDB4RDgwMCA8PCAxMCB8IGNvZGVQb2ludCAtIDB4REMwMCkgKyAweDEwMDAwXG4gICAgfSBlbHNlIGlmIChsZWFkU3Vycm9nYXRlKSB7XG4gICAgICAvLyB2YWxpZCBibXAgY2hhciwgYnV0IGxhc3QgY2hhciB3YXMgYSBsZWFkXG4gICAgICBpZiAoKHVuaXRzIC09IDMpID4gLTEpIGJ5dGVzLnB1c2goMHhFRiwgMHhCRiwgMHhCRClcbiAgICB9XG5cbiAgICBsZWFkU3Vycm9nYXRlID0gbnVsbFxuXG4gICAgLy8gZW5jb2RlIHV0ZjhcbiAgICBpZiAoY29kZVBvaW50IDwgMHg4MCkge1xuICAgICAgaWYgKCh1bml0cyAtPSAxKSA8IDApIGJyZWFrXG4gICAgICBieXRlcy5wdXNoKGNvZGVQb2ludClcbiAgICB9IGVsc2UgaWYgKGNvZGVQb2ludCA8IDB4ODAwKSB7XG4gICAgICBpZiAoKHVuaXRzIC09IDIpIDwgMCkgYnJlYWtcbiAgICAgIGJ5dGVzLnB1c2goXG4gICAgICAgIGNvZGVQb2ludCA+PiAweDYgfCAweEMwLFxuICAgICAgICBjb2RlUG9pbnQgJiAweDNGIHwgMHg4MFxuICAgICAgKVxuICAgIH0gZWxzZSBpZiAoY29kZVBvaW50IDwgMHgxMDAwMCkge1xuICAgICAgaWYgKCh1bml0cyAtPSAzKSA8IDApIGJyZWFrXG4gICAgICBieXRlcy5wdXNoKFxuICAgICAgICBjb2RlUG9pbnQgPj4gMHhDIHwgMHhFMCxcbiAgICAgICAgY29kZVBvaW50ID4+IDB4NiAmIDB4M0YgfCAweDgwLFxuICAgICAgICBjb2RlUG9pbnQgJiAweDNGIHwgMHg4MFxuICAgICAgKVxuICAgIH0gZWxzZSBpZiAoY29kZVBvaW50IDwgMHgxMTAwMDApIHtcbiAgICAgIGlmICgodW5pdHMgLT0gNCkgPCAwKSBicmVha1xuICAgICAgYnl0ZXMucHVzaChcbiAgICAgICAgY29kZVBvaW50ID4+IDB4MTIgfCAweEYwLFxuICAgICAgICBjb2RlUG9pbnQgPj4gMHhDICYgMHgzRiB8IDB4ODAsXG4gICAgICAgIGNvZGVQb2ludCA+PiAweDYgJiAweDNGIHwgMHg4MCxcbiAgICAgICAgY29kZVBvaW50ICYgMHgzRiB8IDB4ODBcbiAgICAgIClcbiAgICB9IGVsc2Uge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKCdJbnZhbGlkIGNvZGUgcG9pbnQnKVxuICAgIH1cbiAgfVxuXG4gIHJldHVybiBieXRlc1xufVxuXG5mdW5jdGlvbiBhc2NpaVRvQnl0ZXMgKHN0cikge1xuICB2YXIgYnl0ZUFycmF5ID0gW11cbiAgZm9yICh2YXIgaSA9IDA7IGkgPCBzdHIubGVuZ3RoOyArK2kpIHtcbiAgICAvLyBOb2RlJ3MgY29kZSBzZWVtcyB0byBiZSBkb2luZyB0aGlzIGFuZCBub3QgJiAweDdGLi5cbiAgICBieXRlQXJyYXkucHVzaChzdHIuY2hhckNvZGVBdChpKSAmIDB4RkYpXG4gIH1cbiAgcmV0dXJuIGJ5dGVBcnJheVxufVxuXG5mdW5jdGlvbiB1dGYxNmxlVG9CeXRlcyAoc3RyLCB1bml0cykge1xuICB2YXIgYywgaGksIGxvXG4gIHZhciBieXRlQXJyYXkgPSBbXVxuICBmb3IgKHZhciBpID0gMDsgaSA8IHN0ci5sZW5ndGg7ICsraSkge1xuICAgIGlmICgodW5pdHMgLT0gMikgPCAwKSBicmVha1xuXG4gICAgYyA9IHN0ci5jaGFyQ29kZUF0KGkpXG4gICAgaGkgPSBjID4+IDhcbiAgICBsbyA9IGMgJSAyNTZcbiAgICBieXRlQXJyYXkucHVzaChsbylcbiAgICBieXRlQXJyYXkucHVzaChoaSlcbiAgfVxuXG4gIHJldHVybiBieXRlQXJyYXlcbn1cblxuZnVuY3Rpb24gYmFzZTY0VG9CeXRlcyAoc3RyKSB7XG4gIHJldHVybiBiYXNlNjQudG9CeXRlQXJyYXkoYmFzZTY0Y2xlYW4oc3RyKSlcbn1cblxuZnVuY3Rpb24gYmxpdEJ1ZmZlciAoc3JjLCBkc3QsIG9mZnNldCwgbGVuZ3RoKSB7XG4gIGZvciAodmFyIGkgPSAwOyBpIDwgbGVuZ3RoOyArK2kpIHtcbiAgICBpZiAoKGkgKyBvZmZzZXQgPj0gZHN0Lmxlbmd0aCkgfHwgKGkgPj0gc3JjLmxlbmd0aCkpIGJyZWFrXG4gICAgZHN0W2kgKyBvZmZzZXRdID0gc3JjW2ldXG4gIH1cbiAgcmV0dXJuIGlcbn1cblxuZnVuY3Rpb24gaXNuYW4gKHZhbCkge1xuICByZXR1cm4gdmFsICE9PSB2YWwgLy8gZXNsaW50LWRpc2FibGUtbGluZSBuby1zZWxmLWNvbXBhcmVcbn1cbiIsImV4cG9ydHMucmVhZCA9IGZ1bmN0aW9uIChidWZmZXIsIG9mZnNldCwgaXNMRSwgbUxlbiwgbkJ5dGVzKSB7XG4gIHZhciBlLCBtXG4gIHZhciBlTGVuID0gbkJ5dGVzICogOCAtIG1MZW4gLSAxXG4gIHZhciBlTWF4ID0gKDEgPDwgZUxlbikgLSAxXG4gIHZhciBlQmlhcyA9IGVNYXggPj4gMVxuICB2YXIgbkJpdHMgPSAtN1xuICB2YXIgaSA9IGlzTEUgPyAobkJ5dGVzIC0gMSkgOiAwXG4gIHZhciBkID0gaXNMRSA/IC0xIDogMVxuICB2YXIgcyA9IGJ1ZmZlcltvZmZzZXQgKyBpXVxuXG4gIGkgKz0gZFxuXG4gIGUgPSBzICYgKCgxIDw8ICgtbkJpdHMpKSAtIDEpXG4gIHMgPj49ICgtbkJpdHMpXG4gIG5CaXRzICs9IGVMZW5cbiAgZm9yICg7IG5CaXRzID4gMDsgZSA9IGUgKiAyNTYgKyBidWZmZXJbb2Zmc2V0ICsgaV0sIGkgKz0gZCwgbkJpdHMgLT0gOCkge31cblxuICBtID0gZSAmICgoMSA8PCAoLW5CaXRzKSkgLSAxKVxuICBlID4+PSAoLW5CaXRzKVxuICBuQml0cyArPSBtTGVuXG4gIGZvciAoOyBuQml0cyA+IDA7IG0gPSBtICogMjU2ICsgYnVmZmVyW29mZnNldCArIGldLCBpICs9IGQsIG5CaXRzIC09IDgpIHt9XG5cbiAgaWYgKGUgPT09IDApIHtcbiAgICBlID0gMSAtIGVCaWFzXG4gIH0gZWxzZSBpZiAoZSA9PT0gZU1heCkge1xuICAgIHJldHVybiBtID8gTmFOIDogKChzID8gLTEgOiAxKSAqIEluZmluaXR5KVxuICB9IGVsc2Uge1xuICAgIG0gPSBtICsgTWF0aC5wb3coMiwgbUxlbilcbiAgICBlID0gZSAtIGVCaWFzXG4gIH1cbiAgcmV0dXJuIChzID8gLTEgOiAxKSAqIG0gKiBNYXRoLnBvdygyLCBlIC0gbUxlbilcbn1cblxuZXhwb3J0cy53cml0ZSA9IGZ1bmN0aW9uIChidWZmZXIsIHZhbHVlLCBvZmZzZXQsIGlzTEUsIG1MZW4sIG5CeXRlcykge1xuICB2YXIgZSwgbSwgY1xuICB2YXIgZUxlbiA9IG5CeXRlcyAqIDggLSBtTGVuIC0gMVxuICB2YXIgZU1heCA9ICgxIDw8IGVMZW4pIC0gMVxuICB2YXIgZUJpYXMgPSBlTWF4ID4+IDFcbiAgdmFyIHJ0ID0gKG1MZW4gPT09IDIzID8gTWF0aC5wb3coMiwgLTI0KSAtIE1hdGgucG93KDIsIC03NykgOiAwKVxuICB2YXIgaSA9IGlzTEUgPyAwIDogKG5CeXRlcyAtIDEpXG4gIHZhciBkID0gaXNMRSA/IDEgOiAtMVxuICB2YXIgcyA9IHZhbHVlIDwgMCB8fCAodmFsdWUgPT09IDAgJiYgMSAvIHZhbHVlIDwgMCkgPyAxIDogMFxuXG4gIHZhbHVlID0gTWF0aC5hYnModmFsdWUpXG5cbiAgaWYgKGlzTmFOKHZhbHVlKSB8fCB2YWx1ZSA9PT0gSW5maW5pdHkpIHtcbiAgICBtID0gaXNOYU4odmFsdWUpID8gMSA6IDBcbiAgICBlID0gZU1heFxuICB9IGVsc2Uge1xuICAgIGUgPSBNYXRoLmZsb29yKE1hdGgubG9nKHZhbHVlKSAvIE1hdGguTE4yKVxuICAgIGlmICh2YWx1ZSAqIChjID0gTWF0aC5wb3coMiwgLWUpKSA8IDEpIHtcbiAgICAgIGUtLVxuICAgICAgYyAqPSAyXG4gICAgfVxuICAgIGlmIChlICsgZUJpYXMgPj0gMSkge1xuICAgICAgdmFsdWUgKz0gcnQgLyBjXG4gICAgfSBlbHNlIHtcbiAgICAgIHZhbHVlICs9IHJ0ICogTWF0aC5wb3coMiwgMSAtIGVCaWFzKVxuICAgIH1cbiAgICBpZiAodmFsdWUgKiBjID49IDIpIHtcbiAgICAgIGUrK1xuICAgICAgYyAvPSAyXG4gICAgfVxuXG4gICAgaWYgKGUgKyBlQmlhcyA+PSBlTWF4KSB7XG4gICAgICBtID0gMFxuICAgICAgZSA9IGVNYXhcbiAgICB9IGVsc2UgaWYgKGUgKyBlQmlhcyA+PSAxKSB7XG4gICAgICBtID0gKHZhbHVlICogYyAtIDEpICogTWF0aC5wb3coMiwgbUxlbilcbiAgICAgIGUgPSBlICsgZUJpYXNcbiAgICB9IGVsc2Uge1xuICAgICAgbSA9IHZhbHVlICogTWF0aC5wb3coMiwgZUJpYXMgLSAxKSAqIE1hdGgucG93KDIsIG1MZW4pXG4gICAgICBlID0gMFxuICAgIH1cbiAgfVxuXG4gIGZvciAoOyBtTGVuID49IDg7IGJ1ZmZlcltvZmZzZXQgKyBpXSA9IG0gJiAweGZmLCBpICs9IGQsIG0gLz0gMjU2LCBtTGVuIC09IDgpIHt9XG5cbiAgZSA9IChlIDw8IG1MZW4pIHwgbVxuICBlTGVuICs9IG1MZW5cbiAgZm9yICg7IGVMZW4gPiAwOyBidWZmZXJbb2Zmc2V0ICsgaV0gPSBlICYgMHhmZiwgaSArPSBkLCBlIC89IDI1NiwgZUxlbiAtPSA4KSB7fVxuXG4gIGJ1ZmZlcltvZmZzZXQgKyBpIC0gZF0gfD0gcyAqIDEyOFxufVxuIiwidmFyIHRvU3RyaW5nID0ge30udG9TdHJpbmc7XG5cbm1vZHVsZS5leHBvcnRzID0gQXJyYXkuaXNBcnJheSB8fCBmdW5jdGlvbiAoYXJyKSB7XG4gIHJldHVybiB0b1N0cmluZy5jYWxsKGFycikgPT0gJ1tvYmplY3QgQXJyYXldJztcbn07XG4iLCJtb2R1bGUuZXhwb3J0cz17XG4gICAgXCJ2ZXJzaW9uXCI6IFwidjJcIlxufVxuIiwiLyoqXG4gKiBFcGljZW50ZXIgSmF2YXNjcmlwdCBsaWJyYXJpZXNcbiAqIHY8JT0gdmVyc2lvbiAlPlxuICogaHR0cHM6Ly9naXRodWIuY29tL2ZvcmlvL2VwaWNlbnRlci1qcy1saWJzXG4gKi9cblxudmFyIEYgPSB7XG4gICAgdXRpbDoge30sXG4gICAgZmFjdG9yeToge30sXG4gICAgdHJhbnNwb3J0OiB7fSxcbiAgICBzdG9yZToge30sXG4gICAgc2VydmljZToge30sXG4gICAgbWFuYWdlcjoge1xuICAgICAgICBzdHJhdGVneToge31cbiAgICB9LFxuXG59O1xuXG5GLmxvYWQgPSByZXF1aXJlKCcuL2Vudi1sb2FkJyk7XG5GLmxvYWQoKTtcblxuRi51dGlsLnF1ZXJ5ID0gcmVxdWlyZSgnLi91dGlsL3F1ZXJ5LXV0aWwnKTtcbkYudXRpbC5tYWtlU2VxdWVuY2UgPSByZXF1aXJlKCcuL3V0aWwvbWFrZS1zZXF1ZW5jZScpO1xuRi51dGlsLnJ1biA9IHJlcXVpcmUoJy4vdXRpbC9ydW4tdXRpbCcpO1xuRi51dGlsLmNsYXNzRnJvbSA9IHJlcXVpcmUoJy4vdXRpbC9pbmhlcml0Jyk7XG5cbkYuZmFjdG9yeS5UcmFuc3BvcnQgPSByZXF1aXJlKCcuL3RyYW5zcG9ydC9odHRwLXRyYW5zcG9ydC1mYWN0b3J5Jyk7XG5GLnRyYW5zcG9ydC5BamF4ID0gcmVxdWlyZSgnLi90cmFuc3BvcnQvYWpheC1odHRwLXRyYW5zcG9ydCcpO1xuXG5GLnNlcnZpY2UuVVJMID0gcmVxdWlyZSgnLi9zZXJ2aWNlL3VybC1jb25maWctc2VydmljZScpO1xuRi5zZXJ2aWNlLkNvbmZpZyA9IHJlcXVpcmUoJy4vc2VydmljZS9jb25maWd1cmF0aW9uLXNlcnZpY2UnKTtcbkYuc2VydmljZS5SdW4gPSByZXF1aXJlKCcuL3NlcnZpY2UvcnVuLWFwaS1zZXJ2aWNlJyk7XG5GLnNlcnZpY2UuRmlsZSA9IHJlcXVpcmUoJy4vc2VydmljZS9hZG1pbi1maWxlLXNlcnZpY2UnKTtcbkYuc2VydmljZS5WYXJpYWJsZXMgPSByZXF1aXJlKCcuL3NlcnZpY2UvdmFyaWFibGVzLWFwaS1zZXJ2aWNlJyk7XG5GLnNlcnZpY2UuRGF0YSA9IHJlcXVpcmUoJy4vc2VydmljZS9kYXRhLWFwaS1zZXJ2aWNlJyk7XG5GLnNlcnZpY2UuQXV0aCA9IHJlcXVpcmUoJy4vc2VydmljZS9hdXRoLWFwaS1zZXJ2aWNlJyk7XG5GLnNlcnZpY2UuV29ybGQgPSByZXF1aXJlKCcuL3NlcnZpY2Uvd29ybGQtYXBpLWFkYXB0ZXInKTtcbkYuc2VydmljZS5TdGF0ZSA9IHJlcXVpcmUoJy4vc2VydmljZS9zdGF0ZS1hcGktYWRhcHRlcicpO1xuRi5zZXJ2aWNlLlVzZXIgPSByZXF1aXJlKCcuL3NlcnZpY2UvdXNlci1hcGktYWRhcHRlcicpO1xuRi5zZXJ2aWNlLk1lbWJlciA9IHJlcXVpcmUoJy4vc2VydmljZS9tZW1iZXItYXBpLWFkYXB0ZXInKTtcbkYuc2VydmljZS5Bc3NldCA9IHJlcXVpcmUoJy4vc2VydmljZS9hc3NldC1hcGktYWRhcHRlcicpO1xuXG5GLnN0b3JlLkNvb2tpZSA9IHJlcXVpcmUoJy4vc3RvcmUvY29va2llLXN0b3JlJyk7XG5GLmZhY3RvcnkuU3RvcmUgPSByZXF1aXJlKCcuL3N0b3JlL3N0b3JlLWZhY3RvcnknKTtcblxuRi5tYW5hZ2VyLlNjZW5hcmlvTWFuYWdlciA9IHJlcXVpcmUoJy4vbWFuYWdlcnMvc2NlbmFyaW8tbWFuYWdlcicpO1xuRi5tYW5hZ2VyLlJ1bk1hbmFnZXIgPSByZXF1aXJlKCcuL21hbmFnZXJzL3J1bi1tYW5hZ2VyJyk7XG5GLm1hbmFnZXIuQXV0aE1hbmFnZXIgPSByZXF1aXJlKCcuL21hbmFnZXJzL2F1dGgtbWFuYWdlcicpO1xuRi5tYW5hZ2VyLldvcmxkTWFuYWdlciA9IHJlcXVpcmUoJy4vbWFuYWdlcnMvd29ybGQtbWFuYWdlcicpO1xuXG5GLm1hbmFnZXIuc3RyYXRlZ3lbJ2Fsd2F5cy1uZXcnXSA9IHJlcXVpcmUoJy4vbWFuYWdlcnMvcnVuLXN0cmF0ZWdpZXMvYWx3YXlzLW5ldy1zdHJhdGVneScpO1xuRi5tYW5hZ2VyLnN0cmF0ZWd5Wydjb25kaXRpb25hbC1jcmVhdGlvbiddID0gcmVxdWlyZSgnLi9tYW5hZ2Vycy9ydW4tc3RyYXRlZ2llcy9jb25kaXRpb25hbC1jcmVhdGlvbi1zdHJhdGVneScpO1xuRi5tYW5hZ2VyLnN0cmF0ZWd5LmlkZW50aXR5ID0gcmVxdWlyZSgnLi9tYW5hZ2Vycy9ydW4tc3RyYXRlZ2llcy9pZGVudGl0eS1zdHJhdGVneScpO1xuRi5tYW5hZ2VyLnN0cmF0ZWd5WyduZXctaWYtbWlzc2luZyddID0gcmVxdWlyZSgnLi9tYW5hZ2Vycy9ydW4tc3RyYXRlZ2llcy9uZXctaWYtbWlzc2luZy1zdHJhdGVneScpO1xuRi5tYW5hZ2VyLnN0cmF0ZWd5WyduZXctaWYtbWlzc2luZyddID0gcmVxdWlyZSgnLi9tYW5hZ2Vycy9ydW4tc3RyYXRlZ2llcy9uZXctaWYtbWlzc2luZy1zdHJhdGVneScpO1xuRi5tYW5hZ2VyLnN0cmF0ZWd5WyduZXctaWYtcGVyc2lzdGVkJ10gPSByZXF1aXJlKCcuL21hbmFnZXJzL3J1bi1zdHJhdGVnaWVzL25ldy1pZi1wZXJzaXN0ZWQtc3RyYXRlZ3knKTtcbkYubWFuYWdlci5zdHJhdGVneVsnbmV3LWlmLWluaXRpYWxpemVkJ10gPSByZXF1aXJlKCcuL21hbmFnZXJzL3J1bi1zdHJhdGVnaWVzL25ldy1pZi1pbml0aWFsaXplZC1zdHJhdGVneScpO1xuXG5GLm1hbmFnZXIuQ2hhbm5lbE1hbmFnZXIgPSByZXF1aXJlKCcuL21hbmFnZXJzL2VwaWNlbnRlci1jaGFubmVsLW1hbmFnZXInKTtcbkYuc2VydmljZS5DaGFubmVsID0gcmVxdWlyZSgnLi9zZXJ2aWNlL2NoYW5uZWwtc2VydmljZScpO1xuXG5GLnZlcnNpb24gPSAnPCU9IHZlcnNpb24gJT4nO1xuRi5hcGkgPSByZXF1aXJlKCcuL2FwaS12ZXJzaW9uLmpzb24nKTtcblxuZ2xvYmFsLkYgPSBGO1xubW9kdWxlLmV4cG9ydHMgPSBGO1xuIiwiJ3VzZSBzdHJpY3QnO1xuXG52YXIgdXJsQ29uZmlnU2VydmljZSA9IHJlcXVpcmUoJy4vc2VydmljZS91cmwtY29uZmlnLXNlcnZpY2UnKTtcblxudmFyIGVudkxvYWQgPSBmdW5jdGlvbiAoY2FsbGJhY2spIHtcbiAgICB2YXIgZW52UHJvbWlzZTtcbiAgICB2YXIgaG9zdDtcbiAgICB2YXIgdXJsU2VydmljZSA9IHVybENvbmZpZ1NlcnZpY2UoKTtcbiAgICB2YXIgZW52UGF0aCA9ICcvZXBpY2VudGVyL3YxL2NvbmZpZyc7XG4gICAgaWYgKHVybFNlcnZpY2UuaXNMb2NhbGhvc3QoKSkge1xuICAgICAgICBob3N0ID0gJ2h0dHBzOi8vZm9yaW8uY29tJztcbiAgICB9IGVsc2Uge1xuICAgICAgICBob3N0ID0gJyc7XG4gICAgfVxuICAgIHZhciBpbmZvVXJsID0gaG9zdCArIGVudlBhdGg7XG4gICAgZW52UHJvbWlzZSA9ICQuYWpheCh7IHVybDogaW5mb1VybCwgYXN5bmM6IGZhbHNlIH0pO1xuICAgIGVudlByb21pc2UuZG9uZShmdW5jdGlvbiAocmVzKSB7XG4gICAgICAgIHZhciBhcGkgPSByZXMuYXBpO1xuICAgICAgICAkLmV4dGVuZCh1cmxDb25maWdTZXJ2aWNlLCBhcGkpO1xuICAgIH0pLmZhaWwoZnVuY3Rpb24gKHJlcykge1xuICAgICAgICAvLyBFcGljZW50ZXIvd2Vic2VydmVyIG5vdCBwcm9wZXJseSBjb25maWd1cmVkXG4gICAgICAgIC8vIGZhbGxiYWNrIHRvIGFwaS5mb3Jpby5jb21cbiAgICAgICAgJC5leHRlbmQodXJsQ29uZmlnU2VydmljZSwgeyBwcm90b2NvbDogJ2h0dHBzJywgaG9zdDogJ2FwaS5mb3Jpby5jb20nIH0pO1xuICAgIH0pO1xuICAgIHJldHVybiBlbnZQcm9taXNlLmRvbmUoY2FsbGJhY2spLmZhaWwoY2FsbGJhY2spO1xufTtcblxubW9kdWxlLmV4cG9ydHMgPSBlbnZMb2FkO1xuIiwiLyoqXG4qICMjIEF1dGhvcml6YXRpb24gTWFuYWdlclxuKlxuKiBUaGUgQXV0aG9yaXphdGlvbiBNYW5hZ2VyIHByb3ZpZGVzIGFuIGVhc3kgd2F5IHRvIG1hbmFnZSB1c2VyIGF1dGhlbnRpY2F0aW9uIChsb2dnaW5nIGluIGFuZCBvdXQpIGFuZCBhdXRob3JpemF0aW9uIChrZWVwaW5nIHRyYWNrIG9mIHRva2Vucywgc2Vzc2lvbnMsIGFuZCBncm91cHMpIGZvciBwcm9qZWN0cy5cbipcbiogVGhlIEF1dGhvcml6YXRpb24gTWFuYWdlciBpcyBtb3N0IHVzZWZ1bCBmb3IgW3RlYW0gcHJvamVjdHNdKC4uLy4uLy4uL2dsb3NzYXJ5LyN0ZWFtKSB3aXRoIGFuIGFjY2VzcyBsZXZlbCBvZiBbQXV0aGVudGljYXRlZF0oLi4vLi4vLi4vZ2xvc3NhcnkvI2FjY2VzcykuIFRoZXNlIHByb2plY3RzIGFyZSBhY2Nlc3NlZCBieSBbZW5kIHVzZXJzXSguLi8uLi8uLi9nbG9zc2FyeS8jdXNlcnMpIHdobyBhcmUgbWVtYmVycyBvZiBvbmUgb3IgbW9yZSBbZ3JvdXBzXSguLi8uLi8uLi9nbG9zc2FyeS8jZ3JvdXBzKS5cbipcbiogIyMjIyBVc2luZyB0aGUgQXV0aG9yaXphdGlvbiBNYW5hZ2VyXG4qXG4qIFRvIHVzZSB0aGUgQXV0aG9yaXphdGlvbiBNYW5hZ2VyLCBpbnN0YW50aWF0ZSBpdC4gVGhlbiwgbWFrZSBjYWxscyB0byBhbnkgb2YgdGhlIG1ldGhvZHMgeW91IG5lZWQ6XG4qXG4qICAgICAgIHZhciBhdXRoTWdyID0gbmV3IEYubWFuYWdlci5BdXRoTWFuYWdlcih7XG4qICAgICAgICAgICBhY2NvdW50OiAnYWNtZS1zaW11bGF0aW9ucycsXG4qICAgICAgICAgICB1c2VyTmFtZTogJ2VuZHVzZXIxJyxcbiogICAgICAgICAgIHBhc3N3b3JkOiAncGFzc3cwcmQnXG4qICAgICAgIH0pO1xuKiAgICAgICBhdXRoTWdyLmxvZ2luKCkudGhlbihmdW5jdGlvbiAoKSB7XG4qICAgICAgICAgICBhdXRoTWdyLmdldEN1cnJlbnRVc2VyU2Vzc2lvbkluZm8oKTtcbiogICAgICAgfSk7XG4qXG4qXG4qIFRoZSBgb3B0aW9uc2Agb2JqZWN0IHBhc3NlZCB0byB0aGUgYEYubWFuYWdlci5BdXRoTWFuYWdlcigpYCBjYWxsIGNhbiBpbmNsdWRlOlxuKlxuKiAgICogYGFjY291bnRgOiBUaGUgYWNjb3VudCBpZCBmb3IgdGhpcyBgdXNlck5hbWVgLiBJbiB0aGUgRXBpY2VudGVyIFVJLCB0aGlzIGlzIHRoZSAqKlRlYW0gSUQqKiAoZm9yIHRlYW0gcHJvamVjdHMpIG9yIHRoZSAqKlVzZXIgSUQqKiAoZm9yIHBlcnNvbmFsIHByb2plY3RzKS5cbiogICAqIGB1c2VyTmFtZWA6IEVtYWlsIG9yIHVzZXJuYW1lIHRvIHVzZSBmb3IgbG9nZ2luZyBpbi5cbiogICAqIGBwYXNzd29yZGA6IFBhc3N3b3JkIGZvciBzcGVjaWZpZWQgYHVzZXJOYW1lYC5cbiogICAqIGBwcm9qZWN0YDogVGhlICoqUHJvamVjdCBJRCoqIGZvciB0aGUgcHJvamVjdCB0byBsb2cgdGhpcyB1c2VyIGludG8uIE9wdGlvbmFsLlxuKiAgICogYGdyb3VwSWRgOiBJZCBvZiB0aGUgZ3JvdXAgdG8gd2hpY2ggYHVzZXJOYW1lYCBiZWxvbmdzLiBSZXF1aXJlZCBmb3IgZW5kIHVzZXJzIGlmIHRoZSBgcHJvamVjdGAgaXMgc3BlY2lmaWVkLlxuKlxuKiBJZiB5b3UgcHJlZmVyIHN0YXJ0aW5nIGZyb20gYSB0ZW1wbGF0ZSwgdGhlIEVwaWNlbnRlciBKUyBMaWJzIFtMb2dpbiBDb21wb25lbnRdKC4uLy4uLyNjb21wb25lbnRzKSB1c2VzIHRoZSBBdXRob3JpemF0aW9uIE1hbmFnZXIgYXMgd2VsbC4gVGhpcyBzYW1wbGUgSFRNTCBwYWdlIChhbmQgYXNzb2NpYXRlZCBDU1MgYW5kIEpTIGZpbGVzKSBwcm92aWRlcyBhIGxvZ2luIGZvcm0gZm9yIHRlYW0gbWVtYmVycyBhbmQgZW5kIHVzZXJzIG9mIHlvdXIgcHJvamVjdC4gSXQgYWxzbyBpbmNsdWRlcyBhIGdyb3VwIHNlbGVjdG9yIGZvciBlbmQgdXNlcnMgdGhhdCBhcmUgbWVtYmVycyBvZiBtdWx0aXBsZSBncm91cHMuXG4qL1xuXG4ndXNlIHN0cmljdCc7XG52YXIgQXV0aEFkYXB0ZXIgPSByZXF1aXJlKCcuLi9zZXJ2aWNlL2F1dGgtYXBpLXNlcnZpY2UnKTtcbnZhciBNZW1iZXJBZGFwdGVyID0gcmVxdWlyZSgnLi4vc2VydmljZS9tZW1iZXItYXBpLWFkYXB0ZXInKTtcbnZhciBTZXNzaW9uTWFuYWdlciA9IHJlcXVpcmUoJy4uL3N0b3JlL3Nlc3Npb24tbWFuYWdlcicpO1xudmFyIEJ1ZmZlciA9IHJlcXVpcmUoJ2J1ZmZlcicpLkJ1ZmZlcjtcbnZhciBfcGljayA9IHJlcXVpcmUoJy4uL3V0aWwvb2JqZWN0LXV0aWwnKS5fcGljaztcblxudmFyIGRlZmF1bHRzID0ge1xuICAgIHJlcXVpcmVzR3JvdXA6IHRydWVcbn07XG5cbmZ1bmN0aW9uIEF1dGhNYW5hZ2VyKG9wdGlvbnMpIHtcbiAgICBvcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sIGRlZmF1bHRzLCBvcHRpb25zKTtcbiAgICB0aGlzLnNlc3Npb25NYW5hZ2VyID0gbmV3IFNlc3Npb25NYW5hZ2VyKG9wdGlvbnMpO1xuICAgIHRoaXMub3B0aW9ucyA9IHRoaXMuc2Vzc2lvbk1hbmFnZXIuZ2V0TWVyZ2VkT3B0aW9ucygpO1xuXG4gICAgdGhpcy5pc0xvY2FsID0gdGhpcy5vcHRpb25zLmlzTG9jYWw7XG4gICAgdGhpcy5hdXRoQWRhcHRlciA9IG5ldyBBdXRoQWRhcHRlcih0aGlzLm9wdGlvbnMpO1xufVxuXG52YXIgX2ZpbmRVc2VySW5Hcm91cCA9IGZ1bmN0aW9uIChtZW1iZXJzLCBpZCkge1xuICAgIGZvciAodmFyIGogPSAwOyBqPG1lbWJlcnMubGVuZ3RoOyBqKyspIHtcbiAgICAgICAgaWYgKG1lbWJlcnNbal0udXNlcklkID09PSBpZCkge1xuICAgICAgICAgICAgcmV0dXJuIG1lbWJlcnNbal07XG4gICAgICAgIH1cbiAgICB9XG5cblxuICAgIHJldHVybiBudWxsO1xufTtcblxuQXV0aE1hbmFnZXIucHJvdG90eXBlID0gJC5leHRlbmQoQXV0aE1hbmFnZXIucHJvdG90eXBlLCB7XG5cbiAgICAvKipcbiAgICAqIExvZ3MgdXNlciBpbi5cbiAgICAqXG4gICAgKiAqKkV4YW1wbGUqKlxuICAgICpcbiAgICAqICAgICAgIGF1dGhNZ3IubG9naW4oe1xuICAgICogICAgICAgICAgIGFjY291bnQ6ICdhY21lLXNpbXVsYXRpb25zJyxcbiAgICAqICAgICAgICAgICBwcm9qZWN0OiAnc3VwcGx5LWNoYWluLWdhbWUnLFxuICAgICogICAgICAgICAgIHVzZXJOYW1lOiAnZW5kdXNlcjEnLFxuICAgICogICAgICAgICAgIHBhc3N3b3JkOiAncGFzc3cwcmQnXG4gICAgKiAgICAgICB9KVxuICAgICogICAgICAgICAgIC50aGVuKGZ1bmN0aW9uKHN0YXR1c09iaikge1xuICAgICogICAgICAgICAgICAgICAvLyBpZiBlbmR1c2VyMSBiZWxvbmdzIHRvIGV4YWN0bHkgb25lIGdyb3VwXG4gICAgKiAgICAgICAgICAgICAgIC8vIChvciBpZiB0aGUgbG9naW4oKSBjYWxsIGlzIG1vZGlmaWVkIHRvIGluY2x1ZGUgdGhlIGdyb3VwIGlkKVxuICAgICogICAgICAgICAgICAgICAvLyBjb250aW51ZSBoZXJlXG4gICAgKiAgICAgICAgICAgfSlcbiAgICAqICAgICAgICAgICAuZmFpbChmdW5jdGlvbihzdGF0dXNPYmopIHtcbiAgICAqICAgICAgICAgICAgICAgLy8gaWYgZW5kdXNlcjEgYmVsb25ncyB0byBtdWx0aXBsZSBncm91cHMsXG4gICAgKiAgICAgICAgICAgICAgIC8vIHRoZSBsb2dpbigpIGNhbGwgZmFpbHNcbiAgICAqICAgICAgICAgICAgICAgLy8gYW5kIHJldHVybnMgYWxsIGdyb3VwcyBvZiB3aGljaCB0aGUgdXNlciBpcyBhIG1lbWJlclxuICAgICogICAgICAgICAgICAgICBmb3IgKHZhciBpPTA7IGkgPCBzdGF0dXNPYmoudXNlckdyb3Vwcy5sZW5ndGg7IGkrKykge1xuICAgICogICAgICAgICAgICAgICAgICAgY29uc29sZS5sb2coc3RhdHVzT2JqLnVzZXJHcm91cHNbaV0ubmFtZSwgc3RhdHVzT2JqLnVzZXJHcm91cHNbaV0uZ3JvdXBJZCk7XG4gICAgKiAgICAgICAgICAgICAgIH1cbiAgICAqICAgICAgICAgICB9KTtcbiAgICAqXG4gICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICpcbiAgICAqIEBwYXJhbSB7T2JqZWN0fSBgb3B0aW9uc2AgKE9wdGlvbmFsKSBPdmVycmlkZXMgZm9yIGNvbmZpZ3VyYXRpb24gb3B0aW9ucy4gSWYgbm90IHBhc3NlZCBpbiB3aGVuIGNyZWF0aW5nIGFuIGluc3RhbmNlIG9mIHRoZSBtYW5hZ2VyIChgRi5tYW5hZ2VyLkF1dGhNYW5hZ2VyKClgKSwgdGhlc2Ugb3B0aW9ucyBzaG91bGQgaW5jbHVkZTpcbiAgICAqIEBwYXJhbSB7c3RyaW5nfSBgb3B0aW9ucy5hY2NvdW50YCBUaGUgYWNjb3VudCBpZCBmb3IgdGhpcyBgdXNlck5hbWVgLiBJbiB0aGUgRXBpY2VudGVyIFVJLCB0aGlzIGlzIHRoZSAqKlRlYW0gSUQqKiAoZm9yIHRlYW0gcHJvamVjdHMpIG9yIHRoZSAqKlVzZXIgSUQqKiAoZm9yIHBlcnNvbmFsIHByb2plY3RzKS5cbiAgICAqIEBwYXJhbSB7c3RyaW5nfSBgb3B0aW9ucy51c2VyTmFtZWAgRW1haWwgb3IgdXNlcm5hbWUgdG8gdXNlIGZvciBsb2dnaW5nIGluLlxuICAgICogQHBhcmFtIHtzdHJpbmd9IGBvcHRpb25zLnBhc3N3b3JkYCBQYXNzd29yZCBmb3Igc3BlY2lmaWVkIGB1c2VyTmFtZWAuXG4gICAgKiBAcGFyYW0ge3N0cmluZ30gYG9wdGlvbnMucHJvamVjdGAgKE9wdGlvbmFsKSBUaGUgKipQcm9qZWN0IElEKiogZm9yIHRoZSBwcm9qZWN0IHRvIGxvZyB0aGlzIHVzZXIgaW50by5cbiAgICAqIEBwYXJhbSB7c3RyaW5nfSBgb3B0aW9ucy5ncm91cElkYCBUaGUgaWQgb2YgdGhlIGdyb3VwIHRvIHdoaWNoIGB1c2VyTmFtZWAgYmVsb25ncy4gUmVxdWlyZWQgZm9yIFtlbmQgdXNlcnNdKC4uLy4uLy4uL2dsb3NzYXJ5LyN1c2VycykgaWYgdGhlIGBwcm9qZWN0YCBpcyBzcGVjaWZpZWQgYW5kIGlmIHRoZSBlbmQgdXNlcnMgYXJlIG1lbWJlcnMgb2YgbXVsdGlwbGUgW2dyb3Vwc10oLi4vLi4vLi4vZ2xvc3NhcnkvI2dyb3VwcyksIG90aGVyd2lzZSBvcHRpb25hbC5cbiAgICAqL1xuICAgIGxvZ2luOiBmdW5jdGlvbiAob3B0aW9ucykge1xuICAgICAgICB2YXIgX3RoaXMgPSB0aGlzO1xuICAgICAgICB2YXIgJGQgPSAkLkRlZmVycmVkKCk7XG4gICAgICAgIHZhciBzZXNzaW9uTWFuYWdlciA9IHRoaXMuc2Vzc2lvbk1hbmFnZXI7XG4gICAgICAgIHZhciBhZGFwdGVyT3B0aW9ucyA9IHNlc3Npb25NYW5hZ2VyLmdldE1lcmdlZE9wdGlvbnMoeyBzdWNjZXNzOiAkLm5vb3AsIGVycm9yOiAkLm5vb3AgfSwgb3B0aW9ucyk7XG4gICAgICAgIHZhciBvdXRTdWNjZXNzID0gYWRhcHRlck9wdGlvbnMuc3VjY2VzcztcbiAgICAgICAgdmFyIG91dEVycm9yID0gYWRhcHRlck9wdGlvbnMuZXJyb3I7XG4gICAgICAgIHZhciBncm91cElkID0gYWRhcHRlck9wdGlvbnMuZ3JvdXBJZDtcblxuICAgICAgICB2YXIgZGVjb2RlVG9rZW4gPSBmdW5jdGlvbiAodG9rZW4pIHtcbiAgICAgICAgICAgIHZhciBlbmNvZGVkID0gdG9rZW4uc3BsaXQoJy4nKVsxXTtcbiAgICAgICAgICAgIHdoaWxlIChlbmNvZGVkLmxlbmd0aCAlIDQgIT09IDApIHtcbiAgICAgICAgICAgICAgICBlbmNvZGVkICs9ICc9JztcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgdmFyIGRlY29kZSA9IHdpbmRvdy5hdG9iID8gd2luZG93LmF0b2IgOiBmdW5jdGlvbiAoZW5jb2RlZCkgeyByZXR1cm4gbmV3IEJ1ZmZlcihlbmNvZGVkLCAnYmFzZTY0JykudG9TdHJpbmcoJ2FzY2lpJyk7IH07XG5cbiAgICAgICAgICAgIHJldHVybiBKU09OLnBhcnNlKGRlY29kZShlbmNvZGVkKSk7XG4gICAgICAgIH07XG5cbiAgICAgICAgdmFyIGhhbmRsZUdyb3VwRXJyb3IgPSBmdW5jdGlvbiAobWVzc2FnZSwgc3RhdHVzQ29kZSwgZGF0YSkge1xuICAgICAgICAgICAgLy8gbG9nb3V0IHRoZSB1c2VyIHNpbmNlIGl0J3MgaW4gYW4gaW52YWxpZCBzdGF0ZSB3aXRoIG5vIGdyb3VwIHNlbGVjdGVkXG4gICAgICAgICAgICBfdGhpcy5sb2dvdXQoKS50aGVuKGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgICAgICB2YXIgZXJyb3IgPSAkLmV4dGVuZCh0cnVlLCB7fSwgZGF0YSwgeyBzdGF0dXNUZXh0OiBtZXNzYWdlLCBzdGF0dXM6IHN0YXR1c0NvZGUgfSk7XG4gICAgICAgICAgICAgICAgJGQucmVqZWN0KGVycm9yKTtcbiAgICAgICAgICAgIH0pO1xuICAgICAgICB9O1xuXG4gICAgICAgIHZhciBoYW5kbGVTdWNjZXNzID0gZnVuY3Rpb24gKHJlc3BvbnNlKSB7XG4gICAgICAgICAgICAvL2pzaGludCBjYW1lbGNhc2U6IGZhbHNlXG4gICAgICAgICAgICAvL2pzY3M6ZGlzYWJsZVxuICAgICAgICAgICAgdmFyIHRva2VuID0gcmVzcG9uc2UuYWNjZXNzX3Rva2VuO1xuICAgICAgICAgICAgdmFyIHVzZXJJbmZvID0gZGVjb2RlVG9rZW4odG9rZW4pO1xuICAgICAgICAgICAgdmFyIG9sZEdyb3VwcyA9IHNlc3Npb25NYW5hZ2VyLmdldFNlc3Npb24oKS5ncm91cHMgfHwge307XG4gICAgICAgICAgICB2YXIgdXNlckdyb3VwT3B0cyA9ICQuZXh0ZW5kKHRydWUsIHt9LCBhZGFwdGVyT3B0aW9ucywgeyBzdWNjZXNzOiAkLm5vb3AgfSk7XG4gICAgICAgICAgICB2YXIgZGF0YSA9IHsgYXV0aDogcmVzcG9uc2UsIHVzZXI6IHVzZXJJbmZvIH07XG4gICAgICAgICAgICB2YXIgcHJvamVjdCA9IGFkYXB0ZXJPcHRpb25zLnByb2plY3Q7XG4gICAgICAgICAgICB2YXIgaXNUZWFtTWVtYmVyID0gdXNlckluZm8ucGFyZW50X2FjY291bnRfaWQgPT09IG51bGw7XG4gICAgICAgICAgICB2YXIgcmVxdWlyZXNHcm91cCA9IGFkYXB0ZXJPcHRpb25zLnJlcXVpcmVzR3JvdXAgJiYgcHJvamVjdDtcblxuICAgICAgICAgICAgdmFyIHNlc3Npb25JbmZvID0ge1xuICAgICAgICAgICAgICAgICdhdXRoX3Rva2VuJzogdG9rZW4sXG4gICAgICAgICAgICAgICAgJ2FjY291bnQnOiBhZGFwdGVyT3B0aW9ucy5hY2NvdW50LFxuICAgICAgICAgICAgICAgICdwcm9qZWN0JzogcHJvamVjdCxcbiAgICAgICAgICAgICAgICAndXNlcklkJzogdXNlckluZm8udXNlcl9pZCxcbiAgICAgICAgICAgICAgICAnZ3JvdXBzJzogb2xkR3JvdXBzLFxuICAgICAgICAgICAgICAgICdpc1RlYW1NZW1iZXInOiBpc1RlYW1NZW1iZXJcbiAgICAgICAgICAgIH07XG4gICAgICAgICAgICAvLyBUaGUgZ3JvdXAgaXMgbm90IHJlcXVpcmVkIGlmIHRoZSB1c2VyIGlzIG5vdCBsb2dnaW5nIGludG8gYSBwcm9qZWN0XG4gICAgICAgICAgICBpZiAoIXJlcXVpcmVzR3JvdXApIHtcbiAgICAgICAgICAgICAgICBzZXNzaW9uTWFuYWdlci5zYXZlU2Vzc2lvbihzZXNzaW9uSW5mbyk7XG4gICAgICAgICAgICAgICAgb3V0U3VjY2Vzcy5hcHBseSh0aGlzLCBbZGF0YV0pO1xuICAgICAgICAgICAgICAgICRkLnJlc29sdmUoZGF0YSk7XG4gICAgICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICBfdGhpcy5nZXRVc2VyR3JvdXBzKHsgdXNlcklkOiB1c2VySW5mby51c2VyX2lkLCB0b2tlbjogdG9rZW4gfSwgdXNlckdyb3VwT3B0cykuZG9uZShmdW5jdGlvbiAobWVtYmVySW5mbykge1xuICAgICAgICAgICAgICAgIGRhdGEudXNlckdyb3VwcyA9IG1lbWJlckluZm87XG5cbiAgICAgICAgICAgICAgICB2YXIgZ3JvdXAgPSBudWxsO1xuICAgICAgICAgICAgICAgIGlmIChtZW1iZXJJbmZvLmxlbmd0aCA9PT0gMCkge1xuICAgICAgICAgICAgICAgICAgICBoYW5kbGVHcm91cEVycm9yKCdUaGUgdXNlciBoYXMgbm8gZ3JvdXBzIGFzc29jaWF0ZWQgaW4gdGhpcyBhY2NvdW50JywgNDAxLCBkYXRhKTtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgICAgICAgIH0gZWxzZSBpZiAobWVtYmVySW5mby5sZW5ndGggPT09IDEpIHtcbiAgICAgICAgICAgICAgICAgICAgLy8gU2VsZWN0IHRoZSBvbmx5IGdyb3VwXG4gICAgICAgICAgICAgICAgICAgIGdyb3VwID0gbWVtYmVySW5mb1swXTtcbiAgICAgICAgICAgICAgICB9IGVsc2UgaWYgKG1lbWJlckluZm8ubGVuZ3RoID4gMSkge1xuICAgICAgICAgICAgICAgICAgICBpZiAoZ3JvdXBJZCkge1xuICAgICAgICAgICAgICAgICAgICAgICAgdmFyIGZpbHRlcmVkR3JvdXBzID0gJC5ncmVwKG1lbWJlckluZm8sIGZ1bmN0aW9uIChyZXNHcm91cCkge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybiByZXNHcm91cC5ncm91cElkID09PSBncm91cElkO1xuICAgICAgICAgICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgICAgICAgICAgICBncm91cCA9IGZpbHRlcmVkR3JvdXBzLmxlbmd0aCA9PT0gMSA/IGZpbHRlcmVkR3JvdXBzWzBdIDogbnVsbDtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgIGlmIChncm91cCkge1xuICAgICAgICAgICAgICAgICAgICB2YXIgZ3JvdXBEYXRhID0ge1xuICAgICAgICAgICAgICAgICAgICAgICAgJ2dyb3VwSWQnOiBncm91cC5ncm91cElkLFxuICAgICAgICAgICAgICAgICAgICAgICAgJ2dyb3VwTmFtZSc6IGdyb3VwLm5hbWUsXG4gICAgICAgICAgICAgICAgICAgICAgICAnaXNGYWMnOiBfZmluZFVzZXJJbkdyb3VwKGdyb3VwLm1lbWJlcnMsIHVzZXJJbmZvLnVzZXJfaWQpLnJvbGUgPT09ICdmYWNpbGl0YXRvcidcbiAgICAgICAgICAgICAgICAgICAgfTtcbiAgICAgICAgICAgICAgICAgICAgdmFyIHNlc3Npb25JbmZvV2l0aEdyb3VwID0gJC5leHRlbmQoe30sIHNlc3Npb25JbmZvLCBncm91cERhdGEpO1xuICAgICAgICAgICAgICAgICAgICBzZXNzaW9uSW5mby5ncm91cHNbcHJvamVjdF0gPSBncm91cERhdGE7XG4gICAgICAgICAgICAgICAgICAgIF90aGlzLnNlc3Npb25NYW5hZ2VyLnNhdmVTZXNzaW9uKHNlc3Npb25JbmZvV2l0aEdyb3VwLCBhZGFwdGVyT3B0aW9ucyk7XG4gICAgICAgICAgICAgICAgICAgIG91dFN1Y2Nlc3MuYXBwbHkodGhpcywgW2RhdGFdKTtcbiAgICAgICAgICAgICAgICAgICAgJGQucmVzb2x2ZShkYXRhKTtcbiAgICAgICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICBoYW5kbGVHcm91cEVycm9yKCdUaGlzIHVzZXIgaXMgYXNzb2NpYXRlZCB3aXRoIG1vcmUgdGhhbiBvbmUgZ3JvdXAuIFBsZWFzZSBzcGVjaWZ5IGEgZ3JvdXAgaWQgdG8gbG9nIGludG8gYW5kIHRyeSBhZ2FpbicsIDQwMywgZGF0YSk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfSkuZmFpbCgkZC5yZWplY3QpO1xuICAgICAgICB9O1xuXG4gICAgICAgIGFkYXB0ZXJPcHRpb25zLnN1Y2Nlc3MgPSBoYW5kbGVTdWNjZXNzO1xuICAgICAgICBhZGFwdGVyT3B0aW9ucy5lcnJvciA9IGZ1bmN0aW9uIChyZXNwb25zZSkge1xuICAgICAgICAgICAgaWYgKGFkYXB0ZXJPcHRpb25zLmFjY291bnQpIHtcbiAgICAgICAgICAgICAgICAvLyBUcnkgdG8gbG9naW4gYXMgYSBzeXN0ZW0gdXNlclxuICAgICAgICAgICAgICAgIGFkYXB0ZXJPcHRpb25zLmFjY291bnQgPSBudWxsO1xuICAgICAgICAgICAgICAgIGFkYXB0ZXJPcHRpb25zLmVycm9yID0gZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgICAgICAgICBvdXRFcnJvci5hcHBseSh0aGlzLCBhcmd1bWVudHMpO1xuICAgICAgICAgICAgICAgICAgICAkZC5yZWplY3QocmVzcG9uc2UpO1xuICAgICAgICAgICAgICAgIH07XG5cbiAgICAgICAgICAgICAgICBfdGhpcy5hdXRoQWRhcHRlci5sb2dpbihhZGFwdGVyT3B0aW9ucyk7XG4gICAgICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICBvdXRFcnJvci5hcHBseSh0aGlzLCBhcmd1bWVudHMpO1xuICAgICAgICAgICAgJGQucmVqZWN0KHJlc3BvbnNlKTtcbiAgICAgICAgfTtcblxuICAgICAgICB0aGlzLmF1dGhBZGFwdGVyLmxvZ2luKGFkYXB0ZXJPcHRpb25zKTtcbiAgICAgICAgcmV0dXJuICRkLnByb21pc2UoKTtcbiAgICB9LFxuXG4gICAgLyoqXG4gICAgKiBMb2dzIHVzZXIgb3V0IGJ5IGNsZWFyaW5nIGFsbCBzZXNzaW9uIGluZm9ybWF0aW9uLlxuICAgICpcbiAgICAqICoqRXhhbXBsZSoqXG4gICAgKlxuICAgICogICAgICAgYXV0aE1nci5sb2dvdXQoKTtcbiAgICAqXG4gICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICpcbiAgICAqIEBwYXJhbSB7T2JqZWN0fSBgb3B0aW9uc2AgKE9wdGlvbmFsKSBPdmVycmlkZXMgZm9yIGNvbmZpZ3VyYXRpb24gb3B0aW9ucy5cbiAgICAqL1xuICAgIGxvZ291dDogZnVuY3Rpb24gKG9wdGlvbnMpIHtcbiAgICAgICAgdmFyIF90aGlzID0gdGhpcztcbiAgICAgICAgdmFyIGFkYXB0ZXJPcHRpb25zID0gdGhpcy5zZXNzaW9uTWFuYWdlci5nZXRNZXJnZWRPcHRpb25zKG9wdGlvbnMpO1xuXG4gICAgICAgIHZhciByZW1vdmVDb29raWVGbiA9IGZ1bmN0aW9uIChyZXNwb25zZSkge1xuICAgICAgICAgICAgX3RoaXMuc2Vzc2lvbk1hbmFnZXIucmVtb3ZlU2Vzc2lvbigpO1xuICAgICAgICB9O1xuXG4gICAgICAgIHJldHVybiB0aGlzLmF1dGhBZGFwdGVyLmxvZ291dChhZGFwdGVyT3B0aW9ucykuZG9uZShyZW1vdmVDb29raWVGbik7XG4gICAgfSxcblxuICAgIC8qKlxuICAgICAqIFJldHVybnMgdGhlIGV4aXN0aW5nIHVzZXIgYWNjZXNzIHRva2VuIGlmIHRoZSB1c2VyIGlzIGFscmVhZHkgbG9nZ2VkIGluLiBPdGhlcndpc2UsIGxvZ3MgdGhlIHVzZXIgaW4sIGNyZWF0aW5nIGEgbmV3IHVzZXIgYWNjZXNzIHRva2VuLCBhbmQgcmV0dXJucyB0aGUgbmV3IHRva2VuLiAoU2VlIFttb3JlIGJhY2tncm91bmQgb24gYWNjZXNzIHRva2Vuc10oLi4vLi4vLi4vcHJvamVjdF9hY2Nlc3MvKSkuXG4gICAgICpcbiAgICAgKiAqKkV4YW1wbGUqKlxuICAgICAqXG4gICAgICogICAgICBhdXRoTWdyLmdldFRva2VuKClcbiAgICAgKiAgICAgICAgICAudGhlbihmdW5jdGlvbiAodG9rZW4pIHtcbiAgICAgKiAgICAgICAgICAgICAgY29uc29sZS5sb2coJ015IHRva2VuIGlzICcsIHRva2VuKTtcbiAgICAgKiAgICAgICAgICB9KTtcbiAgICAgKlxuICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICogQHBhcmFtIHtPYmplY3R9IGBvcHRpb25zYCAoT3B0aW9uYWwpIE92ZXJyaWRlcyBmb3IgY29uZmlndXJhdGlvbiBvcHRpb25zLlxuICAgICAqL1xuICAgIGdldFRva2VuOiBmdW5jdGlvbiAob3B0aW9ucykge1xuICAgICAgICB2YXIgaHR0cE9wdGlvbnMgPSB0aGlzLnNlc3Npb25NYW5hZ2VyLmdldE1lcmdlZE9wdGlvbnMob3B0aW9ucyk7XG5cbiAgICAgICAgdmFyIHNlc3Npb24gPSB0aGlzLnNlc3Npb25NYW5hZ2VyLmdldFNlc3Npb24oKTtcbiAgICAgICAgdmFyICRkID0gJC5EZWZlcnJlZCgpO1xuICAgICAgICAvL2pzaGludCBjYW1lbGNhc2U6IGZhbHNlXG4gICAgICAgIC8vanNjczpkaXNhYmxlXG4gICAgICAgIGlmIChzZXNzaW9uLmF1dGhfdG9rZW4pIHtcbiAgICAgICAgICAgICRkLnJlc29sdmUoc2Vzc2lvbi5hdXRoX3Rva2VuKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIHRoaXMubG9naW4oaHR0cE9wdGlvbnMpLnRoZW4oJGQucmVzb2x2ZSk7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuICRkLnByb21pc2UoKTtcbiAgICB9LFxuXG4gICAgLyoqXG4gICAgICogUmV0dXJucyBhbiBhcnJheSBvZiBncm91cCByZWNvcmRzLCBvbmUgZm9yIGVhY2ggZ3JvdXAgb2Ygd2hpY2ggdGhlIGN1cnJlbnQgdXNlciBpcyBhIG1lbWJlci4gRWFjaCBncm91cCByZWNvcmQgaW5jbHVkZXMgdGhlIGdyb3VwIGBuYW1lYCwgYGFjY291bnRgLCBgcHJvamVjdGAsIGFuZCBgZ3JvdXBJZGAuXG4gICAgICpcbiAgICAgKiBJZiBzb21lIGVuZCB1c2VycyBpbiB5b3VyIHByb2plY3QgYXJlIG1lbWJlcnMgb2YgbXVsdGlwbGUgZ3JvdXBzLCB0aGlzIGlzIGEgdXNlZnVsIG1ldGhvZCB0byBjYWxsIG9uIHlvdXIgcHJvamVjdCdzIGxvZ2luIHBhZ2UuIFdoZW4gdGhlIHVzZXIgYXR0ZW1wdHMgdG8gbG9nIGluLCB5b3UgY2FuIHVzZSB0aGlzIHRvIGRpc3BsYXkgdGhlIGdyb3VwcyBvZiB3aGljaCB0aGUgdXNlciBpcyBtZW1iZXIsIGFuZCBoYXZlIHRoZSB1c2VyIHNlbGVjdCB0aGUgY29ycmVjdCBncm91cCB0byBsb2cgaW4gdG8gZm9yIHRoaXMgc2Vzc2lvbi5cbiAgICAgKlxuICAgICAqICoqRXhhbXBsZSoqXG4gICAgICpcbiAgICAgKiAgICAgIC8vIGdldCBncm91cHMgZm9yIGN1cnJlbnQgdXNlclxuICAgICAqICAgICAgdmFyIHNlc3Npb25PYmogPSBhdXRoTWdyLmdldEN1cnJlbnRVc2VyU2Vzc2lvbkluZm8oKTtcbiAgICAgKiAgICAgIGF1dGhNZ3IuZ2V0VXNlckdyb3Vwcyh7IHVzZXJJZDogc2Vzc2lvbk9iai51c2VySWQsIHRva2VuOiBzZXNzaW9uT2JqLmF1dGhfdG9rZW4gfSlcbiAgICAgKiAgICAgICAgICAudGhlbihmdW5jdGlvbiAoZ3JvdXBzKSB7XG4gICAgICogICAgICAgICAgICAgIGZvciAodmFyIGk9MDsgaSA8IGdyb3Vwcy5sZW5ndGg7IGkrKylcbiAgICAgKiAgICAgICAgICAgICAgICAgIHsgY29uc29sZS5sb2coZ3JvdXBzW2ldLm5hbWUpOyB9XG4gICAgICogICAgICAgICAgfSk7XG4gICAgICpcbiAgICAgKiAgICAgIC8vIGdldCBncm91cHMgZm9yIHBhcnRpY3VsYXIgdXNlclxuICAgICAqICAgICAgYXV0aE1nci5nZXRVc2VyR3JvdXBzKHt1c2VySWQ6ICdiMWMxOWRkYS0yZDJlLTQ3NzctYWQ1ZC0zOTI5ZjE3ZTg2ZDMnLCB0b2tlbjogc2F2ZWRQcm9qQWNjZXNzVG9rZW4gfSk7XG4gICAgICpcbiAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAqIEBwYXJhbSB7T2JqZWN0fSBgcGFyYW1zYCBPYmplY3Qgd2l0aCBhIHVzZXJJZCBhbmQgdG9rZW4gcHJvcGVydGllcy5cbiAgICAgKiBAcGFyYW0ge1N0cmluZ30gYHBhcmFtcy51c2VySWRgIFRoZSB1c2VySWQuIElmIGxvb2tpbmcgdXAgZ3JvdXBzIGZvciB0aGUgY3VycmVudGx5IGxvZ2dlZCBpbiB1c2VyLCB0aGlzIGlzIGluIHRoZSBzZXNzaW9uIGluZm9ybWF0aW9uLiBPdGhlcndpc2UsIHBhc3MgYSBzdHJpbmcuXG4gICAgICogQHBhcmFtIHtTdHJpbmd9IGBwYXJhbXMudG9rZW5gIFRoZSBhdXRob3JpemF0aW9uIGNyZWRlbnRpYWxzIChhY2Nlc3MgdG9rZW4pIHRvIHVzZSBmb3IgY2hlY2tpbmcgdGhlIGdyb3VwcyBmb3IgdGhpcyB1c2VyLiBJZiBsb29raW5nIHVwIGdyb3VwcyBmb3IgdGhlIGN1cnJlbnRseSBsb2dnZWQgaW4gdXNlciwgdGhpcyBpcyBpbiB0aGUgc2Vzc2lvbiBpbmZvcm1hdGlvbi4gQSB0ZWFtIG1lbWJlcidzIHRva2VuIG9yIGEgcHJvamVjdCBhY2Nlc3MgdG9rZW4gY2FuIGFjY2VzcyBhbGwgdGhlIGdyb3VwcyBmb3IgYWxsIGVuZCB1c2VycyBpbiB0aGUgdGVhbSBvciBwcm9qZWN0LlxuICAgICAqIEBwYXJhbSB7T2JqZWN0fSBgb3B0aW9uc2AgKE9wdGlvbmFsKSBPdmVycmlkZXMgZm9yIGNvbmZpZ3VyYXRpb24gb3B0aW9ucy5cbiAgICAgKi9cbiAgICBnZXRVc2VyR3JvdXBzOiBmdW5jdGlvbiAocGFyYW1zLCBvcHRpb25zKSB7XG4gICAgICAgIHZhciBhZGFwdGVyT3B0aW9ucyA9IHRoaXMuc2Vzc2lvbk1hbmFnZXIuZ2V0TWVyZ2VkT3B0aW9ucyh7IHN1Y2Nlc3M6ICQubm9vcCB9LCBvcHRpb25zKTtcbiAgICAgICAgdmFyICRkID0gJC5EZWZlcnJlZCgpO1xuICAgICAgICB2YXIgb3V0U3VjY2VzcyA9IGFkYXB0ZXJPcHRpb25zLnN1Y2Nlc3M7XG5cbiAgICAgICAgYWRhcHRlck9wdGlvbnMuc3VjY2VzcyA9IGZ1bmN0aW9uIChtZW1iZXJJbmZvKSB7XG4gICAgICAgICAgICAvLyBUaGUgbWVtYmVyIEFQSSBpcyBhdCB0aGUgYWNjb3VudCBzY29wZSwgd2UgZmlsdGVyIGJ5IHByb2plY3RcbiAgICAgICAgICAgIGlmIChhZGFwdGVyT3B0aW9ucy5wcm9qZWN0KSB7XG4gICAgICAgICAgICAgICAgbWVtYmVySW5mbyA9ICQuZ3JlcChtZW1iZXJJbmZvLCBmdW5jdGlvbiAoZ3JvdXApIHtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIGdyb3VwLnByb2plY3QgPT09IGFkYXB0ZXJPcHRpb25zLnByb2plY3Q7XG4gICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIG91dFN1Y2Nlc3MuYXBwbHkodGhpcywgW21lbWJlckluZm9dKTtcbiAgICAgICAgICAgICRkLnJlc29sdmUobWVtYmVySW5mbyk7XG4gICAgICAgIH07XG5cbiAgICAgICAgdmFyIG1lbWJlckFkYXB0ZXIgPSBuZXcgTWVtYmVyQWRhcHRlcih7IHRva2VuOiBwYXJhbXMudG9rZW4gfSk7XG4gICAgICAgIG1lbWJlckFkYXB0ZXIuZ2V0R3JvdXBzRm9yVXNlcihwYXJhbXMsIGFkYXB0ZXJPcHRpb25zKS5mYWlsKCRkLnJlamVjdCk7XG4gICAgICAgIHJldHVybiAkZC5wcm9taXNlKCk7XG4gICAgfSxcblxuICAgIC8qKlxuICAgICAqIFJldHVybnMgc2Vzc2lvbiBpbmZvcm1hdGlvbiBmb3IgdGhlIGN1cnJlbnQgdXNlciwgaW5jbHVkaW5nIHRoZSBgdXNlcklkYCwgYGFjY291bnRgLCBgcHJvamVjdGAsIGBncm91cElkYCwgYGdyb3VwTmFtZWAsIGBpc0ZhY2AgKHdoZXRoZXIgdGhlIGVuZCB1c2VyIGlzIGEgZmFjaWxpdGF0b3Igb2YgdGhpcyBncm91cCksIGFuZCBgYXV0aF90b2tlbmAgKHVzZXIgYWNjZXNzIHRva2VuKS5cbiAgICAgKlxuICAgICAqICpJbXBvcnRhbnQqOiBUaGlzIG1ldGhvZCBpcyBzeW5jaHJvbm91cy4gVGhlIHNlc3Npb24gaW5mb3JtYXRpb24gaXMgcmV0dXJuZWQgaW1tZWRpYXRlbHkgaW4gYW4gb2JqZWN0OyBubyBjYWxsYmFja3Mgb3IgcHJvbWlzZXMgYXJlIG5lZWRlZC5cbiAgICAgKlxuICAgICAqIFNlc3Npb24gaW5mb3JtYXRpb24gaXMgc3RvcmVkIGluIGEgY29va2llIGluIHRoZSBicm93c2VyLlxuICAgICAqXG4gICAgICogKipFeGFtcGxlKipcbiAgICAgKlxuICAgICAqICAgICAgdmFyIHNlc3Npb25PYmogPSBhdXRoTWdyLmdldEN1cnJlbnRVc2VyU2Vzc2lvbkluZm8oKTtcbiAgICAgKlxuICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICogQHBhcmFtIHtPYmplY3R9IGBvcHRpb25zYCAoT3B0aW9uYWwpIE92ZXJyaWRlcyBmb3IgY29uZmlndXJhdGlvbiBvcHRpb25zLlxuICAgICAqL1xuICAgIGdldEN1cnJlbnRVc2VyU2Vzc2lvbkluZm86IGZ1bmN0aW9uIChvcHRpb25zKSB7XG4gICAgICAgIHJldHVybiB0aGlzLnNlc3Npb25NYW5hZ2VyLmdldFNlc3Npb24ob3B0aW9ucyk7XG4gICAgfSxcblxuICAgIC8vIChyZXBsYWNlIHdpdGggLyogKi8gY29tbWVudCBibG9jaywgdG8gbWFrZSB2aXNpYmxlIGluIGRvY3MsIG9uY2UgRVBJQ0VOVEVSLTE5MzkgaXMgY29tcGxldGUpXG4gICAgLy9cbiAgICAvLyBBZGQgb25lIG9yIG1vcmUgZ3JvdXBzIHRvIHRoZSBjdXJyZW50IHNlc3Npb24uIFxuICAgIC8vXG4gICAgLy8gVGhpcyBtZXRob2QgYXNzdW1lcyB0aGF0IHRoZSBwcm9qZWN0IGFuZCBncm91cCBleGlzdCBhbmQgdGhlIHVzZXIgc3BlY2lmaWVkIGluIHRoZSBzZXNzaW9uIGlzIHBhcnQgb2YgdGhpcyBwcm9qZWN0IGFuZCBncm91cC5cbiAgICAvL1xuICAgIC8vIFJldHVybnMgdGhlIG5ldyBzZXNzaW9uIG9iamVjdC5cbiAgICAvL1xuICAgIC8vICoqRXhhbXBsZSoqXG4gICAgLy9cbiAgICAvLyAgICAgIGF1dGhNZ3IuYWRkR3JvdXBzKHsgcHJvamVjdDogJ2hlbGxvLXdvcmxkJywgZ3JvdXBOYW1lOiAnZ3JvdXBOYW1lJywgZ3JvdXBJZDogJ2dyb3VwSWQnIH0pO1xuICAgIC8vICAgICAgYXV0aE1nci5hZGRHcm91cHMoW3sgcHJvamVjdDogJ2hlbGxvLXdvcmxkJywgZ3JvdXBOYW1lOiAnZ3JvdXBOYW1lJywgZ3JvdXBJZDogJ2dyb3VwSWQnIH0sIHsgcHJvamVjdDogLi4uIH1dKTtcbiAgICAvL1xuICAgIC8vICoqUGFyYW1ldGVycyoqXG4gICAgLy8gQHBhcmFtIHtvYmplY3R8YXJyYXl9IGBncm91cHNgIChSZXF1aXJlZCkgVGhlIGdyb3VwIG9iamVjdCBtdXN0IGNvbnRhaW4gdGhlIGBwcm9qZWN0YCAoKipQcm9qZWN0IElEKiopIGFuZCBgZ3JvdXBOYW1lYCBwcm9wZXJ0aWVzLlxuICAgIC8vIEBwYXJhbSB7c3RyaW5nfSBgZ3JvdXAuaXNGYWNgIChvcHRpb25hbCkgRGVmYXVsdHMgdG8gYGZhbHNlYC4gU2V0IHRvIGB0cnVlYCBpZiB0aGUgdXNlciBpbiB0aGUgc2Vzc2lvbiBzaG91bGQgYmUgYSBmYWNpbGl0YXRvciBpbiB0aGlzIGdyb3VwLlxuICAgIC8vIEBwYXJhbSB7c3RyaW5nfSBgZ3JvdXAuZ3JvdXBJZGAgKG9wdGlvbmFsKSBEZWZhdWx0cyB0byB1bmRlZmluZWQuIE5lZWRlZCBtb3N0bHkgZm9yIHRoZSBNZW1iZXJzIEFQSS5cbiAgICAvL1xuICAgIGFkZEdyb3VwczogZnVuY3Rpb24gKGdyb3Vwcykge1xuICAgICAgICB2YXIgc2Vzc2lvbiA9IHRoaXMuZ2V0Q3VycmVudFVzZXJTZXNzaW9uSW5mbygpO1xuICAgICAgICB2YXIgaXNBcnJheSA9IEFycmF5LmlzQXJyYXkoZ3JvdXBzKTtcbiAgICAgICAgZ3JvdXBzID0gaXNBcnJheSA/IGdyb3VwcyA6IFtncm91cHNdO1xuXG4gICAgICAgICQuZWFjaChncm91cHMsIGZ1bmN0aW9uIChpbmRleCwgZ3JvdXApIHtcbiAgICAgICAgICAgIHZhciBleHRlbmRlZEdyb3VwID0gJC5leHRlbmQoe30sIHsgaXNGYWM6IGZhbHNlIH0sIGdyb3VwKTtcbiAgICAgICAgICAgIHZhciBwcm9qZWN0ID0gZXh0ZW5kZWRHcm91cC5wcm9qZWN0O1xuICAgICAgICAgICAgdmFyIHZhbGlkUHJvcHMgPSBbJ2dyb3VwTmFtZScsICdncm91cElkJywgJ2lzRmFjJ107XG4gICAgICAgICAgICBpZiAoIXByb2plY3QgfHwgIWV4dGVuZGVkR3JvdXAuZ3JvdXBOYW1lKSB7XG4gICAgICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdObyBwcm9qZWN0IG9yIGdyb3VwTmFtZSBzcGVjaWZpZWQuJyk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICAvLyBmaWx0ZXIgb2JqZWN0XG4gICAgICAgICAgICBleHRlbmRlZEdyb3VwID0gX3BpY2soZXh0ZW5kZWRHcm91cCwgdmFsaWRQcm9wcyk7XG4gICAgICAgICAgICBzZXNzaW9uLmdyb3Vwc1twcm9qZWN0XSA9IGV4dGVuZGVkR3JvdXA7XG4gICAgICAgIH0pO1xuICAgICAgICB0aGlzLnNlc3Npb25NYW5hZ2VyLnNhdmVTZXNzaW9uKHNlc3Npb24pO1xuICAgICAgICByZXR1cm4gc2Vzc2lvbjtcbiAgICB9XG59KTtcblxubW9kdWxlLmV4cG9ydHMgPSBBdXRoTWFuYWdlcjtcbiIsIid1c2Ugc3RyaWN0JztcblxudmFyIENoYW5uZWwgPSByZXF1aXJlKCcuLi9zZXJ2aWNlL2NoYW5uZWwtc2VydmljZScpO1xudmFyIFNlc3Npb25NYW5hZ2VyID0gcmVxdWlyZSgnLi4vc3RvcmUvc2Vzc2lvbi1tYW5hZ2VyJyk7XG5cbi8qKlxuICogIyMgQ2hhbm5lbCBNYW5hZ2VyXG4gKlxuICogVGhlcmUgYXJlIHR3byBtYWluIHVzZSBjYXNlcyBmb3IgdGhlIGNoYW5uZWw6IGV2ZW50IG5vdGlmaWNhdGlvbnMgYW5kIGNoYXQgbWVzc2FnZXMuXG4gKlxuICogVGhlIENoYW5uZWwgTWFuYWdlciBpcyBhIHdyYXBwZXIgYXJvdW5kIHRoZSBkZWZhdWx0IFtjb21ldGQgSmF2YVNjcmlwdCBsaWJyYXJ5XShodHRwOi8vZG9jcy5jb21ldGQub3JnLzIvcmVmZXJlbmNlL2phdmFzY3JpcHQuaHRtbCksIGAkLmNvbWV0ZGAuIEl0IHByb3ZpZGVzIGEgZmV3IG5pY2UgZmVhdHVyZXMgdGhhdCBgJC5jb21ldGRgIGRvZXNuJ3QsIGluY2x1ZGluZzpcbiAqXG4gKiAqIEF1dG9tYXRpYyByZS1zdWJzY3JpcHRpb24gdG8gY2hhbm5lbHMgaWYgeW91IGxvc2UgeW91ciBjb25uZWN0aW9uXG4gKiAqIE9ubGluZSAvIE9mZmxpbmUgbm90aWZpY2F0aW9uc1xuICogKiAnRXZlbnRzJyBmb3IgY29tZXRkIG5vdGlmaWNhdGlvbnMgKGluc3RlYWQgb2YgaGF2aW5nIHRvIGxpc3RlbiBvbiBzcGVjaWZpYyBtZXRhIGNoYW5uZWxzKVxuICpcbiAqIFdoaWxlIHlvdSBjYW4gd29yayBkaXJlY3RseSB3aXRoIHRoZSBDaGFubmVsIE1hbmFnZXIgdGhyb3VnaCBOb2RlLmpzIChmb3IgZXhhbXBsZSwgYHJlcXVpcmUoJ21hbmFnZXIvY2hhbm5lbC1tYW5hZ2VyJylgKSAtLSBvciBldmVuIHdvcmsgZGlyZWN0bHkgd2l0aCBgJC5jb21ldGRgIGFuZCBFcGljZW50ZXIncyB1bmRlcmx5aW5nIFtQdXNoIENoYW5uZWwgQVBJXSguLi8uLi8uLi9yZXN0X2FwaXMvbXVsdGlwbGF5ZXIvY2hhbm5lbC8pIC0tIG1vc3Qgb2Z0ZW4gaXQgd2lsbCBiZSBlYXNpZXN0IHRvIHdvcmsgd2l0aCB0aGUgW0VwaWNlbnRlciBDaGFubmVsIE1hbmFnZXJdKC4uL2VwaWNlbnRlci1jaGFubmVsLW1hbmFnZXIvKS4gVGhlIEVwaWNlbnRlciBDaGFubmVsIE1hbmFnZXIgaXMgYSB3cmFwcGVyIHRoYXQgaW5zdGFudGlhdGVzIGEgQ2hhbm5lbCBNYW5hZ2VyIHdpdGggRXBpY2VudGVyLXNwZWNpZmljIGRlZmF1bHRzLlxuICpcbiAqIFlvdSdsbCBuZWVkIHRvIGluY2x1ZGUgdGhlIGBlcGljZW50ZXItbXVsdGlwbGF5ZXItZGVwZW5kZW5jaWVzLmpzYCBsaWJyYXJ5IGluIGFkZGl0aW9uIHRvIHRoZSBgZXBpY2VudGVyLmpzYCBsaWJyYXJ5IGluIHlvdXIgcHJvamVjdCB0byB1c2UgdGhlIENoYW5uZWwgTWFuYWdlci4gKFNlZSBbSW5jbHVkaW5nIEVwaWNlbnRlci5qc10oLi4vLi4vI2luY2x1ZGUpLilcbiAqXG4gKiBUbyB1c2UgdGhlIENoYW5uZWwgTWFuYWdlciBpbiBjbGllbnQtc2lkZSBKYXZhU2NyaXB0LCBpbnN0YW50aWF0ZSB0aGUgW0VwaWNlbnRlciBDaGFubmVsIE1hbmFnZXJdKC4uL2VwaWNlbnRlci1jaGFubmVsLW1hbmFnZXIvKSwgZ2V0IHRoZSBjaGFubmVsLCB0aGVuIHVzZSB0aGUgY2hhbm5lbCdzIGBzdWJzY3JpYmUoKWAgYW5kIGBwdWJsaXNoKClgIG1ldGhvZHMgdG8gc3Vic2NyaWJlIHRvIHRvcGljcyBvciBwdWJsaXNoIGRhdGEgdG8gdG9waWNzLlxuICpcbiAqICAgICAgICB2YXIgY20gPSBuZXcgRi5tYW5hZ2VyLkNoYW5uZWxNYW5hZ2VyKCk7XG4gKiAgICAgICAgdmFyIGNoYW5uZWwgPSBjbS5nZXRDaGFubmVsKCk7XG4gKlxuICogICAgICAgIGNoYW5uZWwuc3Vic2NyaWJlKCd0b3BpYycsIGNhbGxiYWNrKTtcbiAqICAgICAgICBjaGFubmVsLnB1Ymxpc2goJ3RvcGljJywgeyBteURhdGE6IDEwMCB9KTtcbiAqXG4gKiBUaGUgcGFyYW1ldGVycyBmb3IgaW5zdGFudGlhdGluZyBhIENoYW5uZWwgTWFuYWdlciBpbmNsdWRlOlxuICpcbiAqICogYG9wdGlvbnNgIFRoZSBvcHRpb25zIG9iamVjdCB0byBjb25maWd1cmUgdGhlIENoYW5uZWwgTWFuYWdlci4gQmVzaWRlcyB0aGUgY29tbW9uIG9wdGlvbnMgbGlzdGVkIGhlcmUsIHNlZSBodHRwOi8vZG9jcy5jb21ldGQub3JnL3JlZmVyZW5jZS9qYXZhc2NyaXB0Lmh0bWwgZm9yIG90aGVyIHN1cHBvcnRlZCBvcHRpb25zLlxuICogKiBgb3B0aW9ucy51cmxgIFRoZSBDb21ldGQgZW5kcG9pbnQgVVJMLlxuICogKiBgb3B0aW9ucy53ZWJzb2NrZXRFbmFibGVkYCBXaGV0aGVyIHdlYnNvY2tldCBzdXBwb3J0IGlzIGFjdGl2ZSAoYm9vbGVhbikuXG4gKiAqIGBvcHRpb25zLmNoYW5uZWxgIE90aGVyIGRlZmF1bHRzIHRvIHBhc3Mgb24gdG8gaW5zdGFuY2VzIG9mIHRoZSB1bmRlcmx5aW5nIENoYW5uZWwgU2VydmljZS4gU2VlIFtDaGFubmVsIFNlcnZpY2VdKC4uL2NoYW5uZWwtc2VydmljZS8pIGZvciBkZXRhaWxzLlxuICpcbiAqL1xudmFyIENoYW5uZWxNYW5hZ2VyID0gZnVuY3Rpb24gKG9wdGlvbnMpIHtcbiAgICBpZiAoISQuY29tZXRkKSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcignQ29tZXRkIGxpYnJhcnkgbm90IGZvdW5kLiBQbGVhc2UgaW5jbHVkZSBlcGljZW50ZXItbXVsdGlwbGF5ZXItZGVwZW5kZW5jaWVzLmpzJyk7XG4gICAgfVxuICAgIGlmICghb3B0aW9ucyB8fCAhb3B0aW9ucy51cmwpIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdQbGVhc2UgcHJvdmlkZSBhbiB1cmwgZm9yIHRoZSBjb21ldGQgc2VydmVyJyk7XG4gICAgfVxuXG4gICAgdmFyIGRlZmF1bHRzID0ge1xuICAgICAgICAvKipcbiAgICAgICAgICogVGhlIENvbWV0ZCBlbmRwb2ludCBVUkwuXG4gICAgICAgICAqIEB0eXBlIHtzdHJpbmd9XG4gICAgICAgICAqL1xuICAgICAgICB1cmw6ICcnLFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBUaGUgbG9nIGxldmVsIGZvciB0aGUgY2hhbm5lbCAobG9ncyB0byBjb25zb2xlKS5cbiAgICAgICAgICogQHR5cGUge3N0cmluZ31cbiAgICAgICAgICovXG4gICAgICAgIGxvZ0xldmVsOiAnaW5mbycsXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIFdoZXRoZXIgd2Vic29ja2V0IHN1cHBvcnQgaXMgYWN0aXZlLiBEZWZhdWx0cyB0byBgZmFsc2VgOyBFcGljZW50ZXIgZG9lc24ndCBjdXJyZW50bHkgc3VwcG9ydCBjb21tdW5pY2F0aW9uIHRocm91Z2ggd2Vic29ja2V0cy5cbiAgICAgICAgICogQHR5cGUge2Jvb2xlYW59XG4gICAgICAgICAqL1xuICAgICAgICB3ZWJzb2NrZXRFbmFibGVkOiBmYWxzZSxcblxuICAgICAgICAvKipcbiAgICAgICAgICogSWYgZmFsc2UgZWFjaCBpbnN0YW5jZSBvZiBDaGFubmVsIHdpbGwgaGF2ZSBhIHNlcGFyYXRlIGNvbWV0ZCBjb25uZWN0aW9uIHRvIHNlcnZlciwgd2hpY2ggY291bGQgYmUgbm9pc3kuIFNldCB0byB0cnVlIHRvIHJlLXVzZSB0aGUgc2FtZSBjb25uZWN0aW9uIGFjcm9zcyBpbnN0YW5jZXMuXG4gICAgICAgICAqIEB0eXBlIHtib29sZWFufVxuICAgICAgICAgKi9cbiAgICAgICAgc2hhcmVDb25uZWN0aW9uOiBmYWxzZSxcblxuICAgICAgICAvKipcbiAgICAgICAgICogT3RoZXIgZGVmYXVsdHMgdG8gcGFzcyBvbiB0byBpbnN0YW5jZXMgb2YgdGhlIHVuZGVybHlpbmcgW0NoYW5uZWwgU2VydmljZV0oLi4vY2hhbm5lbC1zZXJ2aWNlLyksIHdoaWNoIGFyZSBjcmVhdGVkIHRocm91Z2ggYGdldENoYW5uZWwoKWAuXG4gICAgICAgICAqIEB0eXBlIHtvYmplY3R9XG4gICAgICAgICAqL1xuICAgICAgICBjaGFubmVsOiB7XG5cbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgICogT3B0aW9ucyB0byBwYXNzIHRvIHRoZSBjaGFubmVsIGhhbmRzaGFrZS5cbiAgICAgICAgICpcbiAgICAgICAgICogRm9yIGV4YW1wbGUsIHRoZSBbRXBpY2VudGVyIENoYW5uZWwgTWFuYWdlcl0oLi4vZXBpY2VudGVyLWNoYW5uZWwtbWFuYWdlci8pIHBhc3NlcyBgZXh0YCBhbmQgYXV0aG9yaXphdGlvbiBpbmZvcm1hdGlvbi4gTW9yZSBpbmZvcm1hdGlvbiBvbiBwb3NzaWJsZSBvcHRpb25zIGlzIGluIHRoZSBkZXRhaWxzIG9mIHRoZSB1bmRlcmx5aW5nIFtQdXNoIENoYW5uZWwgQVBJXSguLi8uLi8uLi9yZXN0X2FwaXMvbXVsdGlwbGF5ZXIvY2hhbm5lbC8pLlxuICAgICAgICAgKlxuICAgICAgICAgKiBAdHlwZSB7b2JqZWN0fVxuICAgICAgICAgKi9cbiAgICAgICAgaGFuZHNoYWtlOiB1bmRlZmluZWRcbiAgICB9O1xuICAgIHRoaXMuc2Vzc2lvbk1hbmFnZXIgPSBuZXcgU2Vzc2lvbk1hbmFnZXIoKTtcbiAgICB2YXIgZGVmYXVsdENvbWV0T3B0aW9ucyA9IHRoaXMuc2Vzc2lvbk1hbmFnZXIuZ2V0TWVyZ2VkT3B0aW9ucyhkZWZhdWx0cywgb3B0aW9ucyk7XG4gICAgdGhpcy5jdXJyZW50U3Vic2NyaXB0aW9ucyA9IFtdO1xuICAgIHRoaXMub3B0aW9ucyA9IGRlZmF1bHRDb21ldE9wdGlvbnM7XG5cbiAgICBpZiAoZGVmYXVsdENvbWV0T3B0aW9ucy5zaGFyZUNvbm5lY3Rpb24gJiYgQ2hhbm5lbE1hbmFnZXIucHJvdG90eXBlLl9jb21ldGQpIHtcbiAgICAgICAgdGhpcy5jb21ldGQgPSBDaGFubmVsTWFuYWdlci5wcm90b3R5cGUuX2NvbWV0ZDtcbiAgICAgICAgcmV0dXJuIHRoaXM7XG4gICAgfVxuICAgIHZhciBjb21ldGQgPSBuZXcgJC5Db21ldGQoKTtcbiAgICBDaGFubmVsTWFuYWdlci5wcm90b3R5cGUuX2NvbWV0ZCA9IGNvbWV0ZDtcblxuICAgIGNvbWV0ZC53ZWJzb2NrZXRFbmFibGVkID0gZGVmYXVsdENvbWV0T3B0aW9ucy53ZWJzb2NrZXRFbmFibGVkO1xuXG4gICAgdGhpcy5pc0Nvbm5lY3RlZCA9IGZhbHNlO1xuICAgIHZhciBjb25uZWN0aW9uQnJva2VuID0gZnVuY3Rpb24gKG1lc3NhZ2UpIHtcbiAgICAgICAgJCh0aGlzKS50cmlnZ2VyKCdkaXNjb25uZWN0JywgbWVzc2FnZSk7XG4gICAgfTtcbiAgICB2YXIgY29ubmVjdGlvblN1Y2NlZWRlZCA9IGZ1bmN0aW9uIChtZXNzYWdlKSB7XG4gICAgICAgICQodGhpcykudHJpZ2dlcignY29ubmVjdCcsIG1lc3NhZ2UpO1xuICAgIH07XG4gICAgdmFyIG1lID0gdGhpcztcblxuICAgIGNvbWV0ZC5jb25maWd1cmUoZGVmYXVsdENvbWV0T3B0aW9ucyk7XG5cbiAgICBjb21ldGQuYWRkTGlzdGVuZXIoJy9tZXRhL2Nvbm5lY3QnLCBmdW5jdGlvbiAobWVzc2FnZSkge1xuICAgICAgICB2YXIgd2FzQ29ubmVjdGVkID0gdGhpcy5pc0Nvbm5lY3RlZDtcbiAgICAgICAgdGhpcy5pc0Nvbm5lY3RlZCA9IChtZXNzYWdlLnN1Y2Nlc3NmdWwgPT09IHRydWUpO1xuICAgICAgICBpZiAoIXdhc0Nvbm5lY3RlZCAmJiB0aGlzLmlzQ29ubmVjdGVkKSB7IC8vQ29ubmVjdGluZyBmb3IgdGhlIGZpcnN0IHRpbWVcbiAgICAgICAgICAgIGNvbm5lY3Rpb25TdWNjZWVkZWQuY2FsbCh0aGlzLCBtZXNzYWdlKTtcbiAgICAgICAgfSBlbHNlIGlmICh3YXNDb25uZWN0ZWQgJiYgIXRoaXMuaXNDb25uZWN0ZWQpIHsgLy9Pbmx5IHRocm93IGRpc2Nvbm5lY3RlZCBtZXNzYWdlIGZybyB0aGUgZmlyc3QgZGlzY29ubmVjdCwgbm90IG9uY2UgcGVyIHRyeVxuICAgICAgICAgICAgY29ubmVjdGlvbkJyb2tlbi5jYWxsKHRoaXMsIG1lc3NhZ2UpO1xuICAgICAgICB9XG4gICAgfS5iaW5kKHRoaXMpKTtcblxuICAgIGNvbWV0ZC5hZGRMaXN0ZW5lcignL21ldGEvZGlzY29ubmVjdCcsIGNvbm5lY3Rpb25Ccm9rZW4pO1xuXG4gICAgY29tZXRkLmFkZExpc3RlbmVyKCcvbWV0YS9oYW5kc2hha2UnLCBmdW5jdGlvbiAobWVzc2FnZSkge1xuICAgICAgICBpZiAobWVzc2FnZS5zdWNjZXNzZnVsKSB7XG4gICAgICAgICAgICAvL2h0dHA6Ly9kb2NzLmNvbWV0ZC5vcmcvcmVmZXJlbmNlL2phdmFzY3JpcHRfc3Vic2NyaWJlLmh0bWwjamF2YXNjcmlwdF9zdWJzY3JpYmVfbWV0YV9jaGFubmVsc1xuICAgICAgICAgICAgLy8gXiBcImR5bmFtaWMgc3Vic2NyaXB0aW9ucyBhcmUgY2xlYXJlZCAobGlrZSBhbnkgb3RoZXIgc3Vic2NyaXB0aW9uKSBhbmQgdGhlIGFwcGxpY2F0aW9uIG5lZWRzIHRvIGZpZ3VyZSBvdXQgd2hpY2ggZHluYW1pYyBzdWJzY3JpcHRpb24gbXVzdCBiZSBwZXJmb3JtZWQgYWdhaW5cIlxuICAgICAgICAgICAgY29tZXRkLmJhdGNoKGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgICAgICAkKG1lLmN1cnJlbnRTdWJzY3JpcHRpb25zKS5lYWNoKGZ1bmN0aW9uIChpbmRleCwgc3Vicykge1xuICAgICAgICAgICAgICAgICAgICBjb21ldGQucmVzdWJzY3JpYmUoc3Vicyk7XG4gICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICB9KTtcbiAgICAgICAgfVxuICAgIH0pO1xuXG4gICAgLy9PdGhlciBpbnRlcmVzdGluZyBldmVudHMgZm9yIHJlZmVyZW5jZVxuICAgIGNvbWV0ZC5hZGRMaXN0ZW5lcignL21ldGEvc3Vic2NyaWJlJywgZnVuY3Rpb24gKG1lc3NhZ2UpIHtcbiAgICAgICAgJChtZSkudHJpZ2dlcignc3Vic2NyaWJlJywgbWVzc2FnZSk7XG4gICAgfSk7XG4gICAgY29tZXRkLmFkZExpc3RlbmVyKCcvbWV0YS91bnN1YnNjcmliZScsIGZ1bmN0aW9uIChtZXNzYWdlKSB7XG4gICAgICAgICQobWUpLnRyaWdnZXIoJ3Vuc3Vic2NyaWJlJywgbWVzc2FnZSk7XG4gICAgfSk7XG4gICAgY29tZXRkLmFkZExpc3RlbmVyKCcvbWV0YS9wdWJsaXNoJywgZnVuY3Rpb24gKG1lc3NhZ2UpIHtcbiAgICAgICAgJChtZSkudHJpZ2dlcigncHVibGlzaCcsIG1lc3NhZ2UpO1xuICAgIH0pO1xuICAgIGNvbWV0ZC5hZGRMaXN0ZW5lcignL21ldGEvdW5zdWNjZXNzZnVsJywgZnVuY3Rpb24gKG1lc3NhZ2UpIHtcbiAgICAgICAgJChtZSkudHJpZ2dlcignZXJyb3InLCBtZXNzYWdlKTtcbiAgICB9KTtcblxuICAgIGNvbWV0ZC5oYW5kc2hha2UoZGVmYXVsdENvbWV0T3B0aW9ucy5oYW5kc2hha2UpO1xuXG4gICAgdGhpcy5jb21ldGQgPSBjb21ldGQ7XG59O1xuXG5cbkNoYW5uZWxNYW5hZ2VyLnByb3RvdHlwZSA9ICQuZXh0ZW5kKENoYW5uZWxNYW5hZ2VyLnByb3RvdHlwZSwge1xuXG4gICAgLyoqXG4gICAgICogQ3JlYXRlcyBhbmQgcmV0dXJucyBhIGNoYW5uZWwsIHRoYXQgaXMsIGFuIGluc3RhbmNlIG9mIGEgW0NoYW5uZWwgU2VydmljZV0oLi4vY2hhbm5lbC1zZXJ2aWNlLykuXG4gICAgICpcbiAgICAgKiAqKkV4YW1wbGUqKlxuICAgICAqXG4gICAgICogICAgICB2YXIgY20gPSBuZXcgRi5tYW5hZ2VyLkNoYW5uZWxNYW5hZ2VyKCk7XG4gICAgICogICAgICB2YXIgY2hhbm5lbCA9IGNtLmdldENoYW5uZWwoKTtcbiAgICAgKlxuICAgICAqICAgICAgY2hhbm5lbC5zdWJzY3JpYmUoJ3RvcGljJywgY2FsbGJhY2spO1xuICAgICAqICAgICAgY2hhbm5lbC5wdWJsaXNoKCd0b3BpYycsIHsgbXlEYXRhOiAxMDAgfSk7XG4gICAgICpcbiAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAqIEBwYXJhbSB7T2JqZWN0fFN0cmluZ30gYG9wdGlvbnNgIChPcHRpb25hbCkgSWYgc3RyaW5nLCBhc3N1bWVkIHRvIGJlIHRoZSBiYXNlIGNoYW5uZWwgdXJsLiBJZiBvYmplY3QsIGFzc3VtZWQgdG8gYmUgY29uZmlndXJhdGlvbiBvcHRpb25zIGZvciB0aGUgY29uc3RydWN0b3IuXG4gICAgICovXG4gICAgZ2V0Q2hhbm5lbDogZnVuY3Rpb24gKG9wdGlvbnMpIHtcbiAgICAgICAgLy9JZiB5b3UganVzdCB3YW50IHRvIHBhc3MgaW4gYSBzdHJpbmdcbiAgICAgICAgaWYgKG9wdGlvbnMgJiYgISQuaXNQbGFpbk9iamVjdChvcHRpb25zKSkge1xuICAgICAgICAgICAgb3B0aW9ucyA9IHtcbiAgICAgICAgICAgICAgICBiYXNlOiBvcHRpb25zXG4gICAgICAgICAgICB9O1xuICAgICAgICB9XG4gICAgICAgIHZhciBkZWZhdWx0cyA9IHtcbiAgICAgICAgICAgIHRyYW5zcG9ydDogdGhpcy5jb21ldGRcbiAgICAgICAgfTtcbiAgICAgICAgdmFyIGNoYW5uZWwgPSBuZXcgQ2hhbm5lbCgkLmV4dGVuZCh0cnVlLCB7fSwgdGhpcy5vcHRpb25zLmNoYW5uZWwsIGRlZmF1bHRzLCBvcHRpb25zKSk7XG5cblxuICAgICAgICAvL1dyYXAgc3VicyBhbmQgdW5zdWJzIHNvIHdlIGNhbiB1c2UgaXQgdG8gcmUtYXR0YWNoIGhhbmRsZXJzIGFmdGVyIGJlaW5nIGRpc2Nvbm5lY3RlZFxuICAgICAgICB2YXIgc3VicyA9IGNoYW5uZWwuc3Vic2NyaWJlO1xuICAgICAgICBjaGFubmVsLnN1YnNjcmliZSA9IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIHZhciBzdWJpZCA9IHN1YnMuYXBwbHkoY2hhbm5lbCwgYXJndW1lbnRzKTtcbiAgICAgICAgICAgIHRoaXMuY3VycmVudFN1YnNjcmlwdGlvbnMgID0gdGhpcy5jdXJyZW50U3Vic2NyaXB0aW9ucy5jb25jYXQoc3ViaWQpO1xuICAgICAgICAgICAgcmV0dXJuIHN1YmlkO1xuICAgICAgICB9LmJpbmQodGhpcyk7XG5cblxuICAgICAgICB2YXIgdW5zdWJzID0gY2hhbm5lbC51bnN1YnNjcmliZTtcbiAgICAgICAgY2hhbm5lbC51bnN1YnNjcmliZSA9IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIHZhciByZW1vdmVkID0gdW5zdWJzLmFwcGx5KGNoYW5uZWwsIGFyZ3VtZW50cyk7XG4gICAgICAgICAgICBmb3IgKHZhciBpID0gMDsgaSA8IHRoaXMuY3VycmVudFN1YnNjcmlwdGlvbnMubGVuZ3RoOyBpKyspIHtcbiAgICAgICAgICAgICAgICBpZiAodGhpcy5jdXJyZW50U3Vic2NyaXB0aW9uc1tpXS5pZCA9PT0gcmVtb3ZlZC5pZCkge1xuICAgICAgICAgICAgICAgICAgICB0aGlzLmN1cnJlbnRTdWJzY3JpcHRpb25zLnNwbGljZShpLCAxKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICByZXR1cm4gcmVtb3ZlZDtcbiAgICAgICAgfS5iaW5kKHRoaXMpO1xuXG4gICAgICAgIHJldHVybiBjaGFubmVsO1xuICAgIH0sXG5cbiAgICAvKipcbiAgICAgKiBTdGFydCBsaXN0ZW5pbmcgZm9yIGV2ZW50cyBvbiB0aGlzIGluc3RhbmNlLiBTaWduYXR1cmUgaXMgc2FtZSBhcyBmb3IgalF1ZXJ5IEV2ZW50czogaHR0cDovL2FwaS5qcXVlcnkuY29tL29uLy5cbiAgICAgKlxuICAgICAqIFN1cHBvcnRlZCBldmVudHMgYXJlOiBgY29ubmVjdGAsIGBkaXNjb25uZWN0YCwgYHN1YnNjcmliZWAsIGB1bnN1YnNjcmliZWAsIGBwdWJsaXNoYCwgYGVycm9yYC5cbiAgICAgKlxuICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICpcbiAgICAgKiBAcGFyYW0ge3N0cmluZ30gYGV2ZW50YCBUaGUgZXZlbnQgdHlwZS4gU2VlIG1vcmUgZGV0YWlsIGF0IGpRdWVyeSBFdmVudHM6IGh0dHA6Ly9hcGkuanF1ZXJ5LmNvbS9vbi8uXG4gICAgICovXG4gICAgb246IGZ1bmN0aW9uIChldmVudCkge1xuICAgICAgICAkKHRoaXMpLm9uLmFwcGx5KCQodGhpcyksIGFyZ3VtZW50cyk7XG4gICAgfSxcblxuICAgIC8qKlxuICAgICAqIFN0b3AgbGlzdGVuaW5nIGZvciBldmVudHMgb24gdGhpcyBpbnN0YW5jZS4gU2lnbmF0dXJlIGlzIHNhbWUgYXMgZm9yIGpRdWVyeSBFdmVudHM6IGh0dHA6Ly9hcGkuanF1ZXJ5LmNvbS9vZmYvLlxuICAgICAqXG4gICAgICogKipQYXJhbWV0ZXJzKipcbiAgICAgKlxuICAgICAqIEBwYXJhbSB7c3RyaW5nfSBgZXZlbnRgIFRoZSBldmVudCB0eXBlLiBTZWUgbW9yZSBkZXRhaWwgYXQgalF1ZXJ5IEV2ZW50czogaHR0cDovL2FwaS5qcXVlcnkuY29tL29mZi8uXG4gICAgICovXG4gICAgb2ZmOiBmdW5jdGlvbiAoZXZlbnQpIHtcbiAgICAgICAgJCh0aGlzKS5vZmYuYXBwbHkoJCh0aGlzKSwgYXJndW1lbnRzKTtcbiAgICB9LFxuXG4gICAgLyoqXG4gICAgICogVHJpZ2dlciBldmVudHMgYW5kIGV4ZWN1dGUgaGFuZGxlcnMuIFNpZ25hdHVyZSBpcyBzYW1lIGFzIGZvciBqUXVlcnkgRXZlbnRzOiBodHRwOi8vYXBpLmpxdWVyeS5jb20vdHJpZ2dlci8uXG4gICAgICpcbiAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAqXG4gICAgICogQHBhcmFtIHtzdHJpbmd9IGBldmVudGAgVGhlIGV2ZW50IHR5cGUuIFNlZSBtb3JlIGRldGFpbCBhdCBqUXVlcnkgRXZlbnRzOiBodHRwOi8vYXBpLmpxdWVyeS5jb20vdHJpZ2dlci8uXG4gICAgICovXG4gICAgdHJpZ2dlcjogZnVuY3Rpb24gKGV2ZW50KSB7XG4gICAgICAgICQodGhpcykudHJpZ2dlci5hcHBseSgkKHRoaXMpLCBhcmd1bWVudHMpO1xuICAgIH1cbn0pO1xuXG5tb2R1bGUuZXhwb3J0cyA9IENoYW5uZWxNYW5hZ2VyO1xuIiwiJ3VzZSBzdHJpY3QnO1xuXG4vKipcbiAqICMjIEVwaWNlbnRlciBDaGFubmVsIE1hbmFnZXJcbiAqXG4gKiBUaGUgRXBpY2VudGVyIHBsYXRmb3JtIHByb3ZpZGVzIGEgcHVzaCBjaGFubmVsLCB3aGljaCBhbGxvd3MgeW91IHRvIHB1Ymxpc2ggYW5kIHN1YnNjcmliZSB0byBtZXNzYWdlcyB3aXRoaW4gYSBbcHJvamVjdF0oLi4vLi4vLi4vZ2xvc3NhcnkvI3Byb2plY3RzKSwgW2dyb3VwXSguLi8uLi8uLi9nbG9zc2FyeS8jZ3JvdXBzKSwgb3IgW211bHRpcGxheWVyIHdvcmxkXSguLi8uLi8uLi9nbG9zc2FyeS8jd29ybGQpLiBUaGVyZSBhcmUgdHdvIG1haW4gdXNlIGNhc2VzIGZvciB0aGUgY2hhbm5lbDogZXZlbnQgbm90aWZpY2F0aW9ucyBhbmQgY2hhdCBtZXNzYWdlcy5cbiAqXG4gKiBUaGUgRXBpY2VudGVyIENoYW5uZWwgTWFuYWdlciBpcyBhIHdyYXBwZXIgYXJvdW5kIHRoZSAobW9yZSBnZW5lcmljKSBbQ2hhbm5lbCBNYW5hZ2VyXSguLi9jaGFubmVsLW1hbmFnZXIvKSwgdG8gaW5zdGFudGlhdGUgaXQgd2l0aCBFcGljZW50ZXItc3BlY2lmaWMgZGVmYXVsdHMuIElmIHlvdSBhcmUgaW50ZXJlc3RlZCBpbiBpbmNsdWRpbmcgYSBub3RpZmljYXRpb24gb3IgY2hhdCBmZWF0dXJlIGluIHlvdXIgcHJvamVjdCwgdXNpbmcgYW4gRXBpY2VudGVyIENoYW5uZWwgTWFuYWdlciBpcyBwcm9iYWJseSB0aGUgZWFzaWVzdCB3YXkgdG8gZ2V0IHN0YXJ0ZWQuXG4gKlxuICogWW91J2xsIG5lZWQgdG8gaW5jbHVkZSB0aGUgYGVwaWNlbnRlci1tdWx0aXBsYXllci1kZXBlbmRlbmNpZXMuanNgIGxpYnJhcnkgaW4gYWRkaXRpb24gdG8gdGhlIGBlcGljZW50ZXIuanNgIGxpYnJhcnkgaW4geW91ciBwcm9qZWN0IHRvIHVzZSB0aGUgRXBpY2VudGVyIENoYW5uZWwgTWFuYWdlci4gU2VlIFtJbmNsdWRpbmcgRXBpY2VudGVyLmpzXSguLi8uLi8jaW5jbHVkZSkuXG4gKlxuICogVG8gdXNlIHRoZSBFcGljZW50ZXIgQ2hhbm5lbCBNYW5hZ2VyOiBpbnN0YW50aWF0ZSBpdCwgZ2V0IHRoZSBjaGFubmVsIG9mIHRoZSBzY29wZSB5b3Ugd2FudCAoW3VzZXJdKC4uLy4uLy4uL2dsb3NzYXJ5LyN1c2VycyksIFt3b3JsZF0oLi4vLi4vLi4vZ2xvc3NhcnkvI3dvcmxkKSwgb3IgW2dyb3VwXSguLi8uLi8uLi9nbG9zc2FyeS8jZ3JvdXBzKSksIHRoZW4gdXNlIHRoZSBjaGFubmVsJ3MgYHN1YnNjcmliZSgpYCBhbmQgYHB1Ymxpc2goKWAgbWV0aG9kcyB0byBzdWJzY3JpYmUgdG8gdG9waWNzIG9yIHB1Ymxpc2ggZGF0YSB0byB0b3BpY3MuXG4gKlxuICogICAgIHZhciBjbSA9IG5ldyBGLm1hbmFnZXIuQ2hhbm5lbE1hbmFnZXIoKTtcbiAqICAgICB2YXIgZ2MgPSBjbS5nZXRHcm91cENoYW5uZWwoKTtcbiAqICAgICBnYy5zdWJzY3JpYmUoJ2Jyb2FkY2FzdHMnLCBjYWxsYmFjayk7XG4gKlxuICogRm9yIGFkZGl0aW9uYWwgYmFja2dyb3VuZCBvbiBFcGljZW50ZXIncyBwdXNoIGNoYW5uZWwsIHNlZSB0aGUgaW50cm9kdWN0b3J5IG5vdGVzIG9uIHRoZSBbUHVzaCBDaGFubmVsIEFQSV0oLi4vLi4vLi4vcmVzdF9hcGlzL211bHRpcGxheWVyL2NoYW5uZWwvKSBwYWdlLlxuICpcbiAqIFRoZSBwYXJhbWV0ZXJzIGZvciBpbnN0YW50aWF0aW5nIGFuIEVwaWNlbnRlciBDaGFubmVsIE1hbmFnZXIgaW5jbHVkZTpcbiAqXG4gKiAqIGBvcHRpb25zYCBPYmplY3Qgd2l0aCBkZXRhaWxzIGFib3V0IHRoZSBFcGljZW50ZXIgcHJvamVjdCBmb3IgdGhpcyBFcGljZW50ZXIgQ2hhbm5lbCBNYW5hZ2VyIGluc3RhbmNlLlxuICogKiBgb3B0aW9ucy5hY2NvdW50YCBUaGUgRXBpY2VudGVyIGFjY291bnQgaWQgKCoqVGVhbSBJRCoqIGZvciB0ZWFtIHByb2plY3RzLCAqKlVzZXIgSUQqKiBmb3IgcGVyc29uYWwgcHJvamVjdHMpLlxuICogKiBgb3B0aW9ucy5wcm9qZWN0YCBFcGljZW50ZXIgcHJvamVjdCBpZC5cbiAqICogYG9wdGlvbnMudXNlck5hbWVgIEVwaWNlbnRlciB1c2VyTmFtZSB1c2VkIGZvciBhdXRoZW50aWNhdGlvbi5cbiAqICogYG9wdGlvbnMudXNlcklkYCBFcGljZW50ZXIgdXNlciBpZCB1c2VkIGZvciBhdXRoZW50aWNhdGlvbi4gT3B0aW9uYWw7IGBvcHRpb25zLnVzZXJOYW1lYCBpcyBwcmVmZXJyZWQuXG4gKiAqIGBvcHRpb25zLnRva2VuYCBFcGljZW50ZXIgdG9rZW4gdXNlZCBmb3IgYXV0aGVudGljYXRpb24uIChZb3UgY2FuIHJldHJpZXZlIHRoaXMgdXNpbmcgYGF1dGhNYW5hZ2VyLmdldFRva2VuKClgIGZyb20gdGhlIFtBdXRob3JpemF0aW9uIE1hbmFnZXJdKC4uL2F1dGgtbWFuYWdlci8pLilcbiAqICogYG9wdGlvbnMuYWxsb3dBbGxDaGFubmVsc2AgSWYgbm90IGluY2x1ZGVkIG9yIGlmIHNldCB0byBgZmFsc2VgLCBhbGwgY2hhbm5lbCBwYXRocyBhcmUgdmFsaWRhdGVkOyBpZiB5b3VyIHByb2plY3QgcmVxdWlyZXMgW1B1c2ggQ2hhbm5lbCBBdXRob3JpemF0aW9uXSguLi8uLi8uLi91cGRhdGluZ195b3VyX3NldHRpbmdzLyksIHlvdSBzaG91bGQgdXNlIHRoaXMgb3B0aW9uLiBJZiB5b3Ugd2FudCB0byBhbGxvdyBvdGhlciBjaGFubmVsIHBhdGhzLCBzZXQgdG8gYHRydWVgOyB0aGlzIGlzIG5vdCBjb21tb24uXG4gKi9cblxudmFyIENoYW5uZWxNYW5hZ2VyID0gcmVxdWlyZSgnLi9jaGFubmVsLW1hbmFnZXInKTtcbnZhciBjbGFzc0Zyb20gPSByZXF1aXJlKCcuLi91dGlsL2luaGVyaXQnKTtcbnZhciB1cmxTZXJ2aWNlID0gcmVxdWlyZSgnLi4vc2VydmljZS91cmwtY29uZmlnLXNlcnZpY2UnKTtcbnZhciBTZXNzaW9uTWFuYWdlciA9IHJlcXVpcmUoJy4uL3N0b3JlL3Nlc3Npb24tbWFuYWdlcicpO1xuXG52YXIgQXV0aE1hbmFnZXIgPSByZXF1aXJlKCcuL2F1dGgtbWFuYWdlcicpO1xuXG52YXIgdmFsaWRUeXBlcyA9IHtcbiAgICBwcm9qZWN0OiB0cnVlLFxuICAgIGdyb3VwOiB0cnVlLFxuICAgIHdvcmxkOiB0cnVlLFxuICAgIHVzZXI6IHRydWUsXG4gICAgZGF0YTogdHJ1ZSxcbiAgICBnZW5lcmFsOiB0cnVlLFxuICAgIGNoYXQ6IHRydWVcbn07XG52YXIgc2Vzc2lvbiA9IG5ldyBBdXRoTWFuYWdlcigpO1xudmFyIGdldEZyb21TZXR0aW5nc09yU2Vzc2lvbk9yRXJyb3IgPSBmdW5jdGlvbiAodmFsdWUsIHNlc3Npb25LZXlOYW1lLCBzZXR0aW5ncykge1xuICAgIGlmICghdmFsdWUpIHtcbiAgICAgICAgdmFyIHVzZXJJbmZvID0gc2Vzc2lvbi5nZXRDdXJyZW50VXNlclNlc3Npb25JbmZvKCk7XG4gICAgICAgIGlmIChzZXR0aW5ncyAmJiBzZXR0aW5nc1tzZXNzaW9uS2V5TmFtZV0pIHtcbiAgICAgICAgICAgIHZhbHVlID0gc2V0dGluZ3Nbc2Vzc2lvbktleU5hbWVdO1xuICAgICAgICB9IGVsc2UgaWYgKHVzZXJJbmZvW3Nlc3Npb25LZXlOYW1lXSkge1xuICAgICAgICAgICAgdmFsdWUgPSB1c2VySW5mb1tzZXNzaW9uS2V5TmFtZV07XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3Ioc2Vzc2lvbktleU5hbWUgKyAnIG5vdCBmb3VuZC4gUGxlYXNlIGxvZy1pbiBhZ2Fpbiwgb3Igc3BlY2lmeSAnICsgc2Vzc2lvbktleU5hbWUgKyAnIGV4cGxpY2l0bHknKTtcbiAgICAgICAgfVxuICAgIH1cbiAgICByZXR1cm4gdmFsdWU7XG59O1xudmFyIF9fc3VwZXIgPSBDaGFubmVsTWFuYWdlci5wcm90b3R5cGU7XG52YXIgRXBpY2VudGVyQ2hhbm5lbE1hbmFnZXIgPSBjbGFzc0Zyb20oQ2hhbm5lbE1hbmFnZXIsIHtcbiAgICBjb25zdHJ1Y3RvcjogZnVuY3Rpb24gKG9wdGlvbnMpIHtcbiAgICAgICAgdGhpcy5zZXNzaW9uTWFuYWdlciA9IG5ldyBTZXNzaW9uTWFuYWdlcigpO1xuICAgICAgICB2YXIgZGVmYXVsdENvbWV0T3B0aW9ucyA9IHRoaXMuc2Vzc2lvbk1hbmFnZXIuZ2V0TWVyZ2VkT3B0aW9ucyhvcHRpb25zKTtcblxuICAgICAgICB2YXIgdXJsT3B0cyA9IHVybFNlcnZpY2UoZGVmYXVsdENvbWV0T3B0aW9ucy5zZXJ2ZXIpO1xuICAgICAgICBpZiAoIWRlZmF1bHRDb21ldE9wdGlvbnMudXJsKSB7XG4gICAgICAgICAgICAvL0RlZmF1bHQgZXBpY2VudGVyIGNvbWV0ZCBlbmRwb2ludFxuICAgICAgICAgICAgZGVmYXVsdENvbWV0T3B0aW9ucy51cmwgPSB1cmxPcHRzLnByb3RvY29sICsgJzovLycgKyB1cmxPcHRzLmhvc3QgKyAnL2NoYW5uZWwvc3Vic2NyaWJlJztcbiAgICAgICAgfVxuXG4gICAgICAgIGlmIChkZWZhdWx0Q29tZXRPcHRpb25zLmhhbmRzaGFrZSA9PT0gdW5kZWZpbmVkKSB7XG4gICAgICAgICAgICB2YXIgdXNlck5hbWUgPSBkZWZhdWx0Q29tZXRPcHRpb25zLnVzZXJOYW1lO1xuICAgICAgICAgICAgdmFyIHVzZXJJZCA9IGRlZmF1bHRDb21ldE9wdGlvbnMudXNlcklkO1xuICAgICAgICAgICAgdmFyIHRva2VuID0gZGVmYXVsdENvbWV0T3B0aW9ucy50b2tlbjtcbiAgICAgICAgICAgIGlmICgodXNlck5hbWUgfHwgdXNlcklkKSAmJiB0b2tlbikge1xuICAgICAgICAgICAgICAgIHZhciB1c2VyUHJvcCA9IHVzZXJOYW1lID8gJ3VzZXJOYW1lJyA6ICd1c2VySWQnO1xuICAgICAgICAgICAgICAgIHZhciBleHQgPSB7XG4gICAgICAgICAgICAgICAgICAgIGF1dGhvcml6YXRpb246ICdCZWFyZXIgJyArIHRva2VuXG4gICAgICAgICAgICAgICAgfTtcbiAgICAgICAgICAgICAgICBleHRbdXNlclByb3BdID0gdXNlck5hbWUgPyB1c2VyTmFtZSA6IHVzZXJJZDtcblxuICAgICAgICAgICAgICAgIGRlZmF1bHRDb21ldE9wdGlvbnMuaGFuZHNoYWtlID0ge1xuICAgICAgICAgICAgICAgICAgICBleHQ6IGV4dFxuICAgICAgICAgICAgICAgIH07XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICB0aGlzLm9wdGlvbnMgPSBkZWZhdWx0Q29tZXRPcHRpb25zO1xuICAgICAgICByZXR1cm4gX19zdXBlci5jb25zdHJ1Y3Rvci5jYWxsKHRoaXMsIGRlZmF1bHRDb21ldE9wdGlvbnMpO1xuICAgIH0sXG5cbiAgICAvKipcbiAgICAgKiBDcmVhdGVzIGFuZCByZXR1cm5zIGEgY2hhbm5lbCwgdGhhdCBpcywgYW4gaW5zdGFuY2Ugb2YgYSBbQ2hhbm5lbCBTZXJ2aWNlXSguLi9jaGFubmVsLXNlcnZpY2UvKS5cbiAgICAgKlxuICAgICAqIFRoaXMgbWV0aG9kIGVuZm9yY2VzIEVwaWNlbnRlci1zcGVjaWZpYyBjaGFubmVsIG5hbWluZzogYWxsIGNoYW5uZWxzIHJlcXVlc3RlZCBtdXN0IGJlIGluIHRoZSBmb3JtIGAve3R5cGV9L3thY2NvdW50IGlkfS97cHJvamVjdCBpZH0vey4uLn1gLCB3aGVyZSBgdHlwZWAgaXMgb25lIG9mIGBydW5gLCBgZGF0YWAsIGB1c2VyYCwgYHdvcmxkYCwgb3IgYGNoYXRgLlxuICAgICAqXG4gICAgICogKipFeGFtcGxlKipcbiAgICAgKlxuICAgICAqICAgICAgdmFyIGNtID0gbmV3IEYubWFuYWdlci5FcGljZW50ZXJDaGFubmVsTWFuYWdlcigpO1xuICAgICAqICAgICAgdmFyIGNoYW5uZWwgPSBjbS5nZXRDaGFubmVsKCcvZ3JvdXAvYWNtZS9zdXBwbHktY2hhaW4tZ2FtZS8nKTtcbiAgICAgKlxuICAgICAqICAgICAgY2hhbm5lbC5zdWJzY3JpYmUoJ3RvcGljJywgY2FsbGJhY2spO1xuICAgICAqICAgICAgY2hhbm5lbC5wdWJsaXNoKCd0b3BpYycsIHsgbXlEYXRhOiAxMDAgfSk7XG4gICAgICpcbiAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAqIEBwYXJhbSB7T2JqZWN0fFN0cmluZ30gYG9wdGlvbnNgIChPcHRpb25hbCkgSWYgc3RyaW5nLCBhc3N1bWVkIHRvIGJlIHRoZSBiYXNlIGNoYW5uZWwgdXJsLiBJZiBvYmplY3QsIGFzc3VtZWQgdG8gYmUgY29uZmlndXJhdGlvbiBvcHRpb25zIGZvciB0aGUgY29uc3RydWN0b3IuXG4gICAgICovXG4gICAgZ2V0Q2hhbm5lbDogZnVuY3Rpb24gKG9wdGlvbnMpIHtcbiAgICAgICAgaWYgKG9wdGlvbnMgJiYgdHlwZW9mIG9wdGlvbnMgIT09ICdvYmplY3QnKSB7XG4gICAgICAgICAgICBvcHRpb25zID0ge1xuICAgICAgICAgICAgICAgIGJhc2U6IG9wdGlvbnNcbiAgICAgICAgICAgIH07XG4gICAgICAgIH1cbiAgICAgICAgdmFyIGNoYW5uZWxPcHRzID0gJC5leHRlbmQoe30sIHRoaXMub3B0aW9ucywgb3B0aW9ucyk7XG4gICAgICAgIHZhciBiYXNlID0gY2hhbm5lbE9wdHMuYmFzZTtcbiAgICAgICAgaWYgKCFiYXNlKSB7XG4gICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ05vIGJhc2UgdG9waWMgd2FzIHByb3ZpZGVkJyk7XG4gICAgICAgIH1cblxuICAgICAgICBpZiAoIWNoYW5uZWxPcHRzLmFsbG93QWxsQ2hhbm5lbHMpIHtcbiAgICAgICAgICAgIHZhciBiYXNlUGFydHMgPSBiYXNlLnNwbGl0KCcvJyk7XG4gICAgICAgICAgICB2YXIgY2hhbm5lbFR5cGUgPSBiYXNlUGFydHNbMV07XG4gICAgICAgICAgICBpZiAoYmFzZVBhcnRzLmxlbmd0aCA8IDQpIHtcbiAgICAgICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ0ludmFsaWQgY2hhbm5lbCBiYXNlIG5hbWUsIGl0IG11c3QgYmUgaW4gdGhlIGZvcm0gL3t0eXBlfS97YWNjb3VudCBpZH0ve3Byb2plY3QgaWR9L3suLi59Jyk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBpZiAoIXZhbGlkVHlwZXNbY2hhbm5lbFR5cGVdKSB7XG4gICAgICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdJbnZhbGlkIGNoYW5uZWwgdHlwZScpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgIHJldHVybiBfX3N1cGVyLmdldENoYW5uZWwuYXBwbHkodGhpcywgYXJndW1lbnRzKTtcbiAgICB9LFxuXG4gICAgLyoqXG4gICAgICogQ3JlYXRlIGFuZCByZXR1cm4gYSBwdWJsaXNoL3N1YnNjcmliZSBjaGFubmVsIChmcm9tIHRoZSB1bmRlcmx5aW5nIFtDaGFubmVsIE1hbmFnZXJdKC4uL2NoYW5uZWwtbWFuYWdlci8pKSBmb3IgdGhlIGdpdmVuIFtncm91cF0oLi4vLi4vLi4vZ2xvc3NhcnkvI2dyb3VwcykuIFRoZSBncm91cCBtdXN0IGV4aXN0IGluIHRoZSBhY2NvdW50ICh0ZWFtKSBhbmQgcHJvamVjdCBwcm92aWRlZC5cbiAgICAgKlxuICAgICAqIFRoZXJlIGFyZSBubyBub3RpZmljYXRpb25zIGZyb20gRXBpY2VudGVyIG9uIHRoaXMgY2hhbm5lbDsgYWxsIG1lc3NhZ2VzIGFyZSB1c2VyLW9yaWdpbmF0ZWQuXG4gICAgICpcbiAgICAgKiAqKkV4YW1wbGUqKlxuICAgICAqXG4gICAgICogICAgIHZhciBjbSA9IG5ldyBGLm1hbmFnZXIuQ2hhbm5lbE1hbmFnZXIoKTtcbiAgICAgKiAgICAgdmFyIGdjID0gY20uZ2V0R3JvdXBDaGFubmVsKCk7XG4gICAgICogICAgIGdjLnN1YnNjcmliZSgnYnJvYWRjYXN0cycsIGNhbGxiYWNrKTtcbiAgICAgKlxuICAgICAqICoqUmV0dXJuIFZhbHVlKipcbiAgICAgKlxuICAgICAqICogKkNoYW5uZWwqIFJldHVybnMgdGhlIGNoYW5uZWwgKGFuIGluc3RhbmNlIG9mIHRoZSBbQ2hhbm5lbCBTZXJ2aWNlXSguLi9jaGFubmVsLXNlcnZpY2UvKSkuXG4gICAgICpcbiAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAqXG4gICAgICogQHBhcmFtICB7U3RyaW5nfSBgZ3JvdXBOYW1lYCAoT3B0aW9uYWwpIEdyb3VwIHRvIGJyb2FkY2FzdCB0by4gSWYgbm90IHByb3ZpZGVkLCBwaWNrcyB1cCBncm91cCBmcm9tIGN1cnJlbnQgc2Vzc2lvbiBpZiBlbmQgdXNlciBpcyBsb2dnZWQgaW4uXG4gICAgICovXG4gICAgZ2V0R3JvdXBDaGFubmVsOiBmdW5jdGlvbiAoZ3JvdXBOYW1lKSB7XG4gICAgICAgIGdyb3VwTmFtZSA9IGdldEZyb21TZXR0aW5nc09yU2Vzc2lvbk9yRXJyb3IoZ3JvdXBOYW1lLCAnZ3JvdXBOYW1lJywgdGhpcy5vcHRpb25zKTtcbiAgICAgICAgdmFyIGFjY291bnQgPSBnZXRGcm9tU2V0dGluZ3NPclNlc3Npb25PckVycm9yKCcnLCAnYWNjb3VudCcsIHRoaXMub3B0aW9ucyk7XG4gICAgICAgIHZhciBwcm9qZWN0ID0gZ2V0RnJvbVNldHRpbmdzT3JTZXNzaW9uT3JFcnJvcignJywgJ3Byb2plY3QnLCB0aGlzLm9wdGlvbnMpO1xuXG4gICAgICAgIHZhciBiYXNlVG9waWMgPSBbJy9ncm91cCcsIGFjY291bnQsIHByb2plY3QsIGdyb3VwTmFtZV0uam9pbignLycpO1xuICAgICAgICByZXR1cm4gX19zdXBlci5nZXRDaGFubmVsLmNhbGwodGhpcywgeyBiYXNlOiBiYXNlVG9waWMgfSk7XG4gICAgfSxcblxuICAgIC8qKlxuICAgICAqIENyZWF0ZSBhbmQgcmV0dXJuIGEgcHVibGlzaC9zdWJzY3JpYmUgY2hhbm5lbCAoZnJvbSB0aGUgdW5kZXJseWluZyBbQ2hhbm5lbCBNYW5hZ2VyXSguLi9jaGFubmVsLW1hbmFnZXIvKSkgZm9yIHRoZSBnaXZlbiBbd29ybGRdKC4uLy4uLy4uL2dsb3NzYXJ5LyN3b3JsZCkuXG4gICAgICpcbiAgICAgKiBUaGlzIGlzIHR5cGljYWxseSB1c2VkIHRvZ2V0aGVyIHdpdGggdGhlIFtXb3JsZCBNYW5hZ2VyXSguLi93b3JsZC1tYW5hZ2VyKS5cbiAgICAgKlxuICAgICAqICoqRXhhbXBsZSoqXG4gICAgICpcbiAgICAgKiAgICAgdmFyIGNtID0gbmV3IEYubWFuYWdlci5DaGFubmVsTWFuYWdlcigpO1xuICAgICAqICAgICB2YXIgd29ybGRNYW5hZ2VyID0gbmV3IEYubWFuYWdlci5Xb3JsZE1hbmFnZXIoe1xuICAgICAqICAgICAgICAgYWNjb3VudDogJ2FjbWUtc2ltdWxhdGlvbnMnLFxuICAgICAqICAgICAgICAgcHJvamVjdDogJ3N1cHBseS1jaGFpbi1nYW1lJyxcbiAgICAgKiAgICAgICAgIGdyb3VwOiAndGVhbTEnLFxuICAgICAqICAgICAgICAgcnVuOiB7IG1vZGVsOiAnbW9kZWwuZXFuJyB9XG4gICAgICogICAgIH0pO1xuICAgICAqICAgICB3b3JsZE1hbmFnZXIuZ2V0Q3VycmVudFdvcmxkKCkudGhlbihmdW5jdGlvbiAod29ybGRPYmplY3QsIHdvcmxkQWRhcHRlcikge1xuICAgICAqICAgICAgICAgdmFyIHdvcmxkQ2hhbm5lbCA9IGNtLmdldFdvcmxkQ2hhbm5lbCh3b3JsZE9iamVjdCk7XG4gICAgICogICAgICAgICB3b3JsZENoYW5uZWwuc3Vic2NyaWJlKCcnLCBmdW5jdGlvbiAoZGF0YSkge1xuICAgICAqICAgICAgICAgICAgIGNvbnNvbGUubG9nKGRhdGEpO1xuICAgICAqICAgICAgICAgfSk7XG4gICAgICogICAgICB9KTtcbiAgICAgKlxuICAgICAqICoqUmV0dXJuIFZhbHVlKipcbiAgICAgKlxuICAgICAqICogKkNoYW5uZWwqIFJldHVybnMgdGhlIGNoYW5uZWwgKGFuIGluc3RhbmNlIG9mIHRoZSBbQ2hhbm5lbCBTZXJ2aWNlXSguLi9jaGFubmVsLXNlcnZpY2UvKSkuXG4gICAgICpcbiAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAqXG4gICAgICogQHBhcmFtICB7U3RyaW5nfE9iamVjdH0gYHdvcmxkYCBUaGUgd29ybGQgb2JqZWN0IG9yIGlkLlxuICAgICAqIEBwYXJhbSAge1N0cmluZ30gYGdyb3VwTmFtZWAgKE9wdGlvbmFsKSBHcm91cCB0aGUgd29ybGQgZXhpc3RzIGluLiBJZiBub3QgcHJvdmlkZWQsIHBpY2tzIHVwIGdyb3VwIGZyb20gY3VycmVudCBzZXNzaW9uIGlmIGVuZCB1c2VyIGlzIGxvZ2dlZCBpbi5cbiAgICAgKi9cbiAgICBnZXRXb3JsZENoYW5uZWw6IGZ1bmN0aW9uICh3b3JsZCwgZ3JvdXBOYW1lKSB7XG4gICAgICAgIHZhciB3b3JsZGlkID0gKCQuaXNQbGFpbk9iamVjdCh3b3JsZCkgJiYgd29ybGQuaWQpID8gd29ybGQuaWQgOiB3b3JsZDtcbiAgICAgICAgaWYgKCF3b3JsZGlkKSB7XG4gICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ1BsZWFzZSBzcGVjaWZ5IGEgd29ybGQgaWQnKTtcbiAgICAgICAgfVxuICAgICAgICBncm91cE5hbWUgPSBnZXRGcm9tU2V0dGluZ3NPclNlc3Npb25PckVycm9yKGdyb3VwTmFtZSwgJ2dyb3VwTmFtZScsIHRoaXMub3B0aW9ucyk7XG4gICAgICAgIHZhciBhY2NvdW50ID0gZ2V0RnJvbVNldHRpbmdzT3JTZXNzaW9uT3JFcnJvcignJywgJ2FjY291bnQnLCB0aGlzLm9wdGlvbnMpO1xuICAgICAgICB2YXIgcHJvamVjdCA9IGdldEZyb21TZXR0aW5nc09yU2Vzc2lvbk9yRXJyb3IoJycsICdwcm9qZWN0JywgdGhpcy5vcHRpb25zKTtcblxuICAgICAgICB2YXIgYmFzZVRvcGljID0gWycvd29ybGQnLCBhY2NvdW50LCBwcm9qZWN0LCBncm91cE5hbWUsIHdvcmxkaWRdLmpvaW4oJy8nKTtcbiAgICAgICAgcmV0dXJuIF9fc3VwZXIuZ2V0Q2hhbm5lbC5jYWxsKHRoaXMsIHsgYmFzZTogYmFzZVRvcGljIH0pO1xuICAgIH0sXG5cbiAgICAvKipcbiAgICAgKiBDcmVhdGUgYW5kIHJldHVybiBhIHB1Ymxpc2gvc3Vic2NyaWJlIGNoYW5uZWwgKGZyb20gdGhlIHVuZGVybHlpbmcgW0NoYW5uZWwgTWFuYWdlcl0oLi4vY2hhbm5lbC1tYW5hZ2VyLykpIGZvciB0aGUgY3VycmVudCBbZW5kIHVzZXJdKC4uLy4uLy4uL2dsb3NzYXJ5LyN1c2VycykgaW4gdGhhdCB1c2VyJ3MgY3VycmVudCBbd29ybGRdKC4uLy4uLy4uL2dsb3NzYXJ5LyN3b3JsZCkuXG4gICAgICpcbiAgICAgKiBUaGlzIGlzIHR5cGljYWxseSB1c2VkIHRvZ2V0aGVyIHdpdGggdGhlIFtXb3JsZCBNYW5hZ2VyXSguLi93b3JsZC1tYW5hZ2VyKS4gTm90ZSB0aGF0IHRoaXMgY2hhbm5lbCBvbmx5IGdldHMgbm90aWZpY2F0aW9ucyBmb3Igd29ybGRzIGN1cnJlbnRseSBpbiBtZW1vcnkuIChTZWUgbW9yZSBiYWNrZ3JvdW5kIG9uIFtwZXJzaXN0ZW5jZV0oLi4vLi4vLi4vcnVuX3BlcnNpc3RlbmNlKS4pXG4gICAgICpcbiAgICAgKiAqKkV4YW1wbGUqKlxuICAgICAqXG4gICAgICogICAgIHZhciBjbSA9IG5ldyBGLm1hbmFnZXIuQ2hhbm5lbE1hbmFnZXIoKTtcbiAgICAgKiAgICAgdmFyIHdvcmxkTWFuYWdlciA9IG5ldyBGLm1hbmFnZXIuV29ybGRNYW5hZ2VyKHtcbiAgICAgKiAgICAgICAgIGFjY291bnQ6ICdhY21lLXNpbXVsYXRpb25zJyxcbiAgICAgKiAgICAgICAgIHByb2plY3Q6ICdzdXBwbHktY2hhaW4tZ2FtZScsXG4gICAgICogICAgICAgICBncm91cDogJ3RlYW0xJyxcbiAgICAgKiAgICAgICAgIHJ1bjogeyBtb2RlbDogJ21vZGVsLmVxbicgfVxuICAgICAqICAgICB9KTtcbiAgICAgKiAgICAgd29ybGRNYW5hZ2VyLmdldEN1cnJlbnRXb3JsZCgpLnRoZW4oZnVuY3Rpb24gKHdvcmxkT2JqZWN0LCB3b3JsZEFkYXB0ZXIpIHtcbiAgICAgKiAgICAgICAgIHZhciB1c2VyQ2hhbm5lbCA9IGNtLmdldFVzZXJDaGFubmVsKHdvcmxkT2JqZWN0KTtcbiAgICAgKiAgICAgICAgIHVzZXJDaGFubmVsLnN1YnNjcmliZSgnJywgZnVuY3Rpb24gKGRhdGEpIHtcbiAgICAgKiAgICAgICAgICAgICBjb25zb2xlLmxvZyhkYXRhKTtcbiAgICAgKiAgICAgICAgIH0pO1xuICAgICAqICAgICAgfSk7XG4gICAgICpcbiAgICAgKlxuICAgICAqICoqUmV0dXJuIFZhbHVlKipcbiAgICAgKlxuICAgICAqICogKkNoYW5uZWwqIFJldHVybnMgdGhlIGNoYW5uZWwgKGFuIGluc3RhbmNlIG9mIHRoZSBbQ2hhbm5lbCBTZXJ2aWNlXSguLi9jaGFubmVsLXNlcnZpY2UvKSkuXG4gICAgICpcbiAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAqXG4gICAgICogQHBhcmFtICB7U3RyaW5nfE9iamVjdH0gYHdvcmxkYCBXb3JsZCBvYmplY3Qgb3IgaWQuXG4gICAgICogQHBhcmFtICB7U3RyaW5nfE9iamVjdH0gYHVzZXJgIChPcHRpb25hbCkgVXNlciBvYmplY3Qgb3IgaWQuIElmIG5vdCBwcm92aWRlZCwgcGlja3MgdXAgdXNlciBpZCBmcm9tIGN1cnJlbnQgc2Vzc2lvbiBpZiBlbmQgdXNlciBpcyBsb2dnZWQgaW4uXG4gICAgICogQHBhcmFtICB7U3RyaW5nfSBgZ3JvdXBOYW1lYCAoT3B0aW9uYWwpIEdyb3VwIHRoZSB3b3JsZCBleGlzdHMgaW4uIElmIG5vdCBwcm92aWRlZCwgcGlja3MgdXAgZ3JvdXAgZnJvbSBjdXJyZW50IHNlc3Npb24gaWYgZW5kIHVzZXIgaXMgbG9nZ2VkIGluLlxuICAgICAqL1xuICAgIGdldFVzZXJDaGFubmVsOiBmdW5jdGlvbiAod29ybGQsIHVzZXIsIGdyb3VwTmFtZSkge1xuICAgICAgICB2YXIgd29ybGRpZCA9ICgkLmlzUGxhaW5PYmplY3Qod29ybGQpICYmIHdvcmxkLmlkKSA/IHdvcmxkLmlkIDogd29ybGQ7XG4gICAgICAgIGlmICghd29ybGRpZCkge1xuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdQbGVhc2Ugc3BlY2lmeSBhIHdvcmxkIGlkJyk7XG4gICAgICAgIH1cbiAgICAgICAgdmFyIHVzZXJpZCA9ICgkLmlzUGxhaW5PYmplY3QodXNlcikgJiYgdXNlci5pZCkgPyB1c2VyLmlkIDogdXNlcjtcbiAgICAgICAgdXNlcmlkID0gZ2V0RnJvbVNldHRpbmdzT3JTZXNzaW9uT3JFcnJvcih1c2VyaWQsICd1c2VySWQnLCB0aGlzLm9wdGlvbnMpO1xuICAgICAgICBncm91cE5hbWUgPSBnZXRGcm9tU2V0dGluZ3NPclNlc3Npb25PckVycm9yKGdyb3VwTmFtZSwgJ2dyb3VwTmFtZScsIHRoaXMub3B0aW9ucyk7XG5cbiAgICAgICAgdmFyIGFjY291bnQgPSBnZXRGcm9tU2V0dGluZ3NPclNlc3Npb25PckVycm9yKCcnLCAnYWNjb3VudCcsIHRoaXMub3B0aW9ucyk7XG4gICAgICAgIHZhciBwcm9qZWN0ID0gZ2V0RnJvbVNldHRpbmdzT3JTZXNzaW9uT3JFcnJvcignJywgJ3Byb2plY3QnLCB0aGlzLm9wdGlvbnMpO1xuXG4gICAgICAgIHZhciBiYXNlVG9waWMgPSBbJy91c2VyJywgYWNjb3VudCwgcHJvamVjdCwgZ3JvdXBOYW1lLCB3b3JsZGlkLCB1c2VyaWRdLmpvaW4oJy8nKTtcbiAgICAgICAgcmV0dXJuIF9fc3VwZXIuZ2V0Q2hhbm5lbC5jYWxsKHRoaXMsIHsgYmFzZTogYmFzZVRvcGljIH0pO1xuICAgIH0sXG5cbiAgICAvKipcbiAgICAgKiBDcmVhdGUgYW5kIHJldHVybiBhIHB1Ymxpc2gvc3Vic2NyaWJlIGNoYW5uZWwgKGZyb20gdGhlIHVuZGVybHlpbmcgW0NoYW5uZWwgTWFuYWdlcl0oLi4vY2hhbm5lbC1tYW5hZ2VyLykpIHRoYXQgYXV0b21hdGljYWxseSB0cmFja3MgdGhlIHByZXNlbmNlIG9mIGFuIFtlbmQgdXNlcl0oLi4vLi4vLi4vZ2xvc3NhcnkvI3VzZXJzKSwgdGhhdCBpcywgd2hldGhlciB0aGUgZW5kIHVzZXIgaXMgY3VycmVudGx5IG9ubGluZSBpbiB0aGlzIGdyb3VwIGFuZCB3b3JsZC4gTm90aWZpY2F0aW9ucyBhcmUgYXV0b21hdGljYWxseSBzZW50IHdoZW4gdGhlIGVuZCB1c2VyIGNvbWVzIG9ubGluZSwgYW5kIHdoZW4gdGhlIGVuZCB1c2VyIGdvZXMgb2ZmbGluZSAobm90IHByZXNlbnQgZm9yIG1vcmUgdGhhbiAyIG1pbnV0ZXMpLiBVc2VmdWwgaW4gbXVsdGlwbGF5ZXIgZ2FtZXMgZm9yIGxldHRpbmcgZWFjaCBlbmQgdXNlciBrbm93IHdoZXRoZXIgb3RoZXIgdXNlcnMgaW4gdGhlaXIgc2hhcmVkIHdvcmxkIGFyZSBhbHNvIG9ubGluZS5cbiAgICAgKlxuICAgICAqICoqRXhhbXBsZSoqXG4gICAgICpcbiAgICAgKiAgICAgdmFyIGNtID0gbmV3IEYubWFuYWdlci5DaGFubmVsTWFuYWdlcigpO1xuICAgICAqICAgICB2YXIgd29ybGRNYW5hZ2VyID0gbmV3IEYubWFuYWdlci5Xb3JsZE1hbmFnZXIoe1xuICAgICAqICAgICAgICAgYWNjb3VudDogJ2FjbWUtc2ltdWxhdGlvbnMnLFxuICAgICAqICAgICAgICAgcHJvamVjdDogJ3N1cHBseS1jaGFpbi1nYW1lJyxcbiAgICAgKiAgICAgICAgIG1vZGVsOiAnbW9kZWwuZXFuJ1xuICAgICAqICAgICB9KTtcbiAgICAgKiAgICAgd29ybGRNYW5hZ2VyLmdldEN1cnJlbnRXb3JsZCgpLnRoZW4oZnVuY3Rpb24gKHdvcmxkT2JqZWN0LCB3b3JsZFNlcnZpY2UpIHtcbiAgICAgKiAgICAgICAgIHZhciBwcmVzZW5jZUNoYW5uZWwgPSBjbS5nZXRQcmVzZW5jZUNoYW5uZWwod29ybGRPYmplY3QpO1xuICAgICAqICAgICAgICAgcHJlc2VuY2VDaGFubmVsLm9uKCdwcmVzZW5jZScsIGZ1bmN0aW9uIChldnQsIG5vdGlmaWNhdGlvbikge1xuICAgICAqICAgICAgICAgICAgICBjb25zb2xlLmxvZyhub3RpZmljYXRpb24ub25saW5lLCBub3RpZmljYXRpb24udXNlcklkKTtcbiAgICAgKiAgICAgICAgICB9KTtcbiAgICAgKiAgICAgIH0pO1xuICAgICAqXG4gICAgICpcbiAgICAgKiAqKlJldHVybiBWYWx1ZSoqXG4gICAgICpcbiAgICAgKiAqICpDaGFubmVsKiBSZXR1cm5zIHRoZSBjaGFubmVsIChhbiBpbnN0YW5jZSBvZiB0aGUgW0NoYW5uZWwgU2VydmljZV0oLi4vY2hhbm5lbC1zZXJ2aWNlLykpLlxuICAgICAqXG4gICAgICogKipQYXJhbWV0ZXJzKipcbiAgICAgKlxuICAgICAqIEBwYXJhbSAge1N0cmluZ3xPYmplY3R9IGB3b3JsZGAgV29ybGQgb2JqZWN0IG9yIGlkLlxuICAgICAqIEBwYXJhbSAge1N0cmluZ3xPYmplY3R9IGB1c2VyaWRgIChPcHRpb25hbCkgVXNlciBvYmplY3Qgb3IgaWQuIElmIG5vdCBwcm92aWRlZCwgcGlja3MgdXAgdXNlciBpZCBmcm9tIGN1cnJlbnQgc2Vzc2lvbiBpZiBlbmQgdXNlciBpcyBsb2dnZWQgaW4uXG4gICAgICogQHBhcmFtICB7U3RyaW5nfSBgZ3JvdXBOYW1lYCAoT3B0aW9uYWwpIEdyb3VwIHRoZSB3b3JsZCBleGlzdHMgaW4uIElmIG5vdCBwcm92aWRlZCwgcGlja3MgdXAgZ3JvdXAgZnJvbSBjdXJyZW50IHNlc3Npb24gaWYgZW5kIHVzZXIgaXMgbG9nZ2VkIGluLlxuICAgICAqL1xuICAgIGdldFByZXNlbmNlQ2hhbm5lbDogZnVuY3Rpb24gKHdvcmxkLCB1c2VyaWQsIGdyb3VwTmFtZSkge1xuICAgICAgICB2YXIgd29ybGRpZCA9ICgkLmlzUGxhaW5PYmplY3Qod29ybGQpICYmIHdvcmxkLmlkKSA/IHdvcmxkLmlkIDogd29ybGQ7XG4gICAgICAgIGlmICghd29ybGRpZCkge1xuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdQbGVhc2Ugc3BlY2lmeSBhIHdvcmxkIGlkJyk7XG4gICAgICAgIH1cbiAgICAgICAgdXNlcmlkID0gZ2V0RnJvbVNldHRpbmdzT3JTZXNzaW9uT3JFcnJvcih1c2VyaWQsICd1c2VySWQnLCB0aGlzLm9wdGlvbnMpO1xuICAgICAgICBncm91cE5hbWUgPSBnZXRGcm9tU2V0dGluZ3NPclNlc3Npb25PckVycm9yKGdyb3VwTmFtZSwgJ2dyb3VwTmFtZScsIHRoaXMub3B0aW9ucyk7XG5cbiAgICAgICAgdmFyIGFjY291bnQgPSBnZXRGcm9tU2V0dGluZ3NPclNlc3Npb25PckVycm9yKCcnLCAnYWNjb3VudCcsIHRoaXMub3B0aW9ucyk7XG4gICAgICAgIHZhciBwcm9qZWN0ID0gZ2V0RnJvbVNldHRpbmdzT3JTZXNzaW9uT3JFcnJvcignJywgJ3Byb2plY3QnLCB0aGlzLm9wdGlvbnMpO1xuXG4gICAgICAgIHZhciBiYXNlVG9waWMgPSBbJy91c2VyJywgYWNjb3VudCwgcHJvamVjdCwgZ3JvdXBOYW1lLCB3b3JsZGlkXS5qb2luKCcvJyk7XG4gICAgICAgIHZhciBjaGFubmVsID0gX19zdXBlci5nZXRDaGFubmVsLmNhbGwodGhpcywgeyBiYXNlOiBiYXNlVG9waWMgfSk7XG5cbiAgICAgICAgdmFyIGxhc3RQaW5nVGltZSA9IHsgfTtcblxuICAgICAgICB2YXIgUElOR19JTlRFUlZBTCA9IDYwMDA7XG4gICAgICAgIGNoYW5uZWwuc3Vic2NyaWJlKCdpbnRlcm5hbC1waW5nLWNoYW5uZWwnLCBmdW5jdGlvbiAobm90aWZpY2F0aW9uKSB7XG4gICAgICAgICAgICB2YXIgaW5jb21pbmdVc2VySWQgPSBub3RpZmljYXRpb24uZGF0YS51c2VyO1xuICAgICAgICAgICAgaWYgKCFsYXN0UGluZ1RpbWVbaW5jb21pbmdVc2VySWRdICYmIGluY29taW5nVXNlcklkICE9PSB1c2VyaWQpIHtcbiAgICAgICAgICAgICAgICBjaGFubmVsLnRyaWdnZXIuY2FsbChjaGFubmVsLCAncHJlc2VuY2UnLCB7IHVzZXJJZDogaW5jb21pbmdVc2VySWQsIG9ubGluZTogdHJ1ZSB9KTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGxhc3RQaW5nVGltZVtpbmNvbWluZ1VzZXJJZF0gPSAobmV3IERhdGUoKSkudmFsdWVPZigpO1xuICAgICAgICB9KTtcblxuICAgICAgICBzZXRJbnRlcnZhbChmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICBjaGFubmVsLnB1Ymxpc2goJ2ludGVybmFsLXBpbmctY2hhbm5lbCcsIHsgdXNlcjogdXNlcmlkIH0pO1xuXG4gICAgICAgICAgICAkLmVhY2gobGFzdFBpbmdUaW1lLCBmdW5jdGlvbiAoa2V5LCB2YWx1ZSkge1xuICAgICAgICAgICAgICAgIHZhciBub3cgPSAobmV3IERhdGUoKSkudmFsdWVPZigpO1xuICAgICAgICAgICAgICAgIGlmICh2YWx1ZSAmJiB2YWx1ZSArIChQSU5HX0lOVEVSVkFMICogMikgPCBub3cpIHtcbiAgICAgICAgICAgICAgICAgICAgbGFzdFBpbmdUaW1lW2tleV0gPSBudWxsO1xuICAgICAgICAgICAgICAgICAgICBjaGFubmVsLnRyaWdnZXIuY2FsbChjaGFubmVsLCAncHJlc2VuY2UnLCB7IHVzZXJJZDoga2V5LCBvbmxpbmU6IGZhbHNlIH0pO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH0pO1xuICAgICAgICB9LCBQSU5HX0lOVEVSVkFMKTtcblxuICAgICAgICByZXR1cm4gY2hhbm5lbDtcbiAgICB9LFxuXG4gICAgLyoqXG4gICAgICogQ3JlYXRlIGFuZCByZXR1cm4gYSBwdWJsaXNoL3N1YnNjcmliZSBjaGFubmVsIChmcm9tIHRoZSB1bmRlcmx5aW5nIFtDaGFubmVsIE1hbmFnZXJdKC4uL2NoYW5uZWwtbWFuYWdlci8pKSBmb3IgdGhlIGdpdmVuIGNvbGxlY3Rpb24uIChUaGUgY29sbGVjdGlvbiBuYW1lIGlzIHNwZWNpZmllZCBpbiB0aGUgYHJvb3RgIGFyZ3VtZW50IHdoZW4gdGhlIFtEYXRhIFNlcnZpY2VdKC4uL2RhdGEtYXBpLXNlcnZpY2UvKSBpcyBpbnN0YW50aWF0ZWQuKSBNdXN0IGJlIG9uZSBvZiB0aGUgY29sbGVjdGlvbnMgaW4gdGhpcyBhY2NvdW50ICh0ZWFtKSBhbmQgcHJvamVjdC5cbiAgICAgKlxuICAgICAqIFRoZXJlIGFyZSBhdXRvbWF0aWMgbm90aWZpY2F0aW9ucyBmcm9tIEVwaWNlbnRlciBvbiB0aGlzIGNoYW5uZWwgd2hlbiBkYXRhIGlzIGNyZWF0ZWQsIHVwZGF0ZWQsIG9yIGRlbGV0ZWQgaW4gdGhpcyBjb2xsZWN0aW9uLiBTZWUgbW9yZSBvbiBbYXV0b21hdGljIG1lc3NhZ2VzIHRvIHRoZSBkYXRhIGNoYW5uZWxdKC4uLy4uLy4uL3Jlc3RfYXBpcy9tdWx0aXBsYXllci9jaGFubmVsLyNkYXRhLW1lc3NhZ2VzKS5cbiAgICAgKlxuICAgICAqICoqRXhhbXBsZSoqXG4gICAgICpcbiAgICAgKiAgICAgdmFyIGNtID0gbmV3IEYubWFuYWdlci5DaGFubmVsTWFuYWdlcigpO1xuICAgICAqICAgICB2YXIgZGMgPSBjbS5nZXREYXRhQ2hhbm5lbCgnc3VydmV5LXJlc3BvbnNlcycpO1xuICAgICAqICAgICBkYy5zdWJzY3JpYmUoJycsIGZ1bmN0aW9uKGRhdGEsIG1ldGEpIHtcbiAgICAgKiAgICAgICAgICBjb25zb2xlLmxvZyhkYXRhKTtcbiAgICAgKlxuICAgICAqICAgICAgICAgIC8vIG1ldGEuZGF0ZSBpcyB0aW1lIG9mIGNoYW5nZSxcbiAgICAgKiAgICAgICAgICAvLyBtZXRhLnN1YlR5cGUgaXMgdGhlIGtpbmQgb2YgY2hhbmdlOiBuZXcsIHVwZGF0ZSwgb3IgZGVsZXRlXG4gICAgICogICAgICAgICAgLy8gbWV0YS5wYXRoIGlzIHRoZSBmdWxsIHBhdGggdG8gdGhlIGNoYW5nZWQgZGF0YVxuICAgICAqICAgICAgICAgIGNvbnNvbGUubG9nKG1ldGEpO1xuICAgICAqICAgICB9KTtcbiAgICAgKlxuICAgICAqICoqUmV0dXJuIFZhbHVlKipcbiAgICAgKlxuICAgICAqICogKkNoYW5uZWwqIFJldHVybnMgdGhlIGNoYW5uZWwgKGFuIGluc3RhbmNlIG9mIHRoZSBbQ2hhbm5lbCBTZXJ2aWNlXSguLi9jaGFubmVsLXNlcnZpY2UvKSkuXG4gICAgICpcbiAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAqXG4gICAgICogQHBhcmFtICB7U3RyaW5nfSBgY29sbGVjdGlvbmAgTmFtZSBvZiBjb2xsZWN0aW9uIHdob3NlIGF1dG9tYXRpYyBub3RpZmljYXRpb25zIHlvdSB3YW50IHRvIHJlY2VpdmUuXG4gICAgICovXG4gICAgZ2V0RGF0YUNoYW5uZWw6IGZ1bmN0aW9uIChjb2xsZWN0aW9uKSB7XG4gICAgICAgIGlmICghY29sbGVjdGlvbikge1xuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdQbGVhc2Ugc3BlY2lmeSBhIGNvbGxlY3Rpb24gdG8gbGlzdGVuIG9uLicpO1xuICAgICAgICB9XG4gICAgICAgIHZhciBhY2NvdW50ID0gZ2V0RnJvbVNldHRpbmdzT3JTZXNzaW9uT3JFcnJvcignJywgJ2FjY291bnQnLCB0aGlzLm9wdGlvbnMpO1xuICAgICAgICB2YXIgcHJvamVjdCA9IGdldEZyb21TZXR0aW5nc09yU2Vzc2lvbk9yRXJyb3IoJycsICdwcm9qZWN0JywgdGhpcy5vcHRpb25zKTtcbiAgICAgICAgdmFyIGJhc2VUb3BpYyA9IFsnL2RhdGEnLCBhY2NvdW50LCBwcm9qZWN0LCBjb2xsZWN0aW9uXS5qb2luKCcvJyk7XG4gICAgICAgIHZhciBjaGFubmVsID0gX19zdXBlci5nZXRDaGFubmVsLmNhbGwodGhpcywgeyBiYXNlOiBiYXNlVG9waWMgfSk7XG5cbiAgICAgICAgLy9UT0RPOiBGaXggYWZ0ZXIgRXBpY2VudGVyIGJ1ZyBpcyByZXNvbHZlZFxuICAgICAgICB2YXIgb2xkc3VicyA9IGNoYW5uZWwuc3Vic2NyaWJlO1xuICAgICAgICBjaGFubmVsLnN1YnNjcmliZSA9IGZ1bmN0aW9uICh0b3BpYywgY2FsbGJhY2ssIGNvbnRleHQsIG9wdGlvbnMpIHtcbiAgICAgICAgICAgIHZhciBjYWxsYmFja1dpdGhDbGVhbkRhdGEgPSBmdW5jdGlvbiAocGF5bG9hZCkge1xuICAgICAgICAgICAgICAgIHZhciBtZXRhID0ge1xuICAgICAgICAgICAgICAgICAgICBwYXRoOiBwYXlsb2FkLmNoYW5uZWwsXG4gICAgICAgICAgICAgICAgICAgIHN1YlR5cGU6IHBheWxvYWQuZGF0YS5zdWJUeXBlLFxuICAgICAgICAgICAgICAgICAgICBkYXRlOiBwYXlsb2FkLmRhdGEuZGF0ZVxuICAgICAgICAgICAgICAgIH07XG4gICAgICAgICAgICAgICAgdmFyIGFjdHVhbERhdGEgPSBwYXlsb2FkLmRhdGEuZGF0YTtcbiAgICAgICAgICAgICAgICBpZiAoYWN0dWFsRGF0YS5kYXRhKSB7IC8vRGVsZXRlIG5vdGlmaWNhdGlvbnMgYXJlIG9uZSBkYXRhLWxldmVsIGJlaGluZCBvZiBjb3Vyc2VcbiAgICAgICAgICAgICAgICAgICAgYWN0dWFsRGF0YSA9IGFjdHVhbERhdGEuZGF0YTtcbiAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICBjYWxsYmFjay5jYWxsKGNvbnRleHQsIGFjdHVhbERhdGEsIG1ldGEpO1xuICAgICAgICAgICAgfTtcbiAgICAgICAgICAgIHJldHVybiBvbGRzdWJzLmNhbGwoY2hhbm5lbCwgdG9waWMsIGNhbGxiYWNrV2l0aENsZWFuRGF0YSwgY29udGV4dCwgb3B0aW9ucyk7XG4gICAgICAgIH07XG5cbiAgICAgICAgcmV0dXJuIGNoYW5uZWw7XG4gICAgfVxufSk7XG5cbm1vZHVsZS5leHBvcnRzID0gRXBpY2VudGVyQ2hhbm5lbE1hbmFnZXI7XG4iLCIndXNlIHN0cmljdCc7XG5cbm1vZHVsZS5leHBvcnRzID0ge1xuICAgIEVQSV9TRVNTSU9OX0tFWTogJ2VwaWNlbnRlcmpzLnNlc3Npb24nLFxuICAgIFNUUkFURUdZX1NFU1NJT05fS0VZOiAnZXBpY2VudGVyLXNjZW5hcmlvJ1xufTsiLCIvKipcbiogIyMgUnVuIE1hbmFnZXJcbipcbiogVGhlIFJ1biBNYW5hZ2VyIGdpdmVzIHlvdSBhY2Nlc3MgdG8gcnVucyBmb3IgeW91ciBwcm9qZWN0LiBUaGlzIGFsbG93cyB5b3UgdG8gcmVhZCBhbmQgdXBkYXRlIHZhcmlhYmxlcywgY2FsbCBvcGVyYXRpb25zLCBldGMuIEFkZGl0aW9uYWxseSwgdGhlIFJ1biBNYW5hZ2VyIGdpdmVzIHlvdSBjb250cm9sIG92ZXIgcnVuIGNyZWF0aW9uIGRlcGVuZGluZyBvbiBydW4gc3RhdGVzLiBTcGVjaWZpY2FsbHksIHlvdSBjYW4gc2VsZWN0IFtydW4gY3JlYXRpb24gc3RyYXRlZ2llcyAocnVsZXMpXSguLi8uLi9zdHJhdGVneS8pIGZvciB3aGljaCBydW5zIGVuZCB1c2VycyBvZiB5b3VyIHByb2plY3Qgd29yayB3aXRoIHdoZW4gdGhleSBsb2cgaW4gdG8geW91ciBwcm9qZWN0LlxuKlxuKiBUaGVyZSBhcmUgbWFueSB3YXlzIHRvIGNyZWF0ZSBuZXcgcnVucywgaW5jbHVkaW5nIHRoZSBFcGljZW50ZXIuanMgW1J1biBTZXJ2aWNlXSguLi9ydW4tYXBpLXNlcnZpY2UvKSwgdGhlIFJFU0ZUZnVsIFtSdW4gQVBJXSguLi8uLi8uLi9yZXN0X2FwaXMvYWdncmVnYXRlX3J1bl9hcGkpIGFuZCB0aGUgW01vZGVsIFJ1biBBUEldKC4uLy4uLy4uL3Jlc3RfYXBpcy9vdGhlcl9hcGlzL21vZGVsX2FwaXMvcnVuLykuIEhvd2V2ZXIsIGZvciBzb21lIHByb2plY3RzIGl0IG1ha2VzIG1vcmUgc2Vuc2UgdG8gcGljayB1cCB3aGVyZSB0aGUgdXNlciBsZWZ0IG9mZiwgdXNpbmcgYW4gZXhpc3RpbmcgcnVuLiBBbmQgaW4gc29tZSBwcm9qZWN0cywgd2hldGhlciB0byBjcmVhdGUgYSBuZXcgcnVuIG9yIHVzZSBhbiBleGlzdGluZyBvbmUgaXMgY29uZGl0aW9uYWwsIGZvciBleGFtcGxlIGJhc2VkIG9uIGNoYXJhY3RlcmlzdGljcyBvZiB0aGUgZXhpc3RpbmcgcnVuIG9yIHlvdXIgb3duIGtub3dsZWRnZSBhYm91dCB0aGUgbW9kZWwuIFRoZSBSdW4gTWFuYWdlciBwcm92aWRlcyB0aGlzIGxldmVsIG9mIGNvbnRyb2w6IHlvdXIgY2FsbCB0byBgZ2V0UnVuKClgLCByYXRoZXIgdGhhbiBhbHdheXMgcmV0dXJuaW5nIGEgbmV3IHJ1biwgcmV0dXJucyBhIHJ1biBiYXNlZCBvbiB0aGUgc3RyYXRlZ3kgeW91J3ZlIHNwZWNpZmllZC4gKE5vdGUgdGhhdCBtYW55IG9mIHRoZSBFcGljZW50ZXIgc2FtcGxlIHByb2plY3RzIHVzZSBhIFJ1biBTZXJ2aWNlIGRpcmVjdGx5LCBiZWNhdXNlIGdlbmVyYWxseSB0aGUgc2FtcGxlIHByb2plY3RzIGFyZSBwbGF5ZWQgaW4gb25lIGVuZCB1c2VyIHNlc3Npb24gYW5kIGRvbid0IGNhcmUgYWJvdXQgcnVuIHN0YXRlcyBvciBydW4gc3RyYXRlZ2llcy4pXG4qXG4qXG4qICMjIyBVc2luZyB0aGUgUnVuIE1hbmFnZXIgdG8gY3JlYXRlIGFuZCBhY2Nlc3MgcnVuc1xuKlxuKiBUbyB1c2UgdGhlIFJ1biBNYW5hZ2VyLCBpbnN0YW50aWF0ZSBpdCBieSBwYXNzaW5nIGluOlxuKlxuKiAgICogYHJ1bmA6IChyZXF1aXJlZCkgUnVuIG9iamVjdC4gTXVzdCBjb250YWluOlxuKiAgICAgICAqIGBhY2NvdW50YDogRXBpY2VudGVyIGFjY291bnQgaWQgKCoqVGVhbSBJRCoqIGZvciB0ZWFtIHByb2plY3RzLCAqKlVzZXIgSUQqKiBmb3IgcGVyc29uYWwgcHJvamVjdHMpLlxuKiAgICAgICAqIGBwcm9qZWN0YDogRXBpY2VudGVyIHByb2plY3QgaWQuXG4qICAgICAgICogYG1vZGVsYDogVGhlIG5hbWUgb2YgeW91ciBwcmltYXJ5IG1vZGVsIGZpbGUuIChTZWUgbW9yZSBvbiBbV3JpdGluZyB5b3VyIE1vZGVsXSguLi8uLi8uLi93cml0aW5nX3lvdXJfbW9kZWwvKS4pXG4qICAgICAgICogYHNjb3BlYDogKG9wdGlvbmFsKSBTY29wZSBvYmplY3QgZm9yIHRoZSBydW4sIGZvciBleGFtcGxlIGBzY29wZS5ncm91cGAgd2l0aCB2YWx1ZSBvZiB0aGUgbmFtZSBvZiB0aGUgZ3JvdXAuXG4qICAgICAgICogYHNlcnZlcmA6IChvcHRpb25hbCkgQW4gb2JqZWN0IHdpdGggb25lIGZpZWxkLCBgaG9zdGAuIFRoZSB2YWx1ZSBvZiBgaG9zdGAgaXMgdGhlIHN0cmluZyBgYXBpLmZvcmlvLmNvbWAsIHRoZSBVUkkgb2YgdGhlIEZvcmlvIHNlcnZlci4gVGhpcyBpcyBhdXRvbWF0aWNhbGx5IHNldCwgYnV0IHlvdSBjYW4gcGFzcyBpdCBleHBsaWNpdGx5IGlmIGRlc2lyZWQuIEl0IGlzIG1vc3QgY29tbW9ubHkgdXNlZCBmb3IgY2xhcml0eSB3aGVuIHlvdSBhcmUgW2hvc3RpbmcgYW4gRXBpY2VudGVyIHByb2plY3Qgb24geW91ciBvd24gc2VydmVyXSguLi8uLi8uLi9ob3dfdG8vc2VsZl9ob3N0aW5nLykuXG4qICAgICAgICogYGZpbGVzYDogKG9wdGlvbmFsKSBJZiBhbmQgb25seSBpZiB5b3UgYXJlIHVzaW5nIGEgVmVuc2ltIG1vZGVsIGFuZCB5b3UgaGF2ZSBhZGRpdGlvbmFsIGRhdGEgdG8gcGFzcyBpbiB0byB5b3VyIG1vZGVsLCB5b3UgY2FuIHBhc3MgYSBgZmlsZXNgIG9iamVjdCB3aXRoIHRoZSBuYW1lcyBvZiB0aGUgZmlsZXMsIGZvciBleGFtcGxlOiBgXCJmaWxlc1wiOiB7XCJkYXRhXCI6IFwibXlFeHRyYURhdGEueGxzXCJ9YC4gKE5vdGUgdGhhdCB5b3UnbGwgYWxzbyBuZWVkIHRvIGFkZCB0aGlzIHNhbWUgZmlsZXMgb2JqZWN0IHRvIHlvdXIgVmVuc2ltIFtjb25maWd1cmF0aW9uIGZpbGVdKC4uLy4uLy4uL21vZGVsX2NvZGUvdmVuc2ltLykuKSBTZWUgdGhlIFt1bmRlcmx5aW5nIE1vZGVsIFJ1biBBUEldKC4uLy4uLy4uL3Jlc3RfYXBpcy9vdGhlcl9hcGlzL21vZGVsX2FwaXMvcnVuLyNwb3N0LWNyZWF0aW5nLWEtbmV3LXJ1bi1mb3ItdGhpcy1wcm9qZWN0KSBmb3IgYWRkaXRpb25hbCBpbmZvcm1hdGlvbi5cbipcbiogICAqIGBzdHJhdGVneWA6IChvcHRpb25hbCkgUnVuIGNyZWF0aW9uIHN0cmF0ZWd5IGZvciB3aGVuIHRvIGNyZWF0ZSBhIG5ldyBydW4gYW5kIHdoZW4gdG8gcmV1c2UgYW4gZW5kIHVzZXIncyBleGlzdGluZyBydW4uIFNlZSBbUnVuIE1hbmFnZXIgU3RyYXRlZ2llc10oLi4vLi4vc3RyYXRlZ3kvKSBmb3IgZGV0YWlscy4gRGVmYXVsdHMgdG8gYG5ldy1pZi1pbml0aWFsaXplZGAuXG4qXG4qICAgKiBgc2Vzc2lvbktleWA6IChvcHRpb25hbCkgTmFtZSBvZiBicm93c2VyIGNvb2tpZSBpbiB3aGljaCB0byBzdG9yZSBydW4gaW5mb3JtYXRpb24sIGluY2x1ZGluZyBydW4gaWQuIE1hbnkgY29uZGl0aW9uYWwgc3RyYXRlZ2llcywgaW5jbHVkaW5nIHRoZSBwcm92aWRlZCBzdHJhdGVnaWVzLCByZWx5IG9uIHRoaXMgYnJvd3NlciBjb29raWUgdG8gc3RvcmUgdGhlIHJ1biBpZCBhbmQgaGVscCBtYWtlIHRoZSBkZWNpc2lvbiBvZiB3aGV0aGVyIHRvIGNyZWF0ZSBhIG5ldyBydW4gb3IgdXNlIGFuIGV4aXN0aW5nIG9uZS4gVGhlIG5hbWUgb2YgdGhpcyBjb29raWUgZGVmYXVsdHMgdG8gYGVwaWNlbnRlci1zY2VuYXJpb2AgYW5kIGNhbiBiZSBzZXQgd2l0aCB0aGUgYHNlc3Npb25LZXlgIHBhcmFtZXRlci5cbipcbipcbiogQWZ0ZXIgaW5zdGFudGlhdGluZyBhIFJ1biBNYW5hZ2VyLCBtYWtlIGEgY2FsbCB0byBgZ2V0UnVuKClgIHdoZW5ldmVyIHlvdSBuZWVkIHRvIGFjY2VzcyBhIHJ1biBmb3IgdGhpcyBlbmQgdXNlci4gVGhlIGBSdW5NYW5hZ2VyLnJ1bmAgY29udGFpbnMgdGhlIGluc3RhbnRpYXRlZCBbUnVuIFNlcnZpY2VdKC4uL3J1bi1hcGktc2VydmljZS8pLiBUaGUgUnVuIFNlcnZpY2UgYWxsb3dzIHlvdSB0byBhY2Nlc3MgdmFyaWFibGVzLCBjYWxsIG9wZXJhdGlvbnMsIGV0Yy5cbipcbiogKipFeGFtcGxlKipcbipcbiogICAgICAgdmFyIHJtID0gbmV3IEYubWFuYWdlci5SdW5NYW5hZ2VyKHtcbiogICAgICAgICAgIHJ1bjoge1xuKiAgICAgICAgICAgICAgIGFjY291bnQ6ICdhY21lLXNpbXVsYXRpb25zJyxcbiogICAgICAgICAgICAgICBwcm9qZWN0OiAnc3VwcGx5LWNoYWluLWdhbWUnLFxuKiAgICAgICAgICAgICAgIG1vZGVsOiAnc3VwcGx5LWNoYWluLW1vZGVsLmpsJyxcbiogICAgICAgICAgICAgICBzZXJ2ZXI6IHsgaG9zdDogJ2FwaS5mb3Jpby5jb20nIH1cbiogICAgICAgICAgIH0sXG4qICAgICAgICAgICBzdHJhdGVneTogJ2Fsd2F5cy1uZXcnLFxuKiAgICAgICAgICAgc2Vzc2lvbktleTogJ2VwaWNlbnRlci1zZXNzaW9uJ1xuKiAgICAgICB9KTtcbiogICAgICAgcm0uZ2V0UnVuKClcbiogICAgICAgICAgIC50aGVuKGZ1bmN0aW9uKHJ1bikge1xuKiAgICAgICAgICAgICAgIC8vIHRoZSByZXR1cm4gdmFsdWUgb2YgZ2V0UnVuKCkgaXMgYSBydW4gb2JqZWN0XG4qICAgICAgICAgICAgICAgdmFyIHRoaXNSdW5JZCA9IHJ1bi5pZDtcbiogICAgICAgICAgICAgICAvLyB0aGUgUnVuTWFuYWdlci5ydW4gYWxzbyBjb250YWlucyB0aGUgaW5zdGFudGlhdGVkIFJ1biBTZXJ2aWNlLFxuKiAgICAgICAgICAgICAgIC8vIHNvIGFueSBSdW4gU2VydmljZSBtZXRob2QgaXMgdmFsaWQgaGVyZVxuKiAgICAgICAgICAgICAgIHJtLnJ1bi5kbygncnVuTW9kZWwnKTtcbiogICAgICAgfSlcbipcbiovXG5cbid1c2Ugc3RyaWN0JztcbnZhciBzdHJhdGVnaWVzTWFwID0gcmVxdWlyZSgnLi9ydW4tc3RyYXRlZ2llcy9zdHJhdGVnaWVzLW1hcCcpO1xudmFyIHNwZWNpYWxPcGVyYXRpb25zID0gcmVxdWlyZSgnLi9zcGVjaWFsLW9wZXJhdGlvbnMnKTtcbnZhciBSdW5TZXJ2aWNlID0gcmVxdWlyZSgnLi4vc2VydmljZS9ydW4tYXBpLXNlcnZpY2UnKTtcblxuXG5mdW5jdGlvbiBwYXRjaFJ1blNlcnZpY2Uoc2VydmljZSwgbWFuYWdlcikge1xuICAgIGlmIChzZXJ2aWNlLnBhdGNoZWQpIHtcbiAgICAgICAgcmV0dXJuIHNlcnZpY2U7XG4gICAgfVxuXG4gICAgdmFyIG9yaWcgPSBzZXJ2aWNlLmRvO1xuICAgIHNlcnZpY2UuZG8gPSBmdW5jdGlvbiAob3BlcmF0aW9uLCBwYXJhbXMsIG9wdGlvbnMpIHtcbiAgICAgICAgdmFyIHJlc2VydmVkT3BzID0gT2JqZWN0LmtleXMoc3BlY2lhbE9wZXJhdGlvbnMpO1xuICAgICAgICBpZiAocmVzZXJ2ZWRPcHMuaW5kZXhPZihvcGVyYXRpb24pID09PSAtMSkge1xuICAgICAgICAgICAgcmV0dXJuIG9yaWcuYXBwbHkoc2VydmljZSwgYXJndW1lbnRzKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIHJldHVybiBzcGVjaWFsT3BlcmF0aW9uc1tvcGVyYXRpb25dLmNhbGwoc2VydmljZSwgcGFyYW1zLCBvcHRpb25zLCBtYW5hZ2VyKTtcbiAgICAgICAgfVxuICAgIH07XG5cbiAgICBzZXJ2aWNlLnBhdGNoZWQgPSB0cnVlO1xuXG4gICAgcmV0dXJuIHNlcnZpY2U7XG59XG5cblxuXG52YXIgZGVmYXVsdHMgPSB7XG4gICAgLyoqXG4gICAgICogUnVuIGNyZWF0aW9uIHN0cmF0ZWd5IGZvciB3aGVuIHRvIGNyZWF0ZSBhIG5ldyBydW4gYW5kIHdoZW4gdG8gcmV1c2UgYW4gZW5kIHVzZXIncyBleGlzdGluZyBydW4uIFNlZSBbUnVuIE1hbmFnZXIgU3RyYXRlZ2llc10oLi4vLi4vc3RyYXRlZ3kvKSBmb3IgZGV0YWlscy4gRGVmYXVsdHMgdG8gYG5ldy1pZi1pbml0aWFsaXplZGAuXG4gICAgICogQHR5cGUge1N0cmluZ31cbiAgICAgKi9cblxuICAgIHN0cmF0ZWd5OiAnbmV3LWlmLWluaXRpYWxpemVkJ1xufTtcblxuZnVuY3Rpb24gUnVuTWFuYWdlcihvcHRpb25zKSB7XG4gICAgdGhpcy5vcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sIGRlZmF1bHRzLCBvcHRpb25zKTtcblxuICAgIGlmICh0aGlzLm9wdGlvbnMucnVuIGluc3RhbmNlb2YgUnVuU2VydmljZSkge1xuICAgICAgICB0aGlzLnJ1biA9IHRoaXMub3B0aW9ucy5ydW47XG4gICAgfSBlbHNlIHtcbiAgICAgICAgdGhpcy5ydW4gPSBuZXcgUnVuU2VydmljZSh0aGlzLm9wdGlvbnMucnVuKTtcbiAgICB9XG5cbiAgICBwYXRjaFJ1blNlcnZpY2UodGhpcy5ydW4sIHRoaXMpO1xuXG4gICAgdmFyIFN0cmF0ZWd5Q3RvciA9IHR5cGVvZiB0aGlzLm9wdGlvbnMuc3RyYXRlZ3kgPT09ICdmdW5jdGlvbicgPyB0aGlzLm9wdGlvbnMuc3RyYXRlZ3kgOiBzdHJhdGVnaWVzTWFwW3RoaXMub3B0aW9ucy5zdHJhdGVneV07XG5cbiAgICBpZiAoIVN0cmF0ZWd5Q3Rvcikge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ1NwZWNpZmllZCBydW4gY3JlYXRpb24gc3RyYXRlZ3kgd2FzIGludmFsaWQ6JywgdGhpcy5vcHRpb25zLnN0cmF0ZWd5KTtcbiAgICB9XG5cbiAgICB0aGlzLnN0cmF0ZWd5ID0gbmV3IFN0cmF0ZWd5Q3Rvcih0aGlzLnJ1biwgdGhpcy5vcHRpb25zKTtcbn1cblxuUnVuTWFuYWdlci5wcm90b3R5cGUgPSB7XG4gICAgLyoqXG4gICAgICogUmV0dXJucyB0aGUgcnVuIG9iamVjdCBmb3IgYSAnZ29vZCcgcnVuLlxuICAgICAqXG4gICAgICogQSBnb29kIHJ1biBpcyBkZWZpbmVkIGJ5IHRoZSBzdHJhdGVneS4gRm9yIGV4YW1wbGUsIGlmIHRoZSBzdHJhdGVneSBpcyBgYWx3YXlzLW5ld2AsIHRoZSBjYWxsXG4gICAgICogdG8gYGdldFJ1bigpYCBhbHdheXMgcmV0dXJucyBhIG5ld2x5IGNyZWF0ZWQgcnVuOyBpZiB0aGUgc3RyYXRlZ3kgaXMgYG5ldy1pZi1wZXJzaXN0ZWRgLFxuICAgICAqIGBnZXRSdW4oKWAgY3JlYXRlcyBhIG5ldyBydW4gaWYgdGhlIHByZXZpb3VzIHJ1biBpcyBpbiBhIHBlcnNpc3RlZCBzdGF0ZSwgb3RoZXJ3aXNlXG4gICAgICogaXQgcmV0dXJucyB0aGUgcHJldmlvdXMgcnVuLiBTZWUgW1J1biBNYW5hZ2VyIFN0cmF0ZWdpZXNdKC4uLy4uL3N0cmF0ZWd5LykgZm9yIG1vcmUgb24gc3RyYXRlZ2llcy5cbiAgICAgKlxuICAgICAqICAqKkV4YW1wbGUqKlxuICAgICAqXG4gICAgICogICAgICBybS5nZXRSdW4oKS50aGVuKGZ1bmN0aW9uIChydW4pIHtcbiAgICAgKiAgICAgICAgICAvLyB1c2UgdGhlIHJ1biBvYmplY3RcbiAgICAgKiAgICAgICAgICB2YXIgdGhpc1J1bklkID0gcnVuLmlkO1xuICAgICAqXG4gICAgICogICAgICAgICAgLy8gdXNlIHRoZSBSdW4gU2VydmljZSBvYmplY3RcbiAgICAgKiAgICAgICAgICBybS5ydW4uZG8oJ3J1bk1vZGVsJyk7XG4gICAgICogICAgICB9KTtcbiAgICAgKlxuICAgICAqIEByZXR1cm4geyRwcm9taXNlfSBQcm9taXNlIHRvIGNvbXBsZXRlIHRoZSBjYWxsLlxuICAgICAqL1xuICAgIGdldFJ1bjogZnVuY3Rpb24gKCkge1xuICAgICAgICByZXR1cm4gdGhpcy5zdHJhdGVneVxuICAgICAgICAgICAgICAgIC5nZXRSdW4oKTtcbiAgICB9LFxuXG4gICAgLyoqXG4gICAgICogUmV0dXJucyB0aGUgcnVuIG9iamVjdCBmb3IgYSBuZXcgcnVuLCByZWdhcmRsZXNzIG9mIHN0cmF0ZWd5OiBmb3JjZSBjcmVhdGlvbiBvZiBhIG5ldyBydW4uXG4gICAgICpcbiAgICAgKiAgKipFeGFtcGxlKipcbiAgICAgKlxuICAgICAqICAgICAgcm0ucmVzZXQoKS50aGVuKGZ1bmN0aW9uIChydW4pIHtcbiAgICAgKiAgICAgICAgICAvLyB1c2UgdGhlIChuZXcpIHJ1biBvYmplY3RcbiAgICAgKiAgICAgICAgICB2YXIgdGhpc1J1bklkID0gcnVuLmlkO1xuICAgICAqXG4gICAgICogICAgICAgICAgLy8gdXNlIHRoZSBSdW4gU2VydmljZSBvYmplY3RcbiAgICAgKiAgICAgICAgICBybS5ydW4uZG8oJ3J1bk1vZGVsJyk7XG4gICAgICogICAgICB9KTtcbiAgICAgKlxuICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICogQHBhcmFtIHtPYmplY3R9IGBydW5TZXJ2aWNlT3B0aW9uc2AgVGhlIG9wdGlvbnMgb2JqZWN0IHRvIGNvbmZpZ3VyZSB0aGUgUnVuIFNlcnZpY2UuIFNlZSBbUnVuIEFQSSBTZXJ2aWNlXSguLi9ydW4tYXBpLXNlcnZpY2UvKSBmb3IgbW9yZS5cbiAgICAgKi9cbiAgICByZXNldDogZnVuY3Rpb24gKHJ1blNlcnZpY2VPcHRpb25zKSB7XG4gICAgICAgIHJldHVybiB0aGlzLnN0cmF0ZWd5LnJlc2V0KHJ1blNlcnZpY2VPcHRpb25zKTtcbiAgICB9XG59O1xuXG5tb2R1bGUuZXhwb3J0cyA9IFJ1bk1hbmFnZXI7XG4iLCIndXNlIHN0cmljdCc7XG5cbnZhciBjbGFzc0Zyb20gPSByZXF1aXJlKCcuLi8uLi91dGlsL2luaGVyaXQnKTtcbnZhciBDb25kaXRpb25hbFN0cmF0ZWd5ID0gcmVxdWlyZSgnLi9jb25kaXRpb25hbC1jcmVhdGlvbi1zdHJhdGVneScpO1xuXG52YXIgX19zdXBlciA9IENvbmRpdGlvbmFsU3RyYXRlZ3kucHJvdG90eXBlO1xuXG52YXIgU3RyYXRlZ3kgPSBjbGFzc0Zyb20oQ29uZGl0aW9uYWxTdHJhdGVneSwge1xuICAgIGNvbnN0cnVjdG9yOiBmdW5jdGlvbiAocnVuU2VydmljZSwgb3B0aW9ucykge1xuICAgICAgICBfX3N1cGVyLmNvbnN0cnVjdG9yLmNhbGwodGhpcywgcnVuU2VydmljZSwgdGhpcy5jcmVhdGVJZiwgb3B0aW9ucyk7XG4gICAgfSxcblxuICAgIGNyZWF0ZUlmOiBmdW5jdGlvbiAocnVuLCBoZWFkZXJzKSB7XG4gICAgICAgIC8vIGFsd2F5cyBjcmVhdGUgYSBuZXcgcnVuIVxuICAgICAgICByZXR1cm4gdHJ1ZTtcbiAgICB9XG59KTtcblxubW9kdWxlLmV4cG9ydHMgPSBTdHJhdGVneTtcbiIsIid1c2Ugc3RyaWN0JztcblxudmFyIG1ha2VTZXEgPSByZXF1aXJlKCcuLi8uLi91dGlsL21ha2Utc2VxdWVuY2UnKTtcbnZhciBCYXNlID0gcmVxdWlyZSgnLi9pZGVudGl0eS1zdHJhdGVneScpO1xudmFyIFNlc3Npb25TdG9yZSA9IHJlcXVpcmUoJy4uLy4uL3N0b3JlL3N0b3JlLWZhY3RvcnknKTtcbnZhciBjbGFzc0Zyb20gPSByZXF1aXJlKCcuLi8uLi91dGlsL2luaGVyaXQnKTtcbnZhciBVcmxTZXJ2aWNlID0gcmVxdWlyZSgnLi4vLi4vc2VydmljZS91cmwtY29uZmlnLXNlcnZpY2UnKTtcbnZhciBBdXRoTWFuYWdlciA9IHJlcXVpcmUoJy4uL2F1dGgtbWFuYWdlcicpO1xuXG52YXIgc2Vzc2lvblN0b3JlID0gbmV3IFNlc3Npb25TdG9yZSh7fSk7XG52YXIgdXJsU2VydmljZSA9IG5ldyBVcmxTZXJ2aWNlKCk7XG52YXIga2V5TmFtZXMgPSByZXF1aXJlKCcuLi9rZXktbmFtZXMnKTtcblxudmFyIGRlZmF1bHRzID0ge1xuICAgIHNlc3Npb25LZXk6IGtleU5hbWVzLlNUUkFURUdZX1NFU1NJT05fS0VZLFxuICAgIHBhdGg6ICcnXG59O1xuXG5mdW5jdGlvbiBzZXRSdW5JblNlc3Npb24oc2Vzc2lvbktleSwgcnVuLCBwYXRoKSB7XG4gICAgaWYgKCFwYXRoKSB7XG4gICAgICAgIGlmICghdXJsU2VydmljZS5pc0xvY2FsaG9zdCgpKSB7XG4gICAgICAgICAgICBwYXRoID0gJy8nICsgW3VybFNlcnZpY2UuYXBwUGF0aCwgdXJsU2VydmljZS5hY2NvdW50UGF0aCwgdXJsU2VydmljZS5wcm9qZWN0UGF0aF0uam9pbignLycpO1xuICAgICAgICAgICAgLy8gbWFrZSBzdXJlIHdlIGRvbid0IGdldCBjb25zZWN1dGVpdmUgJy8nIHNvIHdlIGhhdmUgYSB2YWxpZCBwYXRoIGZvciB0aGUgc2Vzc2lvblxuICAgICAgICAgICAgcGF0aCA9IHBhdGgucmVwbGFjZSgvXFwvezIsfS9nLCcvJyk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICBwYXRoID0gJyc7XG4gICAgICAgIH1cbiAgICB9XG4gICAgLy8gc2V0IHRoZSBzZWVzaW9uS2V5IGZvciB0aGUgcnVuXG4gICAgc2Vzc2lvblN0b3JlLnNldChzZXNzaW9uS2V5LCBKU09OLnN0cmluZ2lmeSh7IHJ1bklkOiBydW4uaWQgfSksIHsgcm9vdDogcGF0aCB9KTtcbn1cblxuLyoqXG4qIENvbmRpdGlvbmFsIENyZWF0aW9uIFN0cmF0ZWd5XG4qIFRoaXMgc3RyYXRlZ3kgd2lsbCB0cnkgdG8gZ2V0IHRoZSBydW4gc3RvcmVkIGluIHRoZSBjb29raWUgYW5kXG4qIGV2YWx1YXRlIGlmIG5lZWRzIHRvIGNyZWF0ZSBhIG5ldyBydW4gYnkgY2FsbGluZyB0aGUgJ2NvbmRpdGlvbicgZnVuY3Rpb25cbiovXG5cbi8qIGpzaGludCBlcW51bGw6IHRydWUgKi9cbnZhciBTdHJhdGVneSA9IGNsYXNzRnJvbShCYXNlLCB7XG4gICAgY29uc3RydWN0b3I6IGZ1bmN0aW9uIFN0cmF0ZWd5KHJ1blNlcnZpY2UsIGNvbmRpdGlvbiwgb3B0aW9ucykge1xuXG4gICAgICAgIGlmIChjb25kaXRpb24gPT0gbnVsbCkge1xuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdDb25kaXRpb25hbCBzdHJhdGVneSBuZWVkcyBhIGNvbmRpdGlvbiB0byBjcmVhdGV0ZSBhIHJ1bicpO1xuICAgICAgICB9XG5cbiAgICAgICAgdGhpcy5fYXV0aCA9IG5ldyBBdXRoTWFuYWdlcigpO1xuICAgICAgICB0aGlzLnJ1biA9IG1ha2VTZXEocnVuU2VydmljZSk7XG4gICAgICAgIHRoaXMuY29uZGl0aW9uID0gdHlwZW9mIGNvbmRpdGlvbiAhPT0gJ2Z1bmN0aW9uJyA/IGZ1bmN0aW9uICgpIHsgcmV0dXJuIGNvbmRpdGlvbjsgfSA6IGNvbmRpdGlvbjtcbiAgICAgICAgdGhpcy5vcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sIGRlZmF1bHRzLCBvcHRpb25zKTtcbiAgICAgICAgdGhpcy5ydW5PcHRpb25zID0gdGhpcy5vcHRpb25zLnJ1bjtcbiAgICB9LFxuXG4gICAgcnVuT3B0aW9uc1dpdGhTY29wZTogZnVuY3Rpb24gKCkge1xuICAgICAgICB2YXIgdXNlclNlc3Npb24gPSB0aGlzLl9hdXRoLmdldEN1cnJlbnRVc2VyU2Vzc2lvbkluZm8oKTtcbiAgICAgICAgcmV0dXJuICQuZXh0ZW5kKHtcbiAgICAgICAgICAgIHNjb3BlOiB7IGdyb3VwOiB1c2VyU2Vzc2lvbi5ncm91cE5hbWUgfVxuICAgICAgICB9LCB0aGlzLnJ1bk9wdGlvbnMpO1xuICAgIH0sXG5cbiAgICByZXNldDogZnVuY3Rpb24gKHJ1blNlcnZpY2VPcHRpb25zKSB7XG4gICAgICAgIHZhciBfdGhpcyA9IHRoaXM7XG4gICAgICAgIHZhciBvcHQgPSB0aGlzLnJ1bk9wdGlvbnNXaXRoU2NvcGUoKTtcblxuICAgICAgICByZXR1cm4gdGhpcy5ydW5cbiAgICAgICAgICAgICAgICAuY3JlYXRlKG9wdCwgcnVuU2VydmljZU9wdGlvbnMpXG4gICAgICAgICAgICAudGhlbihmdW5jdGlvbiAocnVuKSB7XG4gICAgICAgICAgICAgICAgc2V0UnVuSW5TZXNzaW9uKF90aGlzLm9wdGlvbnMuc2Vzc2lvbktleSwgcnVuLCBfdGhpcy5vcHRpb25zLnBhdGgpO1xuICAgICAgICAgICAgICAgIHJ1bi5mcmVzaGx5Q3JlYXRlZCA9IHRydWU7XG4gICAgICAgICAgICAgICAgcmV0dXJuIHJ1bjtcbiAgICAgICAgICAgIH0pXG4gICAgICAgICAgICAuc3RhcnQoKTtcbiAgICB9LFxuXG4gICAgZ2V0UnVuOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHZhciBydW5TZXNzaW9uID0gSlNPTi5wYXJzZShzZXNzaW9uU3RvcmUuZ2V0KHRoaXMub3B0aW9ucy5zZXNzaW9uS2V5KSk7XG5cbiAgICAgICAgaWYgKHJ1blNlc3Npb24gJiYgcnVuU2Vzc2lvbi5ydW5JZCkge1xuICAgICAgICAgICAgcmV0dXJuIHRoaXMuX2xvYWRBbmRDaGVjayhydW5TZXNzaW9uKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIHJldHVybiB0aGlzLnJlc2V0KCk7XG4gICAgICAgIH1cbiAgICB9LFxuXG4gICAgX2xvYWRBbmRDaGVjazogZnVuY3Rpb24gKHJ1blNlc3Npb24pIHtcbiAgICAgICAgdmFyIHNob3VsZENyZWF0ZSA9IGZhbHNlO1xuICAgICAgICB2YXIgX3RoaXMgPSB0aGlzO1xuXG4gICAgICAgIHJldHVybiB0aGlzLnJ1blxuICAgICAgICAgICAgLmxvYWQocnVuU2Vzc2lvbi5ydW5JZCwgbnVsbCwge1xuICAgICAgICAgICAgICAgIHN1Y2Nlc3M6IGZ1bmN0aW9uIChydW4sIG1zZywgaGVhZGVycykge1xuICAgICAgICAgICAgICAgICAgICBzaG91bGRDcmVhdGUgPSBfdGhpcy5jb25kaXRpb24uY2FsbChfdGhpcywgcnVuLCBoZWFkZXJzKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9KVxuICAgICAgICAgICAgLnRoZW4oZnVuY3Rpb24gKHJ1bikge1xuICAgICAgICAgICAgICAgIGlmIChzaG91bGRDcmVhdGUpIHtcbiAgICAgICAgICAgICAgICAgICAgdmFyIG9wdCA9IF90aGlzLnJ1bk9wdGlvbnNXaXRoU2NvcGUoKTtcbiAgICAgICAgICAgICAgICAgICAgLy8gd2UgbmVlZCB0byBkbyB0aGlzLCBvbiB0aGUgb3JpZ2luYWwgcnVuU2VydmljZSAoaWUgbm90IHNlcXVlbmNpYWxpemVkKVxuICAgICAgICAgICAgICAgICAgICAvLyBzbyB3ZSBkb24ndCBnZXQgaW4gdGhlIG1pZGRsZSBvZiB0aGUgcXVldWVcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIF90aGlzLnJ1bi5vcmlnaW5hbC5jcmVhdGUob3B0KVxuICAgICAgICAgICAgICAgICAgICAudGhlbihmdW5jdGlvbiAocnVuKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBzZXRSdW5JblNlc3Npb24oX3RoaXMub3B0aW9ucy5zZXNzaW9uS2V5LCBydW4pO1xuICAgICAgICAgICAgICAgICAgICAgICAgcnVuLmZyZXNobHlDcmVhdGVkID0gdHJ1ZTtcbiAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybiBydW47XG4gICAgICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgIHJldHVybiBydW47XG4gICAgICAgICAgICB9KVxuICAgICAgICAgICAgLnN0YXJ0KCk7XG4gICAgfVxufSk7XG5cbm1vZHVsZS5leHBvcnRzID0gU3RyYXRlZ3k7XG4iLCIndXNlIHN0cmljdCc7XG5cbnZhciBjbGFzc0Zyb20gPSByZXF1aXJlKCcuLi8uLi91dGlsL2luaGVyaXQnKTtcbnZhciBCYXNlID0ge307XG5cbi8vIEludGVyZmFjZSB0aGF0IGFsbCBzdHJhdGVnaWVzIG5lZWQgdG8gaW1wbGVtZW50XG5tb2R1bGUuZXhwb3J0cyA9IGNsYXNzRnJvbShCYXNlLCB7XG4gICAgY29uc3RydWN0b3I6IGZ1bmN0aW9uIChydW5TZXJ2aWNlLCBvcHRpb25zKSB7XG4gICAgICAgIHRoaXMucnVuU2VydmljZSAgPSBydW5TZXJ2aWNlO1xuICAgIH0sXG5cbiAgICByZXNldDogZnVuY3Rpb24gKCkge1xuICAgICAgICAvLyByZXR1cm4gYSBuZXdseSBjcmVhdGVkIHJ1blxuICAgICAgICByZXR1cm4gJC5EZWZlcnJlZCgpLnJlc29sdmUoKS5wcm9taXNlKCk7XG4gICAgfSxcblxuICAgIGdldFJ1bjogZnVuY3Rpb24gKCkge1xuICAgICAgICAvLyByZXR1cm4gYSB1c2FibGUgcnVuXG4gICAgICAgIHJldHVybiAkLkRlZmVycmVkKCkucmVzb2x2ZSh0aGlzLnJ1blNlcnZpY2UpLnByb21pc2UoKTtcbiAgICB9XG59KTtcbiIsIid1c2Ugc3RyaWN0JztcblxudmFyIGNsYXNzRnJvbSA9IHJlcXVpcmUoJy4uLy4uL3V0aWwvaW5oZXJpdCcpO1xuXG52YXIgSWRlbnRpdHlTdHJhdGVneSA9IHJlcXVpcmUoJy4vaWRlbnRpdHktc3RyYXRlZ3knKTtcbnZhciBXb3JsZEFwaUFkYXB0ZXIgPSByZXF1aXJlKCcuLi8uLi9zZXJ2aWNlL3dvcmxkLWFwaS1hZGFwdGVyJyk7XG52YXIgQXV0aE1hbmFnZXIgPSByZXF1aXJlKCcuLi9hdXRoLW1hbmFnZXInKTtcblxudmFyIGRlZmF1bHRzID0ge1xuICAgIHN0b3JlOiB7XG4gICAgICAgIHN5bmNocm9ub3VzOiB0cnVlXG4gICAgfVxufTtcblxudmFyIFN0cmF0ZWd5ID0gY2xhc3NGcm9tKElkZW50aXR5U3RyYXRlZ3ksIHtcblxuICAgIGNvbnN0cnVjdG9yOiBmdW5jdGlvbiAocnVuU2VydmljZSwgb3B0aW9ucykge1xuICAgICAgICB0aGlzLnJ1blNlcnZpY2UgPSBydW5TZXJ2aWNlO1xuICAgICAgICB0aGlzLm9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSwgZGVmYXVsdHMsIG9wdGlvbnMpO1xuICAgICAgICB0aGlzLl9hdXRoID0gbmV3IEF1dGhNYW5hZ2VyKCk7XG4gICAgICAgIHRoaXMuX2xvYWRSdW4gPSB0aGlzLl9sb2FkUnVuLmJpbmQodGhpcyk7XG4gICAgICAgIHRoaXMud29ybGRBcGkgPSBuZXcgV29ybGRBcGlBZGFwdGVyKHRoaXMub3B0aW9ucy5ydW4pO1xuICAgIH0sXG5cbiAgICByZXNldDogZnVuY3Rpb24gKCkge1xuICAgICAgICB2YXIgc2Vzc2lvbiA9IHRoaXMuX2F1dGguZ2V0Q3VycmVudFVzZXJTZXNzaW9uSW5mbygpO1xuICAgICAgICB2YXIgY3VyVXNlcklkID0gc2Vzc2lvbi51c2VySWQ7XG4gICAgICAgIHZhciBjdXJHcm91cE5hbWUgPSBzZXNzaW9uLmdyb3VwTmFtZTtcblxuICAgICAgICByZXR1cm4gdGhpcy53b3JsZEFwaVxuICAgICAgICAgICAgLmdldEN1cnJlbnRXb3JsZEZvclVzZXIoY3VyVXNlcklkLCBjdXJHcm91cE5hbWUpXG4gICAgICAgICAgICAudGhlbihmdW5jdGlvbiAod29ybGQpIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gdGhpcy53b3JsZEFwaS5uZXdSdW5Gb3JXb3JsZCh3b3JsZC5pZCk7XG4gICAgICAgICAgICB9LmJpbmQodGhpcykpO1xuICAgIH0sXG5cbiAgICBnZXRSdW46IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgdmFyIHNlc3Npb24gPSB0aGlzLl9hdXRoLmdldEN1cnJlbnRVc2VyU2Vzc2lvbkluZm8oKTtcbiAgICAgICAgdmFyIGN1clVzZXJJZCA9IHNlc3Npb24udXNlcklkO1xuICAgICAgICB2YXIgY3VyR3JvdXBOYW1lID0gc2Vzc2lvbi5ncm91cE5hbWU7XG4gICAgICAgIHZhciB3b3JsZEFwaSA9IHRoaXMud29ybGRBcGk7XG4gICAgICAgIHZhciBtb2RlbCA9IHRoaXMub3B0aW9ucy5tb2RlbDtcbiAgICAgICAgdmFyIF90aGlzID0gdGhpcztcbiAgICAgICAgdmFyIGR0ZCA9ICQuRGVmZXJyZWQoKTtcblxuICAgICAgICBpZiAoIWN1clVzZXJJZCkge1xuICAgICAgICAgICAgcmV0dXJuIGR0ZC5yZWplY3QoeyBzdGF0dXNDb2RlOiA0MDAsIGVycm9yOiAnV2UgbmVlZCBhbiBhdXRoZW50aWNhdGVkIHVzZXIgdG8gam9pbiBhIG11bHRpcGxheWVyIHdvcmxkLiAoRVJSOiBubyB1c2VySWQgaW4gc2Vzc2lvbiknIH0sIHNlc3Npb24pLnByb21pc2UoKTtcbiAgICAgICAgfVxuXG4gICAgICAgIHZhciBsb2FkUnVuRnJvbVdvcmxkID0gZnVuY3Rpb24gKHdvcmxkKSB7XG4gICAgICAgICAgICBpZiAoIXdvcmxkKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIGR0ZC5yZWplY3QoeyBzdGF0dXNDb2RlOiA0MDQsIGVycm9yOiAnVGhlIHVzZXIgaXMgbm90IGluIGFueSB3b3JsZC4nIH0sIHsgb3B0aW9uczogdGhpcy5vcHRpb25zLCBzZXNzaW9uOiBzZXNzaW9uIH0pO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICByZXR1cm4gd29ybGRBcGkuZ2V0Q3VycmVudFJ1bklkKHsgbW9kZWw6IG1vZGVsLCBmaWx0ZXI6IHdvcmxkLmlkIH0pXG4gICAgICAgICAgICAgICAgLnRoZW4oX3RoaXMuX2xvYWRSdW4pXG4gICAgICAgICAgICAgICAgLnRoZW4oZHRkLnJlc29sdmUpXG4gICAgICAgICAgICAgICAgLmZhaWwoZHRkLnJlamVjdCk7XG4gICAgICAgIH07XG5cbiAgICAgICAgdmFyIHNlcnZlckVycm9yID0gZnVuY3Rpb24gKGVycm9yKSB7XG4gICAgICAgICAgICAvLyBpcyB0aGlzIHBvc3NpYmxlP1xuICAgICAgICAgICAgZHRkLnJlamVjdChlcnJvciwgc2Vzc2lvbiwgdGhpcy5vcHRpb25zKTtcbiAgICAgICAgfTtcblxuICAgICAgICB0aGlzLndvcmxkQXBpXG4gICAgICAgICAgICAuZ2V0Q3VycmVudFdvcmxkRm9yVXNlcihjdXJVc2VySWQsIGN1ckdyb3VwTmFtZSlcbiAgICAgICAgICAgIC50aGVuKGxvYWRSdW5Gcm9tV29ybGQpXG4gICAgICAgICAgICAuZmFpbChzZXJ2ZXJFcnJvcik7XG5cbiAgICAgICAgcmV0dXJuIGR0ZC5wcm9taXNlKCk7XG4gICAgfSxcblxuICAgIF9sb2FkUnVuOiBmdW5jdGlvbiAoaWQsIG9wdGlvbnMpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMucnVuU2VydmljZS5sb2FkKGlkLCBudWxsLCBvcHRpb25zKTtcbiAgICB9XG59KTtcblxubW9kdWxlLmV4cG9ydHMgPSBTdHJhdGVneTtcbiIsIid1c2Ugc3RyaWN0JztcbnZhciBjbGFzc0Zyb20gPSByZXF1aXJlKCcuLi8uLi91dGlsL2luaGVyaXQnKTtcbnZhciBDb25kaXRpb25hbFN0cmF0ZWd5ID0gcmVxdWlyZSgnLi9jb25kaXRpb25hbC1jcmVhdGlvbi1zdHJhdGVneScpO1xuXG52YXIgX19zdXBlciA9IENvbmRpdGlvbmFsU3RyYXRlZ3kucHJvdG90eXBlO1xuXG52YXIgU3RyYXRlZ3kgPSBjbGFzc0Zyb20oQ29uZGl0aW9uYWxTdHJhdGVneSwge1xuICAgIGNvbnN0cnVjdG9yOiBmdW5jdGlvbiAocnVuU2VydmljZSwgb3B0aW9ucykge1xuICAgICAgICBfX3N1cGVyLmNvbnN0cnVjdG9yLmNhbGwodGhpcywgcnVuU2VydmljZSwgdGhpcy5jcmVhdGVJZiwgb3B0aW9ucyk7XG4gICAgfSxcblxuICAgIGNyZWF0ZUlmOiBmdW5jdGlvbiAocnVuLCBoZWFkZXJzKSB7XG4gICAgICAgIHJldHVybiBoZWFkZXJzLmdldFJlc3BvbnNlSGVhZGVyKCdwcmFnbWEnKSA9PT0gJ3BlcnNpc3RlbnQnIHx8IHJ1bi5pbml0aWFsaXplZDtcbiAgICB9XG59KTtcblxubW9kdWxlLmV4cG9ydHMgPSBTdHJhdGVneTtcbiIsIid1c2Ugc3RyaWN0JztcblxudmFyIGNsYXNzRnJvbSA9IHJlcXVpcmUoJy4uLy4uL3V0aWwvaW5oZXJpdCcpO1xudmFyIENvbmRpdGlvbmFsU3RyYXRlZ3kgPSByZXF1aXJlKCcuL2NvbmRpdGlvbmFsLWNyZWF0aW9uLXN0cmF0ZWd5Jyk7XG5cbnZhciBfX3N1cGVyID0gQ29uZGl0aW9uYWxTdHJhdGVneS5wcm90b3R5cGU7XG5cbi8qXG4qICBjcmVhdGUgYSBuZXcgcnVuIG9ubHkgaWYgbm90aGluZyBpcyBzdG9yZWQgaW4gdGhlIGNvb2tpZVxuKiAgdGhpcyBpcyB1c2VmdWwgZm9yIGJhc2VSdW5zLlxuKi9cbnZhciBTdHJhdGVneSA9IGNsYXNzRnJvbShDb25kaXRpb25hbFN0cmF0ZWd5LCB7XG4gICAgY29uc3RydWN0b3I6IGZ1bmN0aW9uIChydW5TZXJ2aWNlLCBvcHRpb25zKSB7XG4gICAgICAgIF9fc3VwZXIuY29uc3RydWN0b3IuY2FsbCh0aGlzLCBydW5TZXJ2aWNlLCB0aGlzLmNyZWF0ZUlmLCBvcHRpb25zKTtcbiAgICB9LFxuXG4gICAgY3JlYXRlSWY6IGZ1bmN0aW9uIChydW4sIGhlYWRlcnMpIHtcbiAgICAgICAgLy8gaWYgd2UgYXJlIGhlcmUsIGl0IG1lYW5zIHRoYXQgdGhlIHJ1biBleGlzdHMuLi4gc28gd2UgZG9uJ3QgbmVlZCBhIG5ldyBvbmVcbiAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgIH1cbn0pO1xuXG5tb2R1bGUuZXhwb3J0cyA9IFN0cmF0ZWd5O1xuIiwiJ3VzZSBzdHJpY3QnO1xudmFyIGNsYXNzRnJvbSA9IHJlcXVpcmUoJy4uLy4uL3V0aWwvaW5oZXJpdCcpO1xudmFyIENvbmRpdGlvbmFsU3RyYXRlZ3kgPSByZXF1aXJlKCcuL2NvbmRpdGlvbmFsLWNyZWF0aW9uLXN0cmF0ZWd5Jyk7XG5cbnZhciBfX3N1cGVyID0gQ29uZGl0aW9uYWxTdHJhdGVneS5wcm90b3R5cGU7XG5cbnZhciBTdHJhdGVneSA9IGNsYXNzRnJvbShDb25kaXRpb25hbFN0cmF0ZWd5LCB7XG4gICAgY29uc3RydWN0b3I6IGZ1bmN0aW9uIChydW5TZXJ2aWNlLCBvcHRpb25zKSB7XG4gICAgICAgIF9fc3VwZXIuY29uc3RydWN0b3IuY2FsbCh0aGlzLCBydW5TZXJ2aWNlLCB0aGlzLmNyZWF0ZUlmLCBvcHRpb25zKTtcbiAgICB9LFxuXG4gICAgY3JlYXRlSWY6IGZ1bmN0aW9uIChydW4sIGhlYWRlcnMpIHtcbiAgICAgICAgcmV0dXJuIGhlYWRlcnMuZ2V0UmVzcG9uc2VIZWFkZXIoJ3ByYWdtYScpID09PSAncGVyc2lzdGVudCc7XG4gICAgfVxufSk7XG5cbm1vZHVsZS5leHBvcnRzID0gU3RyYXRlZ3k7XG4iLCIndXNlIHN0cmljdCc7XG5cbnZhciBjbGFzc0Zyb20gPSByZXF1aXJlKCcuLi8uLi91dGlsL2luaGVyaXQnKTtcbnZhciBJZGVudGl0eVN0cmF0ZWd5ID0gcmVxdWlyZSgnLi9pZGVudGl0eS1zdHJhdGVneScpO1xudmFyIFN0b3JhZ2VGYWN0b3J5ID0gcmVxdWlyZSgnLi4vLi4vc3RvcmUvc3RvcmUtZmFjdG9yeScpO1xudmFyIFN0YXRlQXBpID0gcmVxdWlyZSgnLi4vLi4vc2VydmljZS9zdGF0ZS1hcGktYWRhcHRlcicpO1xudmFyIEF1dGhNYW5hZ2VyID0gcmVxdWlyZSgnLi4vYXV0aC1tYW5hZ2VyJyk7XG5cbnZhciBrZXlOYW1lcyA9IHJlcXVpcmUoJy4uL2tleS1uYW1lcycpO1xuXG52YXIgZGVmYXVsdHMgPSB7XG4gICAgc3RvcmU6IHtcbiAgICAgICAgc3luY2hyb25vdXM6IHRydWVcbiAgICB9XG59O1xuXG52YXIgU3RyYXRlZ3kgPSBjbGFzc0Zyb20oSWRlbnRpdHlTdHJhdGVneSwge1xuICAgIGNvbnN0cnVjdG9yOiBmdW5jdGlvbiBTdHJhdGVneShydW5TZXJ2aWNlLCBvcHRpb25zKSB7XG4gICAgICAgIHRoaXMucnVuID0gcnVuU2VydmljZTtcbiAgICAgICAgdGhpcy5vcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sIGRlZmF1bHRzLCBvcHRpb25zKTtcbiAgICAgICAgdGhpcy5ydW5PcHRpb25zID0gdGhpcy5vcHRpb25zLnJ1bjtcbiAgICAgICAgdGhpcy5fc3RvcmUgPSBuZXcgU3RvcmFnZUZhY3RvcnkodGhpcy5vcHRpb25zLnN0b3JlKTtcbiAgICAgICAgdGhpcy5zdGF0ZUFwaSA9IG5ldyBTdGF0ZUFwaSgpO1xuICAgICAgICB0aGlzLl9hdXRoID0gbmV3IEF1dGhNYW5hZ2VyKCk7XG5cbiAgICAgICAgdGhpcy5fbG9hZEFuZENoZWNrID0gdGhpcy5fbG9hZEFuZENoZWNrLmJpbmQodGhpcyk7XG4gICAgICAgIHRoaXMuX3Jlc3RvcmVSdW4gPSB0aGlzLl9yZXN0b3JlUnVuLmJpbmQodGhpcyk7XG4gICAgICAgIHRoaXMuX2dldEFsbFJ1bnMgPSB0aGlzLl9nZXRBbGxSdW5zLmJpbmQodGhpcyk7XG4gICAgICAgIHRoaXMuX2xvYWRSdW4gPSB0aGlzLl9sb2FkUnVuLmJpbmQodGhpcyk7XG4gICAgfSxcblxuICAgIHJlc2V0OiBmdW5jdGlvbiAocnVuU2VydmljZU9wdGlvbnMpIHtcbiAgICAgICAgdmFyIHNlc3Npb24gPSB0aGlzLl9hdXRoLmdldEN1cnJlbnRVc2VyU2Vzc2lvbkluZm8oKTtcbiAgICAgICAgdmFyIG9wdCA9ICQuZXh0ZW5kKHtcbiAgICAgICAgICAgIHNjb3BlOiB7IGdyb3VwOiBzZXNzaW9uLmdyb3VwTmFtZSB9XG4gICAgICAgIH0sIHRoaXMucnVuT3B0aW9ucyk7XG5cbiAgICAgICAgcmV0dXJuIHRoaXMucnVuXG4gICAgICAgICAgICAuY3JlYXRlKG9wdCwgcnVuU2VydmljZU9wdGlvbnMpXG4gICAgICAgICAgICAudGhlbihmdW5jdGlvbiAocnVuKSB7XG4gICAgICAgICAgICAgICAgcnVuLmZyZXNobHlDcmVhdGVkID0gdHJ1ZTtcbiAgICAgICAgICAgICAgICByZXR1cm4gcnVuO1xuICAgICAgICAgICAgfSk7XG4gICAgfSxcblxuICAgIGdldFJ1bjogZnVuY3Rpb24gKCkge1xuICAgICAgICByZXR1cm4gdGhpcy5fZ2V0QWxsUnVucygpXG4gICAgICAgICAgICAudGhlbih0aGlzLl9sb2FkQW5kQ2hlY2spO1xuICAgIH0sXG5cbiAgICBfZ2V0QWxsUnVuczogZnVuY3Rpb24gKCkge1xuICAgICAgICB2YXIgc2Vzc2lvbiA9IEpTT04ucGFyc2UodGhpcy5fc3RvcmUuZ2V0KGtleU5hbWVzLkVQSV9TRVNTSU9OX0tFWSkgfHwgJ3t9Jyk7XG4gICAgICAgIHJldHVybiB0aGlzLnJ1bi5xdWVyeSh7XG4gICAgICAgICAgICAndXNlci5pZCc6IHNlc3Npb24udXNlcklkIHx8ICcwMDAwJyxcbiAgICAgICAgICAgICdzY29wZS5ncm91cCc6IHNlc3Npb24uZ3JvdXBOYW1lXG4gICAgICAgIH0pO1xuICAgIH0sXG5cbiAgICBfbG9hZEFuZENoZWNrOiBmdW5jdGlvbiAocnVucykge1xuICAgICAgICBpZiAoIXJ1bnMgfHwgIXJ1bnMubGVuZ3RoKSB7XG4gICAgICAgICAgICByZXR1cm4gdGhpcy5yZXNldCgpO1xuICAgICAgICB9XG5cbiAgICAgICAgdmFyIGRhdGVDb21wID0gZnVuY3Rpb24gKGEsIGIpIHsgcmV0dXJuIG5ldyBEYXRlKGIuZGF0ZSkgLSBuZXcgRGF0ZShhLmRhdGUpOyB9O1xuICAgICAgICB2YXIgbGF0ZXN0UnVuID0gcnVucy5zb3J0KGRhdGVDb21wKVswXTtcbiAgICAgICAgdmFyIF90aGlzID0gdGhpcztcbiAgICAgICAgdmFyIHNob3VsZFJlcGxheSA9IGZhbHNlO1xuXG4gICAgICAgIHJldHVybiB0aGlzLnJ1bi5sb2FkKGxhdGVzdFJ1bi5pZCwgbnVsbCwge1xuICAgICAgICAgICAgc3VjY2VzczogZnVuY3Rpb24gKHJ1biwgbXNnLCBoZWFkZXJzKSB7XG4gICAgICAgICAgICAgICAgc2hvdWxkUmVwbGF5ID0gaGVhZGVycy5nZXRSZXNwb25zZUhlYWRlcigncHJhZ21hJykgPT09ICdwZXJzaXN0ZW50JztcbiAgICAgICAgICAgIH1cbiAgICAgICAgfSkudGhlbihmdW5jdGlvbiAocnVuKSB7XG4gICAgICAgICAgICByZXR1cm4gc2hvdWxkUmVwbGF5ID8gX3RoaXMuX3Jlc3RvcmVSdW4ocnVuLmlkKSA6IHJ1bjtcbiAgICAgICAgfSk7XG4gICAgfSxcblxuICAgIF9yZXN0b3JlUnVuOiBmdW5jdGlvbiAocnVuSWQpIHtcbiAgICAgICAgdmFyIF90aGlzID0gdGhpcztcbiAgICAgICAgcmV0dXJuIHRoaXMuc3RhdGVBcGkucmVwbGF5KHsgcnVuSWQ6IHJ1bklkIH0pXG4gICAgICAgICAgICAudGhlbihmdW5jdGlvbiAocmVzcCkge1xuICAgICAgICAgICAgICAgIHJldHVybiBfdGhpcy5fbG9hZFJ1bihyZXNwLnJ1bik7XG4gICAgICAgICAgICB9KTtcbiAgICB9LFxuXG4gICAgX2xvYWRSdW46IGZ1bmN0aW9uIChpZCwgb3B0aW9ucykge1xuICAgICAgICByZXR1cm4gdGhpcy5ydW4ubG9hZChpZCwgbnVsbCwgb3B0aW9ucyk7XG4gICAgfVxuXG59KTtcblxubW9kdWxlLmV4cG9ydHMgPSBTdHJhdGVneTtcbiIsIm1vZHVsZS5leHBvcnRzID0ge1xuICAgICduZXctaWYtaW5pdGlhbGl6ZWQnOiByZXF1aXJlKCcuL25ldy1pZi1pbml0aWFsaXplZC1zdHJhdGVneScpLFxuICAgICduZXctaWYtcGVyc2lzdGVkJzogcmVxdWlyZSgnLi9uZXctaWYtcGVyc2lzdGVkLXN0cmF0ZWd5JyksXG4gICAgJ25ldy1pZi1taXNzaW5nJzogcmVxdWlyZSgnLi9uZXctaWYtbWlzc2luZy1zdHJhdGVneScpLFxuICAgICdhbHdheXMtbmV3JzogcmVxdWlyZSgnLi9hbHdheXMtbmV3LXN0cmF0ZWd5JyksXG4gICAgJ211bHRpcGxheWVyJzogcmVxdWlyZSgnLi9tdWx0aXBsYXllci1zdHJhdGVneScpLFxuICAgICdwZXJzaXN0ZW50LXNpbmdsZS1wbGF5ZXInOiByZXF1aXJlKCcuL3BlcnNpc3RlbnQtc2luZ2xlLXBsYXllci1zdHJhdGVneScpLFxuICAgICdub25lJzogcmVxdWlyZSgnLi9pZGVudGl0eS1zdHJhdGVneScpXG59O1xuIiwiJ3VzZSBzdHJpY3QnO1xudmFyIFJ1blNlcnZpY2UgPSByZXF1aXJlKCcuLi9zZXJ2aWNlL3J1bi1hcGktc2VydmljZScpO1xuXG52YXIgZGVmYXVsdHMgPSB7XG4gICAgdmFsaWRGaWx0ZXI6IHsgc2F2ZWQ6IHRydWUgfVxufTtcblxuZnVuY3Rpb24gU2NlbmFyaW9NYW5hZ2VyKG9wdGlvbnMpIHtcbiAgICB0aGlzLm9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSwgZGVmYXVsdHMsIG9wdGlvbnMpO1xuICAgIHRoaXMucnVuU2VydmljZSA9IHRoaXMub3B0aW9ucy5ydW4gfHwgbmV3IFJ1blNlcnZpY2UodGhpcy5vcHRpb25zKTtcbn1cblxuU2NlbmFyaW9NYW5hZ2VyLnByb3RvdHlwZSA9IHtcbiAgICBnZXRSdW5zOiBmdW5jdGlvbiAoZmlsdGVyKSB7XG4gICAgICAgIHRoaXMuZmlsdGVyID0gJC5leHRlbmQodHJ1ZSwge30sIHRoaXMub3B0aW9ucy52YWxpZEZpbHRlciwgZmlsdGVyKTtcbiAgICAgICAgcmV0dXJuIHRoaXMucnVuU2VydmljZS5xdWVyeSh0aGlzLmZpbHRlcik7XG4gICAgfSxcblxuICAgIGxvYWRWYXJpYWJsZXM6IGZ1bmN0aW9uICh2YXJzKSB7XG4gICAgICAgIHJldHVybiB0aGlzLnJ1blNlcnZpY2UucXVlcnkodGhpcy5maWx0ZXIsIHsgaW5jbHVkZTogdmFycyB9KTtcbiAgICB9LFxuXG4gICAgc2F2ZTogZnVuY3Rpb24gKHJ1biwgbWV0YSkge1xuICAgICAgICByZXR1cm4gdGhpcy5fZ2V0U2VydmljZShydW4pLnNhdmUoJC5leHRlbmQodHJ1ZSwge30sIHsgc2F2ZWQ6IHRydWUgfSwgbWV0YSkpO1xuICAgIH0sXG5cbiAgICBhcmNoaXZlOiBmdW5jdGlvbiAocnVuKSB7XG4gICAgICAgIHJldHVybiB0aGlzLl9nZXRTZXJ2aWNlKHJ1bikuc2F2ZSh7IHNhdmVkOiBmYWxzZSB9KTtcbiAgICB9LFxuXG4gICAgX2dldFNlcnZpY2U6IGZ1bmN0aW9uIChydW4pIHtcbiAgICAgICAgaWYgKHR5cGVvZiBydW4gPT09ICdzdHJpbmcnKSB7XG4gICAgICAgICAgICByZXR1cm4gbmV3IFJ1blNlcnZpY2UoJC5leHRlbmQodHJ1ZSwge30sICB0aGlzLm9wdGlvbnMsIHsgZmlsdGVyOiBydW4gfSkpO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKHR5cGVvZiBydW4gPT09ICdvYmplY3QnICYmIHJ1biBpbnN0YW5jZW9mIFJ1blNlcnZpY2UpIHtcbiAgICAgICAgICAgIHJldHVybiBydW47XG4gICAgICAgIH1cblxuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ1NhdmUgbWV0aG9kIHJlcXVpcmVzIGEgcnVuIHNlcnZpY2Ugb3IgYSBydW5JZCcpO1xuICAgIH0sXG5cbiAgICBnZXRSdW46IGZ1bmN0aW9uIChydW5JZCkge1xuICAgICAgICByZXR1cm4gbmV3IFJ1blNlcnZpY2UoJC5leHRlbmQodHJ1ZSwge30sICB0aGlzLm9wdGlvbnMsIHsgZmlsdGVyOiBydW5JZCB9KSk7XG4gICAgfVxufTtcblxubW9kdWxlLmV4cG9ydHMgPSBTY2VuYXJpb01hbmFnZXI7XG5cbiIsIid1c2Ugc3RyaWN0JztcblxuXG5tb2R1bGUuZXhwb3J0cyA9IHtcbiAgICByZXNldDogZnVuY3Rpb24gKHBhcmFtcywgb3B0aW9ucywgbWFuYWdlcikge1xuICAgICAgICByZXR1cm4gbWFuYWdlci5yZXNldChvcHRpb25zKTtcbiAgICB9XG59O1xuIiwiLyoqXG4qICMjIFdvcmxkIE1hbmFnZXJcbipcbiogQXMgZGlzY3Vzc2VkIHVuZGVyIHRoZSBbV29ybGQgQVBJIEFkYXB0ZXJdKC4uL3dvcmxkLWFwaS1hZGFwdGVyLyksIGEgW3J1bl0oLi4vLi4vLi4vZ2xvc3NhcnkvI3J1bikgaXMgYSBjb2xsZWN0aW9uIG9mIGVuZCB1c2VyIGludGVyYWN0aW9ucyB3aXRoIGEgcHJvamVjdCBhbmQgaXRzIG1vZGVsLiBGb3IgYnVpbGRpbmcgbXVsdGlwbGF5ZXIgc2ltdWxhdGlvbnMgeW91IHR5cGljYWxseSB3YW50IG11bHRpcGxlIGVuZCB1c2VycyB0byBzaGFyZSB0aGUgc2FtZSBzZXQgb2YgaW50ZXJhY3Rpb25zLCBhbmQgd29yayB3aXRoaW4gYSBjb21tb24gc3RhdGUuIEVwaWNlbnRlciBhbGxvd3MgeW91IHRvIGNyZWF0ZSBcIndvcmxkc1wiIHRvIGhhbmRsZSBzdWNoIGNhc2VzLlxuKlxuKiBUaGUgV29ybGQgTWFuYWdlciBwcm92aWRlcyBhbiBlYXN5IHdheSB0byB0cmFjayBhbmQgYWNjZXNzIHRoZSBjdXJyZW50IHdvcmxkIGFuZCBydW4gZm9yIHBhcnRpY3VsYXIgZW5kIHVzZXJzLiBJdCBpcyB0eXBpY2FsbHkgdXNlZCBpbiBwYWdlcyB0aGF0IGVuZCB1c2VycyB3aWxsIGludGVyYWN0IHdpdGguIChUaGUgcmVsYXRlZCBbV29ybGQgQVBJIEFkYXB0ZXJdKC4uL3dvcmxkLWFwaS1hZGFwdGVyLykgaGFuZGxlcyBjcmVhdGluZyBtdWx0aXBsYXllciB3b3JsZHMsIGFuZCBhZGRpbmcgYW5kIHJlbW92aW5nIGVuZCB1c2VycyBhbmQgcnVucyBmcm9tIGEgd29ybGQuIEJlY2F1c2Ugb2YgdGhpcywgdHlwaWNhbGx5IHRoZSBXb3JsZCBBZGFwdGVyIGlzIHVzZWQgZm9yIGZhY2lsaXRhdG9yIHBhZ2VzIGluIHlvdXIgcHJvamVjdC4pXG4qXG4qICMjIyBVc2luZyB0aGUgV29ybGQgTWFuYWdlclxuKlxuKiBUbyB1c2UgdGhlIFdvcmxkIE1hbmFnZXIsIGluc3RhbnRpYXRlIGl0LiBUaGVuLCBtYWtlIGNhbGxzIHRvIGFueSBvZiB0aGUgbWV0aG9kcyB5b3UgbmVlZC5cbipcbiogV2hlbiB5b3UgaW5zdGFudGlhdGUgYSBXb3JsZCBNYW5hZ2VyLCB0aGUgd29ybGQncyBhY2NvdW50IGlkLCBwcm9qZWN0IGlkLCBhbmQgZ3JvdXAgYXJlIGF1dG9tYXRpY2FsbHkgdGFrZW4gZnJvbSB0aGUgc2Vzc2lvbiAodGhhbmtzIHRvIHRoZSBbQXV0aGVudGljYXRpb24gU2VydmljZV0oLi4vYXV0aC1hcGktc2VydmljZSkpLlxuKlxuKiBOb3RlIHRoYXQgdGhlIFdvcmxkIE1hbmFnZXIgZG9lcyAqbm90KiBjcmVhdGUgd29ybGRzIGF1dG9tYXRpY2FsbHkuIChUaGlzIGlzIGRpZmZlcmVudCB0aGFuIHRoZSBbUnVuIE1hbmFnZXJdKC4uL3J1bi1tYW5hZ2VyKS4pIEhvd2V2ZXIsIHlvdSBjYW4gcGFzcyBpbiBzcGVjaWZpYyBvcHRpb25zIHRvIGFueSBydW5zIGNyZWF0ZWQgYnkgdGhlIG1hbmFnZXIsIHVzaW5nIGEgYHJ1bmAgb2JqZWN0LlxuKlxuKiBUaGUgcGFyYW1ldGVycyBmb3IgY3JlYXRpbmcgYSBXb3JsZCBNYW5hZ2VyIGFyZTpcbipcbiogICAqIGBhY2NvdW50YDogVGhlICoqVGVhbSBJRCoqIGluIHRoZSBFcGljZW50ZXIgdXNlciBpbnRlcmZhY2UgZm9yIHRoaXMgcHJvamVjdC5cbiogICAqIGBwcm9qZWN0YDogVGhlICoqUHJvamVjdCBJRCoqIGZvciB0aGlzIHByb2plY3QuXG4qICAgKiBgZ3JvdXBgOiBUaGUgKipHcm91cCBOYW1lKiogZm9yIHRoaXMgd29ybGQuXG4qICAgKiBgcnVuYDogT3B0aW9ucyB0byB1c2Ugd2hlbiBjcmVhdGluZyBuZXcgcnVucyB3aXRoIHRoZSBtYW5hZ2VyLCBlLmcuIGBydW46IHsgZmlsZXM6IFsnZGF0YS54bHMnXSB9YC5cbiogICAqIGBydW4ubW9kZWxgOiBUaGUgbmFtZSBvZiB0aGUgcHJpbWFyeSBtb2RlbCBmaWxlIGZvciB0aGlzIHByb2plY3QuIFJlcXVpcmVkIGlmIHlvdSBoYXZlIG5vdCBhbHJlYWR5IHBhc3NlZCBpdCBpbiBhcyBwYXJ0IG9mIHRoZSBgb3B0aW9uc2AgcGFyYW1ldGVyIGZvciBhbiBlbmNsb3NpbmcgY2FsbC5cbipcbiogRm9yIGV4YW1wbGU6XG4qXG4qICAgICAgIHZhciB3TWdyID0gbmV3IEYubWFuYWdlci5Xb3JsZE1hbmFnZXIoe1xuKiAgICAgICAgICBhY2NvdW50OiAnYWNtZS1zaW11bGF0aW9ucycsXG4qICAgICAgICAgIHByb2plY3Q6ICdzdXBwbHktY2hhaW4tZ2FtZScsXG4qICAgICAgICAgIHJ1bjogeyBtb2RlbDogJ3N1cHBseS1jaGFpbi5weScgfSxcbiogICAgICAgICAgZ3JvdXA6ICd0ZWFtMSdcbiogICAgICAgfSk7XG4qXG4qICAgICAgIHdNZ3IuZ2V0Q3VycmVudFJ1bigpO1xuKi9cblxuJ3VzZSBzdHJpY3QnO1xuXG52YXIgV29ybGRBcGkgPSByZXF1aXJlKCcuLi9zZXJ2aWNlL3dvcmxkLWFwaS1hZGFwdGVyJyk7XG52YXIgUnVuTWFuYWdlciA9ICByZXF1aXJlKCcuL3J1bi1tYW5hZ2VyJyk7XG52YXIgQXV0aE1hbmFnZXIgPSByZXF1aXJlKCcuL2F1dGgtbWFuYWdlcicpO1xudmFyIHdvcmxkQXBpO1xuXG4vLyB2YXIgZGVmYXVsdHMgPSB7XG4vLyAgYWNjb3VudDogJycsXG4vLyAgcHJvamVjdDogJycsXG4vLyAgZ3JvdXA6ICcnLFxuLy8gIHRyYW5zcG9ydDoge1xuLy8gIH1cbi8vIH07XG5cblxuZnVuY3Rpb24gYnVpbGRTdHJhdGVneSh3b3JsZElkLCBkdGQpIHtcblxuICAgIHJldHVybiBmdW5jdGlvbiBDdG9yKHJ1blNlcnZpY2UsIG9wdGlvbnMpIHtcbiAgICAgICAgdGhpcy5ydW5TZXJ2aWNlID0gcnVuU2VydmljZTtcbiAgICAgICAgdGhpcy5vcHRpb25zID0gb3B0aW9ucztcblxuICAgICAgICAkLmV4dGVuZCh0aGlzLCB7XG4gICAgICAgICAgICByZXNldDogZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcignbm90IGltcGxlbWVudGQuIE5lZWQgYXBpIGNoYW5nZXMnKTtcbiAgICAgICAgICAgIH0sXG5cbiAgICAgICAgICAgIGdldFJ1bjogZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgICAgIHZhciBfdGhpcyA9IHRoaXM7XG4gICAgICAgICAgICAgICAgLy9nZXQgb3IgY3JlYXRlIVxuICAgICAgICAgICAgICAgIC8vIE1vZGVsIGlzIHJlcXVpcmVkIGluIHRoZSBvcHRpb25zXG4gICAgICAgICAgICAgICAgdmFyIG1vZGVsID0gdGhpcy5vcHRpb25zLnJ1bi5tb2RlbCB8fCB0aGlzLm9wdGlvbnMubW9kZWw7XG4gICAgICAgICAgICAgICAgcmV0dXJuIHdvcmxkQXBpLmdldEN1cnJlbnRSdW5JZCh7IG1vZGVsOiBtb2RlbCwgZmlsdGVyOiB3b3JsZElkIH0pXG4gICAgICAgICAgICAgICAgICAgIC50aGVuKGZ1bmN0aW9uIChydW5JZCkge1xuICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIF90aGlzLnJ1blNlcnZpY2UubG9hZChydW5JZCk7XG4gICAgICAgICAgICAgICAgICAgIH0pXG4gICAgICAgICAgICAgICAgICAgIC50aGVuKGZ1bmN0aW9uIChydW4pIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGR0ZC5yZXNvbHZlLmNhbGwodGhpcywgcnVuLCBfdGhpcy5ydW5TZXJ2aWNlKTtcbiAgICAgICAgICAgICAgICAgICAgfSlcbiAgICAgICAgICAgICAgICAgICAgLmZhaWwoZHRkLnJlamVjdCk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICApO1xuICAgIH07XG59XG5cblxubW9kdWxlLmV4cG9ydHMgPSBmdW5jdGlvbiAob3B0aW9ucykge1xuICAgIHRoaXMub3B0aW9ucyA9IG9wdGlvbnMgfHwgeyBydW46IHt9LCB3b3JsZDoge30gfTtcblxuICAgICQuZXh0ZW5kKHRydWUsIHRoaXMub3B0aW9ucywgdGhpcy5vcHRpb25zLnJ1bik7XG4gICAgJC5leHRlbmQodHJ1ZSwgdGhpcy5vcHRpb25zLCB0aGlzLm9wdGlvbnMud29ybGQpO1xuXG4gICAgd29ybGRBcGkgPSBuZXcgV29ybGRBcGkodGhpcy5vcHRpb25zKTtcbiAgICB0aGlzLl9hdXRoID0gbmV3IEF1dGhNYW5hZ2VyKCk7XG4gICAgdmFyIF90aGlzID0gdGhpcztcblxuICAgIHZhciBhcGkgPSB7XG5cbiAgICAgICAgLyoqXG4gICAgICAgICogUmV0dXJucyB0aGUgY3VycmVudCB3b3JsZCAob2JqZWN0KSBhbmQgYW4gaW5zdGFuY2Ugb2YgdGhlIFtXb3JsZCBBUEkgQWRhcHRlcl0oLi4vd29ybGQtYXBpLWFkYXB0ZXIvKS5cbiAgICAgICAgKlxuICAgICAgICAqICoqRXhhbXBsZSoqXG4gICAgICAgICpcbiAgICAgICAgKiAgICAgICB3TWdyLmdldEN1cnJlbnRXb3JsZCgpXG4gICAgICAgICogICAgICAgICAgIC50aGVuKGZ1bmN0aW9uKHdvcmxkLCB3b3JsZEFkYXB0ZXIpIHtcbiAgICAgICAgKiAgICAgICAgICAgICAgIGNvbnNvbGUubG9nKHdvcmxkLmlkKTtcbiAgICAgICAgKiAgICAgICAgICAgICAgIHdvcmxkQWRhcHRlci5nZXRDdXJyZW50UnVuSWQoKTtcbiAgICAgICAgKiAgICAgICAgICAgfSk7XG4gICAgICAgICpcbiAgICAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAqIEBwYXJhbSB7c3RyaW5nfSBgdXNlcklkYCAoT3B0aW9uYWwpIFRoZSBpZCBvZiB0aGUgdXNlciB3aG9zZSB3b3JsZCBpcyBiZWluZyBhY2Nlc3NlZC4gRGVmYXVsdHMgdG8gdGhlIHVzZXIgaW4gdGhlIGN1cnJlbnQgc2Vzc2lvbi5cbiAgICAgICAgKiBAcGFyYW0ge3N0cmluZ30gYGdyb3VwTmFtZWAgKE9wdGlvbmFsKSBUaGUgbmFtZSBvZiB0aGUgZ3JvdXAgd2hvc2Ugd29ybGQgaXMgYmVpbmcgYWNjZXNzZWQuIERlZmF1bHRzIHRvIHRoZSBncm91cCBmb3IgdGhlIHVzZXIgaW4gdGhlIGN1cnJlbnQgc2Vzc2lvbi5cbiAgICAgICAgKi9cbiAgICAgICAgZ2V0Q3VycmVudFdvcmxkOiBmdW5jdGlvbiAodXNlcklkLCBncm91cE5hbWUpIHtcbiAgICAgICAgICAgIHZhciBzZXNzaW9uID0gdGhpcy5fYXV0aC5nZXRDdXJyZW50VXNlclNlc3Npb25JbmZvKCk7XG4gICAgICAgICAgICBpZiAoIXVzZXJJZCkge1xuICAgICAgICAgICAgICAgIHVzZXJJZCA9IHNlc3Npb24udXNlcklkO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgaWYgKCFncm91cE5hbWUpIHtcbiAgICAgICAgICAgICAgICBncm91cE5hbWUgPSBzZXNzaW9uLmdyb3VwTmFtZTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHJldHVybiB3b3JsZEFwaS5nZXRDdXJyZW50V29ybGRGb3JVc2VyKHVzZXJJZCwgZ3JvdXBOYW1lKTtcbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgKiBSZXR1cm5zIHRoZSBjdXJyZW50IHJ1biAob2JqZWN0KSBhbmQgYW4gaW5zdGFuY2Ugb2YgdGhlIFtSdW4gQVBJIFNlcnZpY2VdKC4uL3J1bi1hcGktc2VydmljZS8pLlxuICAgICAgICAqXG4gICAgICAgICogKipFeGFtcGxlKipcbiAgICAgICAgKlxuICAgICAgICAqICAgICAgIHdNZ3IuZ2V0Q3VycmVudFJ1bih7bW9kZWw6ICdteU1vZGVsLnB5J30pXG4gICAgICAgICogICAgICAgICAgIC50aGVuKGZ1bmN0aW9uKHJ1biwgcnVuU2VydmljZSkge1xuICAgICAgICAqICAgICAgICAgICAgICAgY29uc29sZS5sb2cocnVuLmlkKTtcbiAgICAgICAgKiAgICAgICAgICAgICAgIHJ1blNlcnZpY2UuZG8oJ3N0YXJ0R2FtZScpO1xuICAgICAgICAqICAgICAgICAgICB9KTtcbiAgICAgICAgKlxuICAgICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICAgICogQHBhcmFtIHtzdHJpbmd9IGBtb2RlbGAgKE9wdGlvbmFsKSBUaGUgbmFtZSBvZiB0aGUgbW9kZWwgZmlsZS4gUmVxdWlyZWQgaWYgbm90IGFscmVhZHkgcGFzc2VkIGluIGFzIGBydW4ubW9kZWxgIHdoZW4gdGhlIFdvcmxkIE1hbmFnZXIgaXMgY3JlYXRlZC5cbiAgICAgICAgKi9cbiAgICAgICAgZ2V0Q3VycmVudFJ1bjogZnVuY3Rpb24gKG1vZGVsKSB7XG4gICAgICAgICAgICB2YXIgZHRkID0gJC5EZWZlcnJlZCgpO1xuICAgICAgICAgICAgdmFyIHNlc3Npb24gPSB0aGlzLl9hdXRoLmdldEN1cnJlbnRVc2VyU2Vzc2lvbkluZm8oKTtcbiAgICAgICAgICAgIHZhciBjdXJVc2VySWQgPSBzZXNzaW9uLnVzZXJJZDtcbiAgICAgICAgICAgIHZhciBjdXJHcm91cE5hbWUgPSBzZXNzaW9uLmdyb3VwTmFtZTtcblxuICAgICAgICAgICAgZnVuY3Rpb24gZ2V0QW5kUmVzdG9yZUxhdGVzdFJ1bih3b3JsZCkge1xuICAgICAgICAgICAgICAgIGlmICghd29ybGQpIHtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIGR0ZC5yZWplY3QoeyBlcnJvcjogJ1RoZSB1c2VyIGlzIG5vdCBwYXJ0IG9mIGFueSB3b3JsZCEnIH0pO1xuICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgIHZhciBjdXJyZW50V29ybGRJZCA9IHdvcmxkLmlkO1xuICAgICAgICAgICAgICAgIHZhciBydW5PcHRzID0gJC5leHRlbmQodHJ1ZSwgX3RoaXMub3B0aW9ucywgeyBtb2RlbDogbW9kZWwgfSk7XG4gICAgICAgICAgICAgICAgdmFyIHN0cmF0ZWd5ID0gYnVpbGRTdHJhdGVneShjdXJyZW50V29ybGRJZCwgZHRkKTtcbiAgICAgICAgICAgICAgICB2YXIgb3B0ID0gJC5leHRlbmQodHJ1ZSwge30sIHtcbiAgICAgICAgICAgICAgICAgICAgc3RyYXRlZ3k6IHN0cmF0ZWd5LFxuICAgICAgICAgICAgICAgICAgICBydW46IHJ1bk9wdHNcbiAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgICB2YXIgcm0gPSBuZXcgUnVuTWFuYWdlcihvcHQpO1xuXG4gICAgICAgICAgICAgICAgcmV0dXJuIHJtLmdldFJ1bigpXG4gICAgICAgICAgICAgICAgICAgIC50aGVuKGZ1bmN0aW9uIChydW4pIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGR0ZC5yZXNvbHZlKHJ1biwgcm0ucnVuU2VydmljZSwgcm0pO1xuICAgICAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgdGhpcy5nZXRDdXJyZW50V29ybGQoY3VyVXNlcklkLCBjdXJHcm91cE5hbWUpXG4gICAgICAgICAgICAgICAgLnRoZW4oZ2V0QW5kUmVzdG9yZUxhdGVzdFJ1bik7XG5cbiAgICAgICAgICAgIHJldHVybiBkdGQucHJvbWlzZSgpO1xuICAgICAgICB9XG4gICAgfTtcblxuICAgICQuZXh0ZW5kKHRoaXMsIGFwaSk7XG59O1xuIiwiLyoqXG4gKiAjIyBGaWxlIEFQSSBTZXJ2aWNlXG4gKlxuICogVGhpcyBpcyB1c2VkIHRvIHVwbG9hZC9kb3dubG9hZCBmaWxlcyBkaXJlY3RseSBvbnRvIEVwaWNlbnRlciwgYW5hbG9nb3VzIHRvIHVzaW5nIHRoZSBGaWxlIE1hbmFnZXIgVUkgaW4gRXBpY2VudGVyIGRpcmVjdGx5IG9yIFNGVFBpbmcgZmlsZXMgaW4uIFRoZSBBc3NldCBBUEkgaXMgdHlwaWNhbGx5IHVzZWQgZm9yIGFsbCBwcm9qZWN0IHVzZS1jYXNlcywgYW5kIGl0J3MgdW5saWtlbHkgdGhpcyBGaWxlIFNlcnZpY2Ugd2lsbCBiZSB1c2VkIGRpcmVjdGx5IGV4Y2VwdCBieSBBZG1pbiB0b29scyAoZS5nLiBGbG93IEluc3BlY3RvcikuXG4gKlxuICogUGFydGlhbGx5IGltcGxlbWVudGVkLlxuICovXG5cbid1c2Ugc3RyaWN0JztcblxudmFyIENvbmZpZ1NlcnZpY2UgPSByZXF1aXJlKCcuL2NvbmZpZ3VyYXRpb24tc2VydmljZScpO1xudmFyIFRyYW5zcG9ydEZhY3RvcnkgPSByZXF1aXJlKCcuLi90cmFuc3BvcnQvaHR0cC10cmFuc3BvcnQtZmFjdG9yeScpO1xudmFyIFNlc3Npb25NYW5hZ2VyID0gcmVxdWlyZSgnLi4vc3RvcmUvc2Vzc2lvbi1tYW5hZ2VyJyk7XG5cbm1vZHVsZS5leHBvcnRzID0gZnVuY3Rpb24gKGNvbmZpZykge1xuICAgIHZhciBkZWZhdWx0cyA9IHtcbiAgICAgICAgLyoqXG4gICAgICAgICAqIEZvciBwcm9qZWN0cyB0aGF0IHJlcXVpcmUgYXV0aGVudGljYXRpb24sIHBhc3MgaW4gdGhlIHVzZXIgYWNjZXNzIHRva2VuIChkZWZhdWx0cyB0byBlbXB0eSBzdHJpbmcpLiBJZiB0aGUgdXNlciBpcyBhbHJlYWR5IGxvZ2dlZCBpbiB0byBFcGljZW50ZXIsIHRoZSB1c2VyIGFjY2VzcyB0b2tlbiBpcyBhbHJlYWR5IHNldCBpbiBhIGNvb2tpZSBhbmQgYXV0b21hdGljYWxseSBsb2FkZWQgZnJvbSB0aGVyZS4gKFNlZSBbbW9yZSBiYWNrZ3JvdW5kIG9uIGFjY2VzcyB0b2tlbnNdKC4uLy4uLy4uL3Byb2plY3RfYWNjZXNzLykpLlxuICAgICAgICAgKiBAc2VlIFtBdXRoZW50aWNhdGlvbiBBUEkgU2VydmljZV0oLi4vYXV0aC1hcGktc2VydmljZS8pIGZvciBnZXR0aW5nIHRva2Vucy5cbiAgICAgICAgICogQHR5cGUge1N0cmluZ31cbiAgICAgICAgICovXG4gICAgICAgIHRva2VuOiB1bmRlZmluZWQsXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIFRoZSBhY2NvdW50IGlkLiBJbiB0aGUgRXBpY2VudGVyIFVJLCB0aGlzIGlzIHRoZSAqKlRlYW0gSUQqKiAoZm9yIHRlYW0gcHJvamVjdHMpIG9yICoqVXNlciBJRCoqIChmb3IgcGVyc29uYWwgcHJvamVjdHMpLiBEZWZhdWx0cyB0byBlbXB0eSBzdHJpbmcuXG4gICAgICAgICAqIEB0eXBlIHtTdHJpbmd9XG4gICAgICAgICAqL1xuICAgICAgICBhY2NvdW50OiB1bmRlZmluZWQsXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIFRoZSBwcm9qZWN0IGlkLiBEZWZhdWx0cyB0byBlbXB0eSBzdHJpbmcuXG4gICAgICAgICAqIEB0eXBlIHtTdHJpbmd9XG4gICAgICAgICAqL1xuICAgICAgICBwcm9qZWN0OiB1bmRlZmluZWQsXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIFRoZSBmb2xkZXIgdHlwZS4gIE9uZSBvZiBNb2RlbHxTdGF0aWN8Tm9kZVxuICAgICAgICAgKiBAdHlwZSB7U3RyaW5nfVxuICAgICAgICAgKi9cbiAgICAgICAgZm9sZGVyVHlwZTogJ3N0YXRpYycsXG5cblxuICAgICAgICAvKipcbiAgICAgICAgICogT3B0aW9ucyB0byBwYXNzIG9uIHRvIHRoZSB1bmRlcmx5aW5nIHRyYW5zcG9ydCBsYXllci4gQWxsIGpxdWVyeS5hamF4IG9wdGlvbnMgYXQgaHR0cDovL2FwaS5qcXVlcnkuY29tL2pRdWVyeS5hamF4LyBhcmUgYXZhaWxhYmxlLiBEZWZhdWx0cyB0byBlbXB0eSBvYmplY3QuXG4gICAgICAgICAqIEB0eXBlIHtPYmplY3R9XG4gICAgICAgICAqL1xuICAgICAgICB0cmFuc3BvcnQ6IHt9XG4gICAgfTtcblxuICAgIHRoaXMuc2Vzc2lvbk1hbmFnZXIgPSBuZXcgU2Vzc2lvbk1hbmFnZXIoKTtcbiAgICB2YXIgc2VydmljZU9wdGlvbnMgPSB0aGlzLnNlc3Npb25NYW5hZ2VyLmdldE1lcmdlZE9wdGlvbnMoZGVmYXVsdHMsIGNvbmZpZyk7XG4gICAgdmFyIHVybENvbmZpZyA9IG5ldyBDb25maWdTZXJ2aWNlKHNlcnZpY2VPcHRpb25zKS5nZXQoJ3NlcnZlcicpO1xuICAgIGlmIChzZXJ2aWNlT3B0aW9ucy5hY2NvdW50KSB7XG4gICAgICAgIHVybENvbmZpZy5hY2NvdW50UGF0aCA9IHNlcnZpY2VPcHRpb25zLmFjY291bnQ7XG4gICAgfVxuICAgIGlmIChzZXJ2aWNlT3B0aW9ucy5wcm9qZWN0KSB7XG4gICAgICAgIHVybENvbmZpZy5wcm9qZWN0UGF0aCA9IHNlcnZpY2VPcHRpb25zLnByb2plY3Q7XG4gICAgfVxuXG4gICAgdmFyIGh0dHBPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sIHNlcnZpY2VPcHRpb25zLnRyYW5zcG9ydCwge1xuICAgICAgICB1cmw6IHVybENvbmZpZy5nZXRBUElQYXRoKCdmaWxlJylcbiAgICB9KTtcblxuICAgIGlmIChzZXJ2aWNlT3B0aW9ucy50b2tlbikge1xuICAgICAgICBodHRwT3B0aW9ucy5oZWFkZXJzID0ge1xuICAgICAgICAgICAgJ0F1dGhvcml6YXRpb24nOiAnQmVhcmVyICcgKyBzZXJ2aWNlT3B0aW9ucy50b2tlblxuICAgICAgICB9O1xuICAgIH1cbiAgICB2YXIgaHR0cCA9IG5ldyBUcmFuc3BvcnRGYWN0b3J5KGh0dHBPcHRpb25zKTtcblxuICAgIHZhciBwdWJsaWNBc3luY0FQSSA9IHtcbiAgICAgICAgLyoqXG4gICAgICAgICAqIEdldCBhIGRpcmVjdG9yeSBsaXN0aW5nLCBvciBjb250ZW50cyBvZiBhIGZpbGVcbiAgICAgICAgICogQHBhcmFtICB7U3RyaW5nfSBgZmlsZVBhdGhgICAgUGF0aCB0byB0aGUgZmlsZVxuICAgICAgICAgKiBAcGFyYW0gIHtPYmplY3R9IGBvcHRpb25zYCAoT3B0aW9uYWwpIE92ZXJyaWRlcyBmb3IgY29uZmlndXJhdGlvbiBvcHRpb25zLlxuICAgICAgICAgKi9cbiAgICAgICAgZ2V0Q29udGVudHM6IGZ1bmN0aW9uIChmaWxlUGF0aCwgb3B0aW9ucykge1xuICAgICAgICAgICAgdmFyIHBhdGggPSBzZXJ2aWNlT3B0aW9ucy5mb2xkZXJUeXBlICsgJy8nICsgZmlsZVBhdGg7XG4gICAgICAgICAgICB2YXIgaHR0cE9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSwgc2VydmljZU9wdGlvbnMsIG9wdGlvbnMsIHtcbiAgICAgICAgICAgICAgICB1cmw6IHVybENvbmZpZy5nZXRBUElQYXRoKCdmaWxlJykgKyBwYXRoXG4gICAgICAgICAgICB9KTtcbiAgICAgICAgICAgIHJldHVybiBodHRwLmdldCgnJywgaHR0cE9wdGlvbnMpO1xuICAgICAgICB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBXcml0ZXMgdG8gdGhlIGdpdmVuIGZpbGUgcGF0aDsgcmVwbGFjZXMgdGhlIGV4aXN0aW5nIGZpbGUgaWYgaXQgZXhpc3RzXG4gICAgICAgICAqIEBwYXJhbSAge1N0cmluZ30gYGZpbGVQYXRoYCBQYXRoIHRvIHRoZSBmaWxlXG4gICAgICAgICAqIEBwYXJhbSAge1N0cmluZ30gYGNvbnRlbnRzYCBDb250ZW50cyB0byB3cml0ZSB0byBmaWxlXG4gICAgICAgICAqIEBwYXJhbSAge09iamVjdH0gYG9wdGlvbnNgICAoT3B0aW9uYWwpIE92ZXJyaWRlcyBmb3IgY29uZmlndXJhdGlvbiBvcHRpb25zXG4gICAgICAgICAqL1xuICAgICAgICB3cml0ZVRvRmlsZTogZnVuY3Rpb24gKGZpbGVQYXRoLCBjb250ZW50cywgb3B0aW9ucykge1xuICAgICAgICAgICAgZmlsZVBhdGggPSBmaWxlUGF0aC5zcGxpdCgnLycpO1xuICAgICAgICAgICAgdmFyIGZpbGVOYW1lID0gZmlsZVBhdGgucG9wKCk7XG4gICAgICAgICAgICBmaWxlUGF0aCA9IGZpbGVQYXRoLmpvaW4oJy8nKTtcbiAgICAgICAgICAgIHZhciBwYXRoID0gc2VydmljZU9wdGlvbnMuZm9sZGVyVHlwZSArICcvJyArIGZpbGVQYXRoO1xuICAgICAgICAgICAgdmFyIGJvdW5kYXJ5ID0gJy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLTdkYTI0ZjJlNTAwNDYnO1xuXG4gICAgICAgICAgICB2YXIgYm9keSA9ICctLScgKyBib3VuZGFyeSArICdcXHJcXG4nICtcbiAgICAgICAgICAgICAgICAnQ29udGVudC1EaXNwb3NpdGlvbjogZm9ybS1kYXRhOyBuYW1lPVwiZmlsZVwiOycgK1xuICAgICAgICAgICAgICAgICdmaWxlbmFtZT1cIicgKyBmaWxlTmFtZSArICdcIlxcclxcbicgK1xuICAgICAgICAgICAgICAgICdDb250ZW50LXR5cGU6IHRleHQvaHRtbFxcclxcblxcclxcbicgK1xuICAgICAgICAgICAgICAgIGNvbnRlbnRzICsgJ1xcclxcbicgK1xuICAgICAgICAgICAgICAgICctLScgKyBib3VuZGFyeSArICctLSc7XG5cbiAgICAgICAgICAgIHZhciBodHRwT3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LCBzZXJ2aWNlT3B0aW9ucywgb3B0aW9ucywge1xuICAgICAgICAgICAgICAgIHVybDogdXJsQ29uZmlnLmdldEFQSVBhdGgoJ2ZpbGUnKSArIHBhdGgsXG4gICAgICAgICAgICAgICAgZGF0YTogYm9keSxcbiAgICAgICAgICAgICAgICBjb250ZW50VHlwZTogJ211bHRpcGFydC9mb3JtLWRhdGE7IGJvdW5kYXJ5PScgKyBib3VuZGFyeVxuICAgICAgICAgICAgfSk7XG5cbiAgICAgICAgICAgIHJldHVybiBodHRwLnB1dChib2R5LCBodHRwT3B0aW9ucyk7XG4gICAgICAgIH0sXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIFJlbW92ZXMgdGhlIGZpbGVcbiAgICAgICAgICogQHBhcmFtICB7U3RyaW5nfSBgZmlsZVBhdGhgIFBhdGggdG8gdGhlIGZpbGVcbiAgICAgICAgICogQHBhcmFtICB7T2JqZWN0fSBgb3B0aW9uc2AgIChPcHRpb25hbCkgT3ZlcnJpZGVzIGZvciBjb25maWd1cmF0aW9uIG9wdGlvbnNcbiAgICAgICAgICovXG4gICAgICAgIHJlbW92ZTogZnVuY3Rpb24gKGZpbGVQYXRoLCBvcHRpb25zKSB7XG4gICAgICAgICAgICB2YXIgcGF0aCA9IHNlcnZpY2VPcHRpb25zLmZvbGRlclR5cGUgKyAnLycgKyBmaWxlUGF0aDtcbiAgICAgICAgICAgIHZhciBodHRwT3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LCBzZXJ2aWNlT3B0aW9ucywgb3B0aW9ucywge1xuICAgICAgICAgICAgICAgIHVybDogdXJsQ29uZmlnLmdldEFQSVBhdGgoJ2ZpbGUnKSArIHBhdGhcbiAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgcmV0dXJuIGh0dHAuZGVsZXRlKG51bGwsIGh0dHBPcHRpb25zKTtcbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgICogUmVuYW1lIHRoZSBmaWxlXG4gICAgICAgICAqIEBwYXJhbSAge1N0cmluZ30gZmlsZVBhdGggUGF0aCB0byB0aGUgZmlsZVxuICAgICAgICAgKiBAcGFyYW0gIHtTdGlybmd9IG5ld05hbWUgIE5ldyBuYW1lIG9mIGZpbGVcbiAgICAgICAgICogQHBhcmFtICB7T2JqZWN0fSBvcHRpb25zICAoT3B0aW9uYWwpIE92ZXJyaWRlcyBmb3IgY29uZmlndXJhdGlvbiBvcHRpb25zXG4gICAgICAgICAqL1xuICAgICAgICByZW5hbWU6IGZ1bmN0aW9uIChmaWxlUGF0aCwgbmV3TmFtZSwgb3B0aW9ucykge1xuICAgICAgICAgICAgdmFyIHBhdGggPSBzZXJ2aWNlT3B0aW9ucy5mb2xkZXJUeXBlICsgJy8nICsgZmlsZVBhdGg7XG4gICAgICAgICAgICB2YXIgaHR0cE9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSwgc2VydmljZU9wdGlvbnMsIG9wdGlvbnMsIHtcbiAgICAgICAgICAgICAgICB1cmw6IHVybENvbmZpZy5nZXRBUElQYXRoKCdmaWxlJykgKyBwYXRoXG4gICAgICAgICAgICB9KTtcbiAgICAgICAgICAgIHJldHVybiBodHRwLnBhdGNoKHsgJ25hbWUnOiBuZXdOYW1lIH0sIGh0dHBPcHRpb25zKTtcbiAgICAgICAgfVxuICAgIH07XG5cbiAgICAkLmV4dGVuZCh0aGlzLCBwdWJsaWNBc3luY0FQSSk7XG59O1xuIiwiLyoqXG4gKiAjIyBBc3NldCBBUEkgQWRhcHRlclxuICpcbiAqIFRoZSBBc3NldCBBUEkgQWRhcHRlciBhbGxvd3MgeW91IHRvIHN0b3JlIGFzc2V0cyAtLSByZXNvdXJjZXMgb3IgZmlsZXMgb2YgYW55IGtpbmQgLS0gdXNlZCBieSBhIHByb2plY3Qgd2l0aCBhIHNjb3BlIHRoYXQgaXMgc3BlY2lmaWMgdG8gcHJvamVjdCwgZ3JvdXAsIG9yIGVuZCB1c2VyLlxuICpcbiAqIEFzc2V0cyBhcmUgdXNlZCB3aXRoIFt0ZWFtIHByb2plY3RzXSguLi8uLi8uLi9wcm9qZWN0X2FkbWluLyN0ZWFtKS4gT25lIGNvbW1vbiB1c2UgY2FzZSBpcyBoYXZpbmcgZW5kIHVzZXJzIGluIGEgW2dyb3VwXSguLi8uLi8uLi9nbG9zc2FyeS8jZ3JvdXBzKSBvciBpbiBhIFttdWx0aXBsYXllciB3b3JsZF0oLi4vLi4vLi4vZ2xvc3NhcnkvI3dvcmxkKSB1cGxvYWQgZGF0YSAtLSB2aWRlb3MgY3JlYXRlZCBkdXJpbmcgZ2FtZSBwbGF5LCBwcm9maWxlIHBpY3R1cmVzIGZvciBjdXN0b21pemluZyB0aGVpciBleHBlcmllbmNlLCBldGMuIC0tIGFzIHBhcnQgb2YgcGxheWluZyB0aHJvdWdoIHRoZSBwcm9qZWN0LlxuICpcbiAqIFJlc291cmNlcyBjcmVhdGVkIHVzaW5nIHRoZSBBc3NldCBBZGFwdGVyIGFyZSBzY29wZWQ6XG4gKlxuICogICogUHJvamVjdCBhc3NldHMgYXJlIHdyaXRhYmxlIG9ubHkgYnkgW3RlYW0gbWVtYmVyc10oLi4vLi4vLi4vZ2xvc3NhcnkvI3RlYW0pLCB0aGF0IGlzLCBFcGljZW50ZXIgYXV0aG9ycy5cbiAqICAqIEdyb3VwIGFzc2V0cyBhcmUgd3JpdGFibGUgYnkgYW55b25lIHdpdGggYWNjZXNzIHRvIHRoZSBwcm9qZWN0IHRoYXQgaXMgcGFydCBvZiB0aGF0IHBhcnRpY3VsYXIgW2dyb3VwXSguLi8uLi8uLi9nbG9zc2FyeS8jZ3JvdXBzKS4gVGhpcyBpbmNsdWRlcyBhbGwgW3RlYW0gbWVtYmVyc10oLi4vLi4vLi4vZ2xvc3NhcnkvI3RlYW0pIChFcGljZW50ZXIgYXV0aG9ycykgYW5kIGFueSBbZW5kIHVzZXJzXSguLi8uLi8uLi9nbG9zc2FyeS8jdXNlcnMpIHdobyBhcmUgbWVtYmVycyBvZiB0aGUgZ3JvdXAgLS0gYm90aCBmYWNpbGl0YXRvcnMgYW5kIHN0YW5kYXJkIGVuZCB1c2Vycy5cbiAqICAqIFVzZXIgYXNzZXRzIGFyZSB3cml0YWJsZSBieSB0aGUgc3BlY2lmaWMgZW5kIHVzZXIsIGFuZCBieSB0aGUgZmFjaWxpdGF0b3Igb2YgdGhlIGdyb3VwLlxuICogICogQWxsIGFzc2V0cyBhcmUgcmVhZGFibGUgYnkgYW55b25lIHdpdGggdGhlIGV4YWN0IFVSSS5cbiAqXG4gKiBUbyB1c2UgdGhlIEFzc2V0IEFkYXB0ZXIsIGluc3RhbnRpYXRlIGl0IGFuZCB0aGVuIGFjY2VzcyB0aGUgbWV0aG9kcyBwcm92aWRlZC4gSW5zdGFudGlhdGluZyByZXF1aXJlcyB0aGUgYWNjb3VudCBpZCAoKipUZWFtIElEKiogaW4gdGhlIEVwaWNlbnRlciB1c2VyIGludGVyZmFjZSkgYW5kIHByb2plY3QgaWQgKCoqUHJvamVjdCBJRCoqKS4gVGhlIGdyb3VwIG5hbWUgaXMgcmVxdWlyZWQgZm9yIGFzc2V0cyB3aXRoIGEgZ3JvdXAgc2NvcGUsIGFuZCB0aGUgZ3JvdXAgbmFtZSBhbmQgdXNlcklkIGFyZSByZXF1aXJlZCBmb3IgYXNzZXRzIHdpdGggYSB1c2VyIHNjb3BlLiBJZiBub3QgaW5jbHVkZWQsIHRoZXkgYXJlIHRha2VuIGZyb20gdGhlIGxvZ2dlZCBpbiB1c2VyJ3Mgc2Vzc2lvbiBpbmZvcm1hdGlvbiBpZiBuZWVkZWQuXG4gKlxuICogV2hlbiBjcmVhdGluZyBhbiBhc3NldCwgeW91IGNhbiBwYXNzIGluIHRleHQgKGVuY29kZWQgZGF0YSkgdG8gdGhlIGBjcmVhdGUoKWAgY2FsbC4gQWx0ZXJuYXRpdmVseSwgeW91IGNhbiBtYWtlIHRoZSBgY3JlYXRlKClgIGNhbGwgYXMgcGFydCBvZiBhbiBIVE1MIGZvcm0gYW5kIHBhc3MgaW4gYSBmaWxlIHVwbG9hZGVkIHZpYSB0aGUgZm9ybS5cbiAqXG4gKiAgICAgICAvLyBpbnN0YW50aWF0ZSB0aGUgQXNzZXQgQWRhcHRlclxuICogICAgICAgdmFyIGFhID0gbmV3IEYuc2VydmljZS5Bc3NldCh7XG4gKiAgICAgICAgICBhY2NvdW50OiAnYWNtZS1zaW11bGF0aW9ucycsXG4gKiAgICAgICAgICBwcm9qZWN0OiAnc3VwcGx5LWNoYWluLWdhbWUnLFxuICogICAgICAgICAgZ3JvdXA6ICd0ZWFtMScsXG4gKiAgICAgICAgICB1c2VySWQ6ICcxMjM0NSdcbiAqICAgICAgIH0pO1xuICpcbiAqICAgICAgIC8vIGNyZWF0ZSBhIG5ldyBhc3NldCB1c2luZyBlbmNvZGVkIHRleHRcbiAqICAgICAgIGFhLmNyZWF0ZSgndGVzdC50eHQnLCB7XG4gKiAgICAgICAgICAgZW5jb2Rpbmc6ICdCQVNFXzY0JyxcbiAqICAgICAgICAgICBkYXRhOiAnVkdocGN5QnBjeUJoSUhSbGMzUWdabWxzWlM0PScsXG4gKiAgICAgICAgICAgY29udGVudFR5cGU6ICd0ZXh0L3BsYWluJ1xuICogICAgICAgfSwgeyBzY29wZTogJ3VzZXInIH0pO1xuICpcbiAqICAgICAgIC8vIGFsdGVybmF0aXZlbHksIGNyZWF0ZSBhIG5ldyBhc3NldCB1c2luZyBhIGZpbGUgdXBsb2FkZWQgdGhyb3VnaCBhIGZvcm1cbiAqICAgICAgIC8vIHRoaXMgc2FtcGxlIGNvZGUgZ29lcyB3aXRoIGFuIGh0bWwgZm9ybSB0aGF0IGxvb2tzIGxpa2UgdGhpczpcbiAqICAgICAgIC8vXG4gKiAgICAgICAvLyA8Zm9ybSBpZD1cInVwbG9hZC1maWxlXCI+XG4gKiAgICAgICAvLyAgIDxpbnB1dCBpZD1cImZpbGVcIiB0eXBlPVwiZmlsZVwiPlxuICogICAgICAgLy8gICA8aW5wdXQgaWQ9XCJmaWxlbmFtZVwiIHR5cGU9XCJ0ZXh0XCIgdmFsdWU9XCJteUZpbGUudHh0XCI+XG4gKiAgICAgICAvLyAgIDxidXR0b24gdHlwZT1cInN1Ym1pdFwiPlVwbG9hZCBteUZpbGU8L2J1dHRvbj5cbiAqICAgICAgIC8vIDwvZm9ybT5cbiAqICAgICAgIC8vXG4gKiAgICAgICAkKCcjdXBsb2FkLWZpbGUnKS5vbignc3VibWl0JywgZnVuY3Rpb24gKGUpIHtcbiAqICAgICAgICAgIGUucHJldmVudERlZmF1bHQoKTtcbiAqICAgICAgICAgIHZhciBmaWxlbmFtZSA9ICQoJyNmaWxlbmFtZScpLnZhbCgpO1xuICogICAgICAgICAgdmFyIGRhdGEgPSBuZXcgRm9ybURhdGEoKTtcbiAqICAgICAgICAgIHZhciBpbnB1dENvbnRyb2wgPSAkKCcjZmlsZScpWzBdO1xuICogICAgICAgICAgZGF0YS5hcHBlbmQoJ2ZpbGUnLCBpbnB1dENvbnRyb2wuZmlsZXNbMF0sIGZpbGVuYW1lKTtcbiAqXG4gKiAgICAgICAgICBhYS5jcmVhdGUoZmlsZW5hbWUsIGRhdGEsIHsgc2NvcGU6ICd1c2VyJyB9KTtcbiAqICAgICAgIH0pO1xuICpcbiAqL1xuXG4ndXNlIHN0cmljdCc7XG5cbnZhciBDb25maWdTZXJ2aWNlID0gcmVxdWlyZSgnLi9jb25maWd1cmF0aW9uLXNlcnZpY2UnKTtcbnZhciBUcmFuc3BvcnRGYWN0b3J5ID0gcmVxdWlyZSgnLi4vdHJhbnNwb3J0L2h0dHAtdHJhbnNwb3J0LWZhY3RvcnknKTtcbnZhciBfcGljayA9IHJlcXVpcmUoJy4uL3V0aWwvb2JqZWN0LXV0aWwnKS5fcGljaztcbnZhciBTZXNzaW9uTWFuYWdlciA9IHJlcXVpcmUoJy4uL3N0b3JlL3Nlc3Npb24tbWFuYWdlcicpO1xuXG52YXIgYXBpRW5kcG9pbnQgPSAnYXNzZXQnO1xuXG5tb2R1bGUuZXhwb3J0cyA9IGZ1bmN0aW9uIChjb25maWcpIHtcbiAgICB2YXIgZGVmYXVsdHMgPSB7XG4gICAgICAgIC8qKlxuICAgICAgICAgKiBGb3IgcHJvamVjdHMgdGhhdCByZXF1aXJlIGF1dGhlbnRpY2F0aW9uLCBwYXNzIGluIHRoZSB1c2VyIGFjY2VzcyB0b2tlbiAoZGVmYXVsdHMgdG8gZW1wdHkgc3RyaW5nKS4gSWYgdGhlIHVzZXIgaXMgYWxyZWFkeSBsb2dnZWQgaW4gdG8gRXBpY2VudGVyLCB0aGUgdXNlciBhY2Nlc3MgdG9rZW4gaXMgYWxyZWFkeSBzZXQgaW4gYSBjb29raWUgYW5kIGF1dG9tYXRpY2FsbHkgbG9hZGVkIGZyb20gdGhlcmUuIChTZWUgW21vcmUgYmFja2dyb3VuZCBvbiBhY2Nlc3MgdG9rZW5zXSguLi8uLi8uLi9wcm9qZWN0X2FjY2Vzcy8pKS5cbiAgICAgICAgICogQHNlZSBbQXV0aGVudGljYXRpb24gQVBJIFNlcnZpY2VdKC4uL2F1dGgtYXBpLXNlcnZpY2UvKSBmb3IgZ2V0dGluZyB0b2tlbnMuXG4gICAgICAgICAqIEB0eXBlIHtTdHJpbmd9XG4gICAgICAgICAqL1xuICAgICAgICB0b2tlbjogdW5kZWZpbmVkLFxuICAgICAgICAvKipcbiAgICAgICAgICogVGhlIGFjY291bnQgaWQuIEluIHRoZSBFcGljZW50ZXIgVUksIHRoaXMgaXMgdGhlICoqVGVhbSBJRCoqIChmb3IgdGVhbSBwcm9qZWN0cykuIElmIGxlZnQgdW5kZWZpbmVkLCB0YWtlbiBmcm9tIHRoZSBVUkwuXG4gICAgICAgICAqIEB0eXBlIHtTdHJpbmd9XG4gICAgICAgICAqL1xuICAgICAgICBhY2NvdW50OiB1bmRlZmluZWQsXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBUaGUgcHJvamVjdCBpZC4gSWYgbGVmdCB1bmRlZmluZWQsIHRha2VuIGZyb20gdGhlIFVSTC5cbiAgICAgICAgICogQHR5cGUge1N0cmluZ31cbiAgICAgICAgICovXG4gICAgICAgIHByb2plY3Q6IHVuZGVmaW5lZCxcbiAgICAgICAgLyoqXG4gICAgICAgICAqIFRoZSBncm91cCBuYW1lLiBEZWZhdWx0cyB0byBzZXNzaW9uJ3MgYGdyb3VwTmFtZWAuXG4gICAgICAgICAqIEB0eXBlIHtTdHJpbmd9XG4gICAgICAgICAqL1xuICAgICAgICBncm91cDogdW5kZWZpbmVkLFxuICAgICAgICAvKipcbiAgICAgICAgICogVGhlIHVzZXIgaWQuIERlZmF1bHRzIHRvIHNlc3Npb24ncyBgdXNlcklkYC5cbiAgICAgICAgICogQHR5cGUge1N0cmluZ31cbiAgICAgICAgICovXG4gICAgICAgIHVzZXJJZDogdW5kZWZpbmVkLFxuICAgICAgICAvKipcbiAgICAgICAgICogVGhlIHNjb3BlIGZvciB0aGUgYXNzZXQuIFZhbGlkIHZhbHVlcyBhcmU6IGB1c2VyYCwgYGdyb3VwYCwgYW5kIGBwcm9qZWN0YC4gU2VlIGFib3ZlIGZvciB0aGUgcmVxdWlyZWQgcGVybWlzc2lvbnMgdG8gd3JpdGUgdG8gZWFjaCBzY29wZS4gRGVmYXVsdHMgdG8gYHVzZXJgLCBtZWFuaW5nIHRoZSBjdXJyZW50IGVuZCB1c2VyIG9yIGEgZmFjaWxpdGF0b3IgaW4gdGhlIGVuZCB1c2VyJ3MgZ3JvdXAgY2FuIGVkaXQgdGhlIGFzc2V0LlxuICAgICAgICAgKiBAdHlwZSB7U3RyaW5nfVxuICAgICAgICAgKi9cbiAgICAgICAgc2NvcGU6ICd1c2VyJyxcbiAgICAgICAgLyoqXG4gICAgICAgICAqIERldGVybWluZXMgaWYgYSByZXF1ZXN0IHRvIGxpc3QgdGhlIGFzc2V0cyBpbiBhIHNjb3BlIGluY2x1ZGVzIHRoZSBjb21wbGV0ZSBVUkwgZm9yIGVhY2ggYXNzZXQgKGB0cnVlYCksIG9yIG9ubHkgdGhlIGZpbGUgbmFtZXMgb2YgdGhlIGFzc2V0cyAoYGZhbHNlYCkuIERlZmF1bHRzIHRvIGB0cnVlYC5cbiAgICAgICAgICogQHR5cGUge2Jvb2xlYW59XG4gICAgICAgICAqL1xuICAgICAgICBmdWxsVXJsOiB0cnVlLFxuICAgICAgICAvKipcbiAgICAgICAgICogVGhlIHRyYW5zcG9ydCBvYmplY3QgY29udGFpbnMgdGhlIG9wdGlvbnMgcGFzc2VkIHRvIHRoZSBYSFIgcmVxdWVzdC5cbiAgICAgICAgICogQHR5cGUge29iamVjdH1cbiAgICAgICAgICovXG4gICAgICAgIHRyYW5zcG9ydDoge1xuICAgICAgICAgICAgcHJvY2Vzc0RhdGE6IGZhbHNlXG4gICAgICAgIH1cbiAgICB9O1xuICAgIHRoaXMuc2Vzc2lvbk1hbmFnZXIgPSBuZXcgU2Vzc2lvbk1hbmFnZXIoKTtcbiAgICB2YXIgc2VydmljZU9wdGlvbnMgPSB0aGlzLnNlc3Npb25NYW5hZ2VyLmdldE1lcmdlZE9wdGlvbnMoZGVmYXVsdHMsIGNvbmZpZyk7XG4gICAgdmFyIHVybENvbmZpZyA9IG5ldyBDb25maWdTZXJ2aWNlKHNlcnZpY2VPcHRpb25zKS5nZXQoJ3NlcnZlcicpO1xuXG4gICAgaWYgKCFzZXJ2aWNlT3B0aW9ucy5hY2NvdW50KSB7XG4gICAgICAgIHNlcnZpY2VPcHRpb25zLmFjY291bnQgPSB1cmxDb25maWcuYWNjb3VudFBhdGg7XG4gICAgfVxuXG4gICAgaWYgKCFzZXJ2aWNlT3B0aW9ucy5wcm9qZWN0KSB7XG4gICAgICAgIHNlcnZpY2VPcHRpb25zLnByb2plY3QgPSB1cmxDb25maWcucHJvamVjdFBhdGg7XG4gICAgfVxuXG4gICAgdmFyIHRyYW5zcG9ydE9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSwgc2VydmljZU9wdGlvbnMudHJhbnNwb3J0LCB7XG4gICAgICAgIHVybDogdXJsQ29uZmlnLmdldEFQSVBhdGgoYXBpRW5kcG9pbnQpXG4gICAgfSk7XG5cbiAgICBpZiAoc2VydmljZU9wdGlvbnMudG9rZW4pIHtcbiAgICAgICAgdHJhbnNwb3J0T3B0aW9ucy5oZWFkZXJzID0ge1xuICAgICAgICAgICAgJ0F1dGhvcml6YXRpb24nOiAnQmVhcmVyICcgKyBzZXJ2aWNlT3B0aW9ucy50b2tlblxuICAgICAgICB9O1xuICAgIH1cblxuICAgIHZhciBodHRwID0gbmV3IFRyYW5zcG9ydEZhY3RvcnkodHJhbnNwb3J0T3B0aW9ucyk7XG5cbiAgICB2YXIgYXNzZXRBcGlQYXJhbXMgPSBbJ2VuY29kaW5nJywgJ2RhdGEnLCAnY29udGVudFR5cGUnXTtcbiAgICB2YXIgc2NvcGVDb25maWcgPSB7XG4gICAgICAgIHVzZXI6IFsnc2NvcGUnLCAnYWNjb3VudCcsICdwcm9qZWN0JywgJ2dyb3VwJywgJ3VzZXJJZCddLFxuICAgICAgICBncm91cDogWydzY29wZScsICdhY2NvdW50JywgJ3Byb2plY3QnLCAnZ3JvdXAnXSxcbiAgICAgICAgcHJvamVjdDogWydzY29wZScsICdhY2NvdW50JywgJ3Byb2plY3QnXSxcbiAgICB9O1xuXG4gICAgdmFyIHZhbGlkYXRlRmlsZW5hbWUgPSBmdW5jdGlvbiAoZmlsZW5hbWUpIHtcbiAgICAgICAgaWYgKCFmaWxlbmFtZSkge1xuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdmaWxlbmFtZSBpcyBuZWVkZWQuJyk7XG4gICAgICAgIH1cbiAgICB9O1xuXG4gICAgdmFyIHZhbGlkYXRlVXJsUGFyYW1zID0gZnVuY3Rpb24gKG9wdGlvbnMpIHtcbiAgICAgICAgdmFyIHBhcnRLZXlzID0gc2NvcGVDb25maWdbb3B0aW9ucy5zY29wZV07XG4gICAgICAgIGlmICghcGFydEtleXMpIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcignc2NvcGUgcGFyYW1ldGVyIGlzIG5lZWRlZC4nKTtcbiAgICAgICAgfVxuXG4gICAgICAgICQuZWFjaChwYXJ0S2V5cywgZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgaWYgKCFvcHRpb25zW3RoaXNdKSB7XG4gICAgICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKHRoaXMgKyAnIHBhcmFtZXRlciBpcyBuZWVkZWQuJyk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH0pO1xuICAgIH07XG5cbiAgICB2YXIgYnVpbGRVcmwgPSBmdW5jdGlvbiAoZmlsZW5hbWUsIG9wdGlvbnMpIHtcbiAgICAgICAgdmFsaWRhdGVVcmxQYXJhbXMob3B0aW9ucyk7XG4gICAgICAgIHZhciBwYXJ0S2V5cyA9IHNjb3BlQ29uZmlnW29wdGlvbnMuc2NvcGVdO1xuICAgICAgICB2YXIgcGFydHMgPSAkLm1hcChwYXJ0S2V5cywgZnVuY3Rpb24gKGtleSkge1xuICAgICAgICAgICAgcmV0dXJuIG9wdGlvbnNba2V5XTtcbiAgICAgICAgfSk7XG4gICAgICAgIGlmIChmaWxlbmFtZSkge1xuICAgICAgICAgICAgLy8gVGhpcyBwcmV2ZW50cyBhZGRpbmcgYSB0cmFpbGluZyAvIGluIHRoZSBVUkwgYXMgdGhlIEFzc2V0IEFQSVxuICAgICAgICAgICAgLy8gZG9lcyBub3Qgd29yayBjb3JyZWN0bHkgd2l0aCBpdFxuICAgICAgICAgICAgZmlsZW5hbWUgPSAnLycgKyBmaWxlbmFtZTtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gdXJsQ29uZmlnLmdldEFQSVBhdGgoYXBpRW5kcG9pbnQpICsgcGFydHMuam9pbignLycpICsgZmlsZW5hbWU7XG4gICAgfTtcblxuICAgIC8vIFByaXZhdGUgZnVuY3Rpb24sIGFsbCByZXF1ZXN0cyBmb2xsb3cgYSBtb3JlIG9yIGxlc3Mgc2FtZSBhcHByb2FjaCB0b1xuICAgIC8vIHVzZSB0aGUgQXNzZXQgQVBJIGFuZCB0aGUgZGlmZmVyZW5jZSBpcyB0aGUgSFRUUCB2ZXJiXG4gICAgLy9cbiAgICAvLyBAcGFyYW0ge3N0cmluZ30gYG1ldGhvZGAgKFJlcXVpcmVkKSBIVFRQIHZlcmJcbiAgICAvLyBAcGFyYW0ge3N0cmluZ30gYGZpbGVuYW1lYCAoUmVxdWlyZWQpIE5hbWUgb2YgdGhlIGZpbGUgdG8gZGVsZXRlL3JlcGxhY2UvY3JlYXRlXG4gICAgLy8gQHBhcmFtIHtvYmplY3R9IGBwYXJhbXNgIChPcHRpb25hbCkgQm9keSBwYXJhbWV0ZXJzIHRvIHNlbmQgdG8gdGhlIEFzc2V0IEFQSVxuICAgIC8vIEBwYXJhbSB7b2JqZWN0fSBgb3B0aW9uc2AgKE9wdGlvbmFsKSBPcHRpb25zIG9iamVjdCB0byBvdmVycmlkZSBnbG9iYWwgb3B0aW9ucy5cbiAgICB2YXIgdXBsb2FkID0gZnVuY3Rpb24gKG1ldGhvZCwgZmlsZW5hbWUsIHBhcmFtcywgb3B0aW9ucykge1xuICAgICAgICB2YWxpZGF0ZUZpbGVuYW1lKGZpbGVuYW1lKTtcbiAgICAgICAgLy8gbWFrZSBzdXJlIHRoZSBwYXJhbWV0ZXIgaXMgY2xlYW5cbiAgICAgICAgbWV0aG9kID0gbWV0aG9kLnRvTG93ZXJDYXNlKCk7XG4gICAgICAgIHZhciBjb250ZW50VHlwZSA9IHBhcmFtcyBpbnN0YW5jZW9mIEZvcm1EYXRhID09PSB0cnVlID8gZmFsc2UgOiAnYXBwbGljYXRpb24vanNvbic7XG4gICAgICAgIGlmIChjb250ZW50VHlwZSA9PT0gJ2FwcGxpY2F0aW9uL2pzb24nKSB7XG4gICAgICAgICAgICAvLyB3aGl0ZWxpc3QgdGhlIGZpZWxkcyB0aGF0IHdlIGFjdHVhbGx5IGNhbiBzZW5kIHRvIHRoZSBhcGlcbiAgICAgICAgICAgIHBhcmFtcyA9IF9waWNrKHBhcmFtcywgYXNzZXRBcGlQYXJhbXMpO1xuICAgICAgICB9IGVsc2UgeyAvLyBlbHNlIHdlJ3JlIHNlbmRpbmcgZm9ybSBkYXRhIHdoaWNoIGdvZXMgZGlyZWN0bHkgaW4gcmVxdWVzdCBib2R5XG4gICAgICAgICAgICAvLyBGb3IgbXVsdGlwYXJ0L2Zvcm0tZGF0YSB1cGxvYWRzIHRoZSBmaWxlbmFtZSBpcyBub3Qgc2V0IGluIHRoZSBVUkwsXG4gICAgICAgICAgICAvLyBpdCdzIGdldHRpbmcgcGlja2VkIGJ5IHRoZSBGb3JtRGF0YSBmaWVsZCBmaWxlbmFtZS5cbiAgICAgICAgICAgIGZpbGVuYW1lID0gbWV0aG9kID09PSAncG9zdCcgfHwgbWV0aG9kID09PSAncHV0JyA/ICcnIDogZmlsZW5hbWU7XG4gICAgICAgIH1cbiAgICAgICAgdmFyIHVybE9wdGlvbnMgPSAkLmV4dGVuZCh7fSwgc2VydmljZU9wdGlvbnMsIG9wdGlvbnMpO1xuICAgICAgICB2YXIgdXJsID0gYnVpbGRVcmwoZmlsZW5hbWUsIHVybE9wdGlvbnMpO1xuICAgICAgICB2YXIgY3JlYXRlT3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LCB1cmxPcHRpb25zLCB7IHVybDogdXJsLCBjb250ZW50VHlwZTogY29udGVudFR5cGUgfSk7XG5cbiAgICAgICAgcmV0dXJuIGh0dHBbbWV0aG9kXShwYXJhbXMsIGNyZWF0ZU9wdGlvbnMpO1xuICAgIH07XG5cbiAgICB2YXIgcHVibGljQVBJID0ge1xuICAgICAgICAvKipcbiAgICAgICAgKiBDcmVhdGVzIGEgZmlsZSBpbiB0aGUgQXNzZXQgQVBJLiBUaGUgc2VydmVyIHJldHVybnMgYW4gZXJyb3IgKHN0YXR1cyBjb2RlIGA0MDlgLCBjb25mbGljdCkgaWYgdGhlIGZpbGUgYWxyZWFkeSBleGlzdHMsIHNvXG4gICAgICAgICogY2hlY2sgZmlyc3Qgd2l0aCBhIGBsaXN0KClgIG9yIGEgYGdldCgpYC5cbiAgICAgICAgKlxuICAgICAgICAqICAqKkV4YW1wbGUqKlxuICAgICAgICAqXG4gICAgICAgICogICAgICAgdmFyIGFhID0gbmV3IEYuc2VydmljZS5Bc3NldCh7XG4gICAgICAgICogICAgICAgICAgYWNjb3VudDogJ2FjbWUtc2ltdWxhdGlvbnMnLFxuICAgICAgICAqICAgICAgICAgIHByb2plY3Q6ICdzdXBwbHktY2hhaW4tZ2FtZScsXG4gICAgICAgICogICAgICAgICAgZ3JvdXA6ICd0ZWFtMScsXG4gICAgICAgICogICAgICAgICAgdXNlcklkOiAnJ1xuICAgICAgICAqICAgICAgIH0pO1xuICAgICAgICAqXG4gICAgICAgICogICAgICAgLy8gY3JlYXRlIGEgbmV3IGFzc2V0IHVzaW5nIGVuY29kZWQgdGV4dFxuICAgICAgICAqICAgICAgIGFhLmNyZWF0ZSgndGVzdC50eHQnLCB7XG4gICAgICAgICogICAgICAgICAgIGVuY29kaW5nOiAnQkFTRV82NCcsXG4gICAgICAgICogICAgICAgICAgIGRhdGE6ICdWR2hwY3lCcGN5QmhJSFJsYzNRZ1ptbHNaUzQ9JyxcbiAgICAgICAgKiAgICAgICAgICAgY29udGVudFR5cGU6ICd0ZXh0L3BsYWluJ1xuICAgICAgICAqICAgICAgIH0sIHsgc2NvcGU6ICd1c2VyJyB9KTtcbiAgICAgICAgKlxuICAgICAgICAqICAgICAgIC8vIGFsdGVybmF0aXZlbHksIGNyZWF0ZSBhIG5ldyBhc3NldCB1c2luZyBhIGZpbGUgdXBsb2FkZWQgdGhyb3VnaCBhIGZvcm1cbiAgICAgICAgKiAgICAgICAvLyB0aGlzIHNhbXBsZSBjb2RlIGdvZXMgd2l0aCBhbiBodG1sIGZvcm0gdGhhdCBsb29rcyBsaWtlIHRoaXM6XG4gICAgICAgICogICAgICAgLy9cbiAgICAgICAgKiAgICAgICAvLyA8Zm9ybSBpZD1cInVwbG9hZC1maWxlXCI+XG4gICAgICAgICogICAgICAgLy8gICA8aW5wdXQgaWQ9XCJmaWxlXCIgdHlwZT1cImZpbGVcIj5cbiAgICAgICAgKiAgICAgICAvLyAgIDxpbnB1dCBpZD1cImZpbGVuYW1lXCIgdHlwZT1cInRleHRcIiB2YWx1ZT1cIm15RmlsZS50eHRcIj5cbiAgICAgICAgKiAgICAgICAvLyAgIDxidXR0b24gdHlwZT1cInN1Ym1pdFwiPlVwbG9hZCBteUZpbGU8L2J1dHRvbj5cbiAgICAgICAgKiAgICAgICAvLyA8L2Zvcm0+XG4gICAgICAgICogICAgICAgLy9cbiAgICAgICAgKiAgICAgICAkKCcjdXBsb2FkLWZpbGUnKS5vbignc3VibWl0JywgZnVuY3Rpb24gKGUpIHtcbiAgICAgICAgKiAgICAgICAgICBlLnByZXZlbnREZWZhdWx0KCk7XG4gICAgICAgICogICAgICAgICAgdmFyIGZpbGVuYW1lID0gJCgnI2ZpbGVuYW1lJykudmFsKCk7XG4gICAgICAgICogICAgICAgICAgdmFyIGRhdGEgPSBuZXcgRm9ybURhdGEoKTtcbiAgICAgICAgKiAgICAgICAgICB2YXIgaW5wdXRDb250cm9sID0gJCgnI2ZpbGUnKVswXTtcbiAgICAgICAgKiAgICAgICAgICBkYXRhLmFwcGVuZCgnZmlsZScsIGlucHV0Q29udHJvbC5maWxlc1swXSwgZmlsZW5hbWUpO1xuICAgICAgICAqXG4gICAgICAgICogICAgICAgICAgYWEuY3JlYXRlKGZpbGVuYW1lLCBkYXRhLCB7IHNjb3BlOiAndXNlcicgfSk7XG4gICAgICAgICogICAgICAgfSk7XG4gICAgICAgICpcbiAgICAgICAgKlxuICAgICAgICAqICAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAqIEBwYXJhbSB7c3RyaW5nfSBgZmlsZW5hbWVgIChSZXF1aXJlZCkgTmFtZSBvZiB0aGUgZmlsZSB0byBjcmVhdGUuXG4gICAgICAgICogQHBhcmFtIHtvYmplY3R9IGBwYXJhbXNgIChPcHRpb25hbCkgQm9keSBwYXJhbWV0ZXJzIHRvIHNlbmQgdG8gdGhlIEFzc2V0IEFQSS4gUmVxdWlyZWQgaWYgdGhlIGBvcHRpb25zLnRyYW5zcG9ydC5jb250ZW50VHlwZWAgaXMgYGFwcGxpY2F0aW9uL2pzb25gLCBvdGhlcndpc2UgaWdub3JlZC5cbiAgICAgICAgKiBAcGFyYW0ge3N0cmluZ30gYHBhcmFtcy5lbmNvZGluZ2AgRWl0aGVyIGBIRVhgIG9yIGBCQVNFXzY0YC4gUmVxdWlyZWQgaWYgYG9wdGlvbnMudHJhbnNwb3J0LmNvbnRlbnRUeXBlYCBpcyBgYXBwbGljYXRpb24vanNvbmAuXG4gICAgICAgICogQHBhcmFtIHtzdHJpbmd9IGBwYXJhbXMuZGF0YWAgVGhlIGVuY29kZWQgZGF0YSBmb3IgdGhlIGZpbGUuIFJlcXVpcmVkIGlmIGBvcHRpb25zLnRyYW5zcG9ydC5jb250ZW50VHlwZWAgaXMgYGFwcGxpY2F0aW9uL2pzb25gLlxuICAgICAgICAqIEBwYXJhbSB7c3RyaW5nfSBgcGFyYW1zLmNvbnRlbnRUeXBlYCBUaGUgbWltZSB0eXBlIG9mIHRoZSBmaWxlLiBPcHRpb25hbC5cbiAgICAgICAgKiBAcGFyYW0ge29iamVjdH0gYG9wdGlvbnNgIChPcHRpb25hbCkgT3B0aW9ucyBvYmplY3QgdG8gb3ZlcnJpZGUgZ2xvYmFsIG9wdGlvbnMuXG4gICAgICAgICpcbiAgICAgICAgKi9cbiAgICAgICAgY3JlYXRlOiBmdW5jdGlvbiAoZmlsZW5hbWUsIHBhcmFtcywgb3B0aW9ucykge1xuICAgICAgICAgICAgcmV0dXJuIHVwbG9hZCgncG9zdCcsIGZpbGVuYW1lLCBwYXJhbXMsIG9wdGlvbnMpO1xuICAgICAgICB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAqIEdldHMgYSBmaWxlIGZyb20gdGhlIEFzc2V0IEFQSSwgZmV0Y2hpbmcgdGhlIGFzc2V0IGNvbnRlbnQuIChUbyBnZXQgYSBsaXN0XG4gICAgICAgICogb2YgdGhlIGFzc2V0cyBpbiBhIHNjb3BlLCB1c2UgYGxpc3QoKWAuKVxuICAgICAgICAqXG4gICAgICAgICogICoqUGFyYW1ldGVycyoqXG4gICAgICAgICogQHBhcmFtIHtzdHJpbmd9IGBmaWxlbmFtZWAgKFJlcXVpcmVkKSBOYW1lIG9mIHRoZSBmaWxlIHRvIHJldHJpZXZlLlxuICAgICAgICAqIEBwYXJhbSB7b2JqZWN0fSBgb3B0aW9uc2AgKE9wdGlvbmFsKSBPcHRpb25zIG9iamVjdCB0byBvdmVycmlkZSBnbG9iYWwgb3B0aW9ucy5cbiAgICAgICAgKlxuICAgICAgICAqL1xuICAgICAgICBnZXQ6IGZ1bmN0aW9uIChmaWxlbmFtZSwgb3B0aW9ucykge1xuICAgICAgICAgICAgdmFyIGdldFNlcnZpY2VPcHRpb25zID0gX3BpY2soc2VydmljZU9wdGlvbnMsIFsnc2NvcGUnLCAnYWNjb3VudCcsICdwcm9qZWN0JywgJ2dyb3VwJywgJ3VzZXJJZCddKTtcbiAgICAgICAgICAgIHZhciB1cmxPcHRpb25zID0gJC5leHRlbmQoe30sIGdldFNlcnZpY2VPcHRpb25zLCBvcHRpb25zKTtcbiAgICAgICAgICAgIHZhciB1cmwgPSBidWlsZFVybChmaWxlbmFtZSwgdXJsT3B0aW9ucyk7XG4gICAgICAgICAgICB2YXIgZ2V0T3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LCB1cmxPcHRpb25zLCB7IHVybDogdXJsIH0pO1xuXG4gICAgICAgICAgICByZXR1cm4gaHR0cC5nZXQoe30sIGdldE9wdGlvbnMpO1xuICAgICAgICB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAqIEdldHMgdGhlIGxpc3Qgb2YgdGhlIGFzc2V0cyBpbiBhIHNjb3BlLlxuICAgICAgICAqXG4gICAgICAgICogKipFeGFtcGxlKipcbiAgICAgICAgKlxuICAgICAgICAqICAgICAgIGFhLmxpc3QoeyBmdWxsVXJsOiB0cnVlIH0pLnRoZW4oZnVuY3Rpb24oZmlsZUxpc3Qpe1xuICAgICAgICAqICAgICAgICAgICBjb25zb2xlLmxvZygnYXJyYXkgb2YgZmlsZXMgPSAnLCBmaWxlTGlzdCk7XG4gICAgICAgICogICAgICAgfSk7XG4gICAgICAgICpcbiAgICAgICAgKiAgKipQYXJhbWV0ZXJzKipcbiAgICAgICAgKiBAcGFyYW0ge29iamVjdH0gYG9wdGlvbnNgIChPcHRpb25hbCkgT3B0aW9ucyBvYmplY3QgdG8gb3ZlcnJpZGUgZ2xvYmFsIG9wdGlvbnMuXG4gICAgICAgICogQHBhcmFtIHtzdHJpbmd9IGBvcHRpb25zLnNjb3BlYCAoT3B0aW9uYWwpIFRoZSBzY29wZSAoYHVzZXJgLCBgZ3JvdXBgLCBgcHJvamVjdGApLlxuICAgICAgICAqIEBwYXJhbSB7Ym9vbGVhbn0gYG9wdGlvbnMuZnVsbFVybGAgKE9wdGlvbmFsKSBEZXRlcm1pbmVzIGlmIHRoZSBsaXN0IG9mIGFzc2V0cyBpbiBhIHNjb3BlIGluY2x1ZGVzIHRoZSBjb21wbGV0ZSBVUkwgZm9yIGVhY2ggYXNzZXQgKGB0cnVlYCksIG9yIG9ubHkgdGhlIGZpbGUgbmFtZXMgb2YgdGhlIGFzc2V0cyAoYGZhbHNlYCkuXG4gICAgICAgICpcbiAgICAgICAgKi9cbiAgICAgICAgbGlzdDogZnVuY3Rpb24gKG9wdGlvbnMpIHtcbiAgICAgICAgICAgIHZhciBkdGQgPSAkLkRlZmVycmVkKCk7XG4gICAgICAgICAgICB2YXIgbWUgPSB0aGlzO1xuICAgICAgICAgICAgdmFyIHVybE9wdGlvbnMgPSAkLmV4dGVuZCh7fSwgc2VydmljZU9wdGlvbnMsIG9wdGlvbnMpO1xuICAgICAgICAgICAgdmFyIHVybCA9IGJ1aWxkVXJsKCcnLCB1cmxPcHRpb25zKTtcbiAgICAgICAgICAgIHZhciBnZXRPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sIHVybE9wdGlvbnMsIHsgdXJsOiB1cmwgfSk7XG4gICAgICAgICAgICB2YXIgZnVsbFVybCA9IGdldE9wdGlvbnMuZnVsbFVybDtcblxuICAgICAgICAgICAgaWYgKCFmdWxsVXJsKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIGh0dHAuZ2V0KHt9LCBnZXRPcHRpb25zKTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgaHR0cC5nZXQoe30sIGdldE9wdGlvbnMpXG4gICAgICAgICAgICAgICAgLnRoZW4oZnVuY3Rpb24gKGZpbGVzKSB7XG4gICAgICAgICAgICAgICAgICAgIHZhciBmdWxsUGF0aEZpbGVzID0gJC5tYXAoZmlsZXMsIGZ1bmN0aW9uIChmaWxlKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICByZXR1cm4gYnVpbGRVcmwoZmlsZSwgdXJsT3B0aW9ucyk7XG4gICAgICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICAgICAgICBkdGQucmVzb2x2ZShmdWxsUGF0aEZpbGVzLCBtZSk7XG4gICAgICAgICAgICAgICAgfSlcbiAgICAgICAgICAgICAgICAuZmFpbChkdGQucmVqZWN0KTtcblxuICAgICAgICAgICAgcmV0dXJuIGR0ZC5wcm9taXNlKCk7XG4gICAgICAgIH0sXG5cbiAgICAgICAgLyoqXG4gICAgICAgICogUmVwbGFjZXMgYW4gZXhpc3RpbmcgZmlsZSBpbiB0aGUgQXNzZXQgQVBJLlxuICAgICAgICAqXG4gICAgICAgICogKipFeGFtcGxlKipcbiAgICAgICAgKlxuICAgICAgICAqICAgICAgIC8vIHJlcGxhY2UgYW4gYXNzZXQgdXNpbmcgZW5jb2RlZCB0ZXh0XG4gICAgICAgICogICAgICAgYWEucmVwbGFjZSgndGVzdC50eHQnLCB7XG4gICAgICAgICogICAgICAgICAgIGVuY29kaW5nOiAnQkFTRV82NCcsXG4gICAgICAgICogICAgICAgICAgIGRhdGE6ICdWR2hwY3lCcGN5QmhJSE5sWTI5dVpDQjBaWE4wSUdacGJHVXUnLFxuICAgICAgICAqICAgICAgICAgICBjb250ZW50VHlwZTogJ3RleHQvcGxhaW4nXG4gICAgICAgICogICAgICAgfSwgeyBzY29wZTogJ3VzZXInIH0pO1xuICAgICAgICAqXG4gICAgICAgICogICAgICAgLy8gYWx0ZXJuYXRpdmVseSwgcmVwbGFjZSBhbiBhc3NldCB1c2luZyBhIGZpbGUgdXBsb2FkZWQgdGhyb3VnaCBhIGZvcm1cbiAgICAgICAgKiAgICAgICAvLyB0aGlzIHNhbXBsZSBjb2RlIGdvZXMgd2l0aCBhbiBodG1sIGZvcm0gdGhhdCBsb29rcyBsaWtlIHRoaXM6XG4gICAgICAgICogICAgICAgLy9cbiAgICAgICAgKiAgICAgICAvLyA8Zm9ybSBpZD1cInJlcGxhY2UtZmlsZVwiPlxuICAgICAgICAqICAgICAgIC8vICAgPGlucHV0IGlkPVwiZmlsZVwiIHR5cGU9XCJmaWxlXCI+XG4gICAgICAgICogICAgICAgLy8gICA8aW5wdXQgaWQ9XCJyZXBsYWNlLWZpbGVuYW1lXCIgdHlwZT1cInRleHRcIiB2YWx1ZT1cIm15RmlsZS50eHRcIj5cbiAgICAgICAgKiAgICAgICAvLyAgIDxidXR0b24gdHlwZT1cInN1Ym1pdFwiPlJlcGxhY2UgbXlGaWxlPC9idXR0b24+XG4gICAgICAgICogICAgICAgLy8gPC9mb3JtPlxuICAgICAgICAqICAgICAgIC8vXG4gICAgICAgICogICAgICAgJCgnI3JlcGxhY2UtZmlsZScpLm9uKCdzdWJtaXQnLCBmdW5jdGlvbiAoZSkge1xuICAgICAgICAqICAgICAgICAgIGUucHJldmVudERlZmF1bHQoKTtcbiAgICAgICAgKiAgICAgICAgICB2YXIgZmlsZW5hbWUgPSAkKCcjcmVwbGFjZS1maWxlbmFtZScpLnZhbCgpO1xuICAgICAgICAqICAgICAgICAgIHZhciBkYXRhID0gbmV3IEZvcm1EYXRhKCk7XG4gICAgICAgICogICAgICAgICAgdmFyIGlucHV0Q29udHJvbCA9ICQoJyNmaWxlJylbMF07XG4gICAgICAgICogICAgICAgICAgZGF0YS5hcHBlbmQoJ2ZpbGUnLCBpbnB1dENvbnRyb2wuZmlsZXNbMF0sIGZpbGVuYW1lKTtcbiAgICAgICAgKlxuICAgICAgICAqICAgICAgICAgIGFhLnJlcGxhY2UoZmlsZW5hbWUsIGRhdGEsIHsgc2NvcGU6ICd1c2VyJyB9KTtcbiAgICAgICAgKiAgICAgICB9KTtcbiAgICAgICAgKlxuICAgICAgICAqICAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAqIEBwYXJhbSB7c3RyaW5nfSBgZmlsZW5hbWVgIChSZXF1aXJlZCkgTmFtZSBvZiB0aGUgZmlsZSBiZWluZyByZXBsYWNlZC5cbiAgICAgICAgKiBAcGFyYW0ge29iamVjdH0gYHBhcmFtc2AgKE9wdGlvbmFsKSBCb2R5IHBhcmFtZXRlcnMgdG8gc2VuZCB0byB0aGUgQXNzZXQgQVBJLiBSZXF1aXJlZCBpZiB0aGUgYG9wdGlvbnMudHJhbnNwb3J0LmNvbnRlbnRUeXBlYCBpcyBgYXBwbGljYXRpb24vanNvbmAsIG90aGVyd2lzZSBpZ25vcmVkLlxuICAgICAgICAqIEBwYXJhbSB7c3RyaW5nfSBgcGFyYW1zLmVuY29kaW5nYCBFaXRoZXIgYEhFWGAgb3IgYEJBU0VfNjRgLiBSZXF1aXJlZCBpZiBgb3B0aW9ucy50cmFuc3BvcnQuY29udGVudFR5cGVgIGlzIGBhcHBsaWNhdGlvbi9qc29uYC5cbiAgICAgICAgKiBAcGFyYW0ge3N0cmluZ30gYHBhcmFtcy5kYXRhYCBUaGUgZW5jb2RlZCBkYXRhIGZvciB0aGUgZmlsZS4gUmVxdWlyZWQgaWYgYG9wdGlvbnMudHJhbnNwb3J0LmNvbnRlbnRUeXBlYCBpcyBgYXBwbGljYXRpb24vanNvbmAuXG4gICAgICAgICogQHBhcmFtIHtzdHJpbmd9IGBwYXJhbXMuY29udGVudFR5cGVgIFRoZSBtaW1lIHR5cGUgb2YgdGhlIGZpbGUuIE9wdGlvbmFsLlxuICAgICAgICAqIEBwYXJhbSB7b2JqZWN0fSBgb3B0aW9uc2AgKE9wdGlvbmFsKSBPcHRpb25zIG9iamVjdCB0byBvdmVycmlkZSBnbG9iYWwgb3B0aW9ucy5cbiAgICAgICAgKlxuICAgICAgICAqL1xuICAgICAgICByZXBsYWNlOiBmdW5jdGlvbiAoZmlsZW5hbWUsIHBhcmFtcywgb3B0aW9ucykge1xuICAgICAgICAgICAgcmV0dXJuIHVwbG9hZCgncHV0JywgZmlsZW5hbWUsIHBhcmFtcywgb3B0aW9ucyk7XG4gICAgICAgIH0sXG5cbiAgICAgICAgLyoqXG4gICAgICAgICogRGVsZXRlcyBhIGZpbGUgZnJvbSB0aGUgQXNzZXQgQVBJLlxuICAgICAgICAqXG4gICAgICAgICogKipFeGFtcGxlKipcbiAgICAgICAgKlxuICAgICAgICAqICAgICAgIGFhLmRlbGV0ZShzYW1wbGVGaWxlTmFtZSk7XG4gICAgICAgICpcbiAgICAgICAgKiAgKipQYXJhbWV0ZXJzKipcbiAgICAgICAgKiBAcGFyYW0ge3N0cmluZ30gYGZpbGVuYW1lYCAoUmVxdWlyZWQpIE5hbWUgb2YgdGhlIGZpbGUgdG8gZGVsZXRlLlxuICAgICAgICAqIEBwYXJhbSB7b2JqZWN0fSBgb3B0aW9uc2AgKE9wdGlvbmFsKSBPcHRpb25zIG9iamVjdCB0byBvdmVycmlkZSBnbG9iYWwgb3B0aW9ucy5cbiAgICAgICAgKlxuICAgICAgICAqL1xuICAgICAgICBkZWxldGU6IGZ1bmN0aW9uIChmaWxlbmFtZSwgb3B0aW9ucykge1xuICAgICAgICAgICAgcmV0dXJuIHVwbG9hZCgnZGVsZXRlJywgZmlsZW5hbWUsIHt9LCBvcHRpb25zKTtcbiAgICAgICAgfSxcblxuICAgICAgICBhc3NldFVybDogZnVuY3Rpb24gKGZpbGVuYW1lLCBvcHRpb25zKSB7XG4gICAgICAgICAgICB2YXIgdXJsT3B0aW9ucyA9ICQuZXh0ZW5kKHt9LCBzZXJ2aWNlT3B0aW9ucywgb3B0aW9ucyk7XG4gICAgICAgICAgICByZXR1cm4gYnVpbGRVcmwoZmlsZW5hbWUsIHVybE9wdGlvbnMpO1xuICAgICAgICB9XG4gICAgfTtcbiAgICAkLmV4dGVuZCh0aGlzLCBwdWJsaWNBUEkpO1xufTtcbiIsIi8qKlxuICpcbiAqICMjIEF1dGhlbnRpY2F0aW9uIEFQSSBTZXJ2aWNlXG4gKlxuICogVGhlIEF1dGhlbnRpY2F0aW9uIEFQSSBTZXJ2aWNlIHByb3ZpZGVzIGEgbWV0aG9kIGZvciBsb2dnaW5nIGluLCB3aGljaCBjcmVhdGVzIGFuZCByZXR1cm5zIGEgdXNlciBhY2Nlc3MgdG9rZW4uXG4gKlxuICogVXNlciBhY2Nlc3MgdG9rZW5zIGFyZSByZXF1aXJlZCBmb3IgZWFjaCBjYWxsIHRvIEVwaWNlbnRlci4gKFNlZSBbUHJvamVjdCBBY2Nlc3NdKC4uLy4uLy4uL3Byb2plY3RfYWNjZXNzLykgZm9yIG1vcmUgaW5mb3JtYXRpb24uKVxuICpcbiAqIElmIHlvdSBuZWVkIGFkZGl0aW9uYWwgZnVuY3Rpb25hbGl0eSAtLSBzdWNoIGFzIHRyYWNraW5nIHNlc3Npb24gaW5mb3JtYXRpb24sIGVhc2lseSByZXRyaWV2aW5nIHRoZSB1c2VyIHRva2VuLCBvciBnZXR0aW5nIHRoZSBncm91cHMgdG8gd2hpY2ggYW4gZW5kIHVzZXIgYmVsb25ncyAtLSBjb25zaWRlciB1c2luZyB0aGUgW0F1dGhvcml6YXRpb24gTWFuYWdlcl0oLi4vYXV0aC1tYW5hZ2VyLykgaW5zdGVhZC5cbiAqXG4gKiAgICAgIHZhciBhdXRoID0gbmV3IEYuc2VydmljZS5BdXRoKCk7XG4gKiAgICAgIGF1dGgubG9naW4oeyB1c2VyTmFtZTogJ2pzbWl0aEBhY21lc2ltdWxhdGlvbnMuY29tJyxcbiAqICAgICAgICAgICAgICAgICAgcGFzc3dvcmQ6ICdwYXNzdzByZCcgfSk7XG4gKi9cblxuJ3VzZSBzdHJpY3QnO1xuXG52YXIgQ29uZmlnU2VydmljZSA9IHJlcXVpcmUoJy4vY29uZmlndXJhdGlvbi1zZXJ2aWNlJyk7XG52YXIgVHJhbnNwb3J0RmFjdG9yeSA9IHJlcXVpcmUoJy4uL3RyYW5zcG9ydC9odHRwLXRyYW5zcG9ydC1mYWN0b3J5Jyk7XG5cbm1vZHVsZS5leHBvcnRzID0gZnVuY3Rpb24gKGNvbmZpZykge1xuICAgIHZhciBkZWZhdWx0cyA9IHtcbiAgICAgICAgLyoqXG4gICAgICAgICAqIEVtYWlsIG9yIHVzZXJuYW1lIHRvIHVzZSBmb3IgbG9nZ2luZyBpbi4gRGVmYXVsdHMgdG8gZW1wdHkgc3RyaW5nLlxuICAgICAgICAgKiBAdHlwZSB7U3RyaW5nfVxuICAgICAgICAgKi9cbiAgICAgICAgdXNlck5hbWU6ICcnLFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBQYXNzd29yZCBmb3Igc3BlY2lmaWVkIGB1c2VyTmFtZWAuIERlZmF1bHRzIHRvIGVtcHR5IHN0cmluZy5cbiAgICAgICAgICogQHR5cGUge1N0cmluZ31cbiAgICAgICAgICovXG4gICAgICAgIHBhc3N3b3JkOiAnJyxcblxuICAgICAgICAvKipcbiAgICAgICAgICogVGhlIGFjY291bnQgaWQgZm9yIHRoaXMgYHVzZXJOYW1lYC4gSW4gdGhlIEVwaWNlbnRlciBVSSwgdGhpcyBpcyB0aGUgKipUZWFtIElEKiogKGZvciB0ZWFtIHByb2plY3RzKSBvciB0aGUgKipVc2VyIElEKiogKGZvciBwZXJzb25hbCBwcm9qZWN0cykuIFJlcXVpcmVkIGlmIHRoZSBgdXNlck5hbWVgIGlzIGZvciBhbiBbZW5kIHVzZXJdKC4uLy4uLy4uL2dsb3NzYXJ5LyN1c2VycykuIERlZmF1bHRzIHRvIGVtcHR5IHN0cmluZy5cbiAgICAgICAgICogQHR5cGUge1N0cmluZ31cbiAgICAgICAgICovXG4gICAgICAgIGFjY291bnQ6ICcnLFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBPcHRpb25zIHRvIHBhc3Mgb24gdG8gdGhlIHVuZGVybHlpbmcgdHJhbnNwb3J0IGxheWVyLiBBbGwganF1ZXJ5LmFqYXggb3B0aW9ucyBhdCBodHRwOi8vYXBpLmpxdWVyeS5jb20valF1ZXJ5LmFqYXgvIGFyZSBhdmFpbGFibGUuIERlZmF1bHRzIHRvIGVtcHR5IG9iamVjdC5cbiAgICAgICAgICogQHR5cGUge09iamVjdH1cbiAgICAgICAgICovXG4gICAgICAgIHRyYW5zcG9ydDoge31cbiAgICB9O1xuICAgIHZhciBzZXJ2aWNlT3B0aW9ucyA9ICQuZXh0ZW5kKHt9LCBkZWZhdWx0cywgY29uZmlnKTtcbiAgICB2YXIgdXJsQ29uZmlnID0gbmV3IENvbmZpZ1NlcnZpY2Uoc2VydmljZU9wdGlvbnMpLmdldCgnc2VydmVyJyk7XG5cbiAgICB2YXIgdHJhbnNwb3J0T3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LCBzZXJ2aWNlT3B0aW9ucy50cmFuc3BvcnQsIHtcbiAgICAgICAgdXJsOiB1cmxDb25maWcuZ2V0QVBJUGF0aCgnYXV0aGVudGljYXRpb24nKVxuICAgIH0pO1xuICAgIHZhciBodHRwID0gbmV3IFRyYW5zcG9ydEZhY3RvcnkodHJhbnNwb3J0T3B0aW9ucyk7XG5cbiAgICB2YXIgcHVibGljQVBJID0ge1xuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBMb2dzIHVzZXIgaW4sIHJldHVybmluZyB0aGUgdXNlciBhY2Nlc3MgdG9rZW4uXG4gICAgICAgICAqXG4gICAgICAgICAqIElmIG5vIGB1c2VyTmFtZWAgb3IgYHBhc3N3b3JkYCB3ZXJlIHByb3ZpZGVkIGluIHRoZSBpbml0aWFsIGNvbmZpZ3VyYXRpb24gb3B0aW9ucywgdGhleSBhcmUgcmVxdWlyZWQgaW4gdGhlIGBvcHRpb25zYCBoZXJlLiBJZiBubyBgYWNjb3VudGAgd2FzIHByb3ZpZGVkIGluIHRoZSBpbml0aWFsIGNvbmZpZ3VyYXRpb24gb3B0aW9ucyBhbmQgdGhlIGB1c2VyTmFtZWAgaXMgZm9yIGFuIFtlbmQgdXNlcl0oLi4vLi4vLi4vZ2xvc3NhcnkvI3VzZXJzKSwgdGhlIGBhY2NvdW50YCBpcyByZXF1aXJlZCBhcyB3ZWxsLlxuICAgICAgICAgKlxuICAgICAgICAgKiAqKkV4YW1wbGUqKlxuICAgICAgICAgKlxuICAgICAgICAgKiAgICAgIGF1dGgubG9naW4oe1xuICAgICAgICAgKiAgICAgICAgICB1c2VyTmFtZTogJ2pzbWl0aCcsXG4gICAgICAgICAqICAgICAgICAgIHBhc3N3b3JkOiAncGFzc3cwcmQnLFxuICAgICAgICAgKiAgICAgICAgICBhY2NvdW50OiAnYWNtZS1zaW11bGF0aW9ucycgfSlcbiAgICAgICAgICogICAgICAudGhlbihmdW5jdGlvbiAodG9rZW4pIHtcbiAgICAgICAgICogICAgICAgICAgY29uc29sZS5sb2coXCJ1c2VyIGFjY2VzcyB0b2tlbiBpczogXCIsIHRva2VuLmFjY2Vzc190b2tlbik7XG4gICAgICAgICAqICAgICAgfSk7XG4gICAgICAgICAqXG4gICAgICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICAgICAqIEBwYXJhbSB7T2JqZWN0fSBgb3B0aW9uc2AgKE9wdGlvbmFsKSBPdmVycmlkZXMgZm9yIGNvbmZpZ3VyYXRpb24gb3B0aW9ucy5cbiAgICAgICAgICovXG4gICAgICAgIGxvZ2luOiBmdW5jdGlvbiAob3B0aW9ucykge1xuICAgICAgICAgICAgdmFyIGh0dHBPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwgeyBzdWNjZXNzOiAkLm5vb3AgfSwgc2VydmljZU9wdGlvbnMsIG9wdGlvbnMpO1xuICAgICAgICAgICAgaWYgKCFodHRwT3B0aW9ucy51c2VyTmFtZSB8fCAhaHR0cE9wdGlvbnMucGFzc3dvcmQpIHtcbiAgICAgICAgICAgICAgICB2YXIgcmVzcCA9IHsgc3RhdHVzOiA0MDEsIHN0YXR1c01lc3NhZ2U6ICdObyB1c2VybmFtZSBvciBwYXNzd29yZCBzcGVjaWZpZWQuJyB9O1xuICAgICAgICAgICAgICAgIGlmIChvcHRpb25zLmVycm9yKSB7XG4gICAgICAgICAgICAgICAgICAgIG9wdGlvbnMuZXJyb3IuY2FsbCh0aGlzLCByZXNwKTtcbiAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICByZXR1cm4gJC5EZWZlcnJlZCgpLnJlamVjdChyZXNwKS5wcm9taXNlKCk7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIHZhciBwb3N0UGFyYW1zID0ge1xuICAgICAgICAgICAgICAgIHVzZXJOYW1lOiBodHRwT3B0aW9ucy51c2VyTmFtZSxcbiAgICAgICAgICAgICAgICBwYXNzd29yZDogaHR0cE9wdGlvbnMucGFzc3dvcmQsXG4gICAgICAgICAgICB9O1xuICAgICAgICAgICAgaWYgKGh0dHBPcHRpb25zLmFjY291bnQpIHtcbiAgICAgICAgICAgICAgICAvL3Bhc3MgaW4gbnVsbCBmb3IgYWNjb3VudCB1bmRlciBvcHRpb25zIGlmIHlvdSBkb24ndCB3YW50IGl0IHRvIGJlIHNlbnRcbiAgICAgICAgICAgICAgICBwb3N0UGFyYW1zLmFjY291bnQgPSBodHRwT3B0aW9ucy5hY2NvdW50O1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICByZXR1cm4gaHR0cC5wb3N0KHBvc3RQYXJhbXMsIGh0dHBPcHRpb25zKTtcbiAgICAgICAgfSxcblxuICAgICAgICAvLyAocmVwbGFjZSB3aXRoIC8qICovIGNvbW1lbnQgYmxvY2ssIHRvIG1ha2UgdmlzaWJsZSBpbiBkb2NzLCBvbmNlIHRoaXMgaXMgbW9yZSB0aGFuIGEgbm9vcClcbiAgICAgICAgLy9cbiAgICAgICAgLy8gTG9ncyB1c2VyIG91dCBmcm9tIHNwZWNpZmllZCBhY2NvdW50cy5cbiAgICAgICAgLy9cbiAgICAgICAgLy8gRXBpY2VudGVyIGxvZ291dCBpcyBub3QgaW1wbGVtZW50ZWQgeWV0LCBzbyBmb3Igbm93IHRoaXMgaXMgYSBkdW1teSBwcm9taXNlIHRoYXQgZ2V0cyBhdXRvbWF0aWNhbGx5IHJlc29sdmVkLlxuICAgICAgICAvL1xuICAgICAgICAvLyAqKkV4YW1wbGUqKlxuICAgICAgICAvL1xuICAgICAgICAvLyAgICAgIGF1dGgubG9nb3V0KCk7XG4gICAgICAgIC8vXG4gICAgICAgIC8vICoqUGFyYW1ldGVycyoqXG4gICAgICAgIC8vIEBwYXJhbSB7T2JqZWN0fSBgb3B0aW9uc2AgKE9wdGlvbmFsKSBPdmVycmlkZXMgZm9yIGNvbmZpZ3VyYXRpb24gb3B0aW9ucy5cbiAgICAgICAgLy9cbiAgICAgICAgbG9nb3V0OiBmdW5jdGlvbiAob3B0aW9ucykge1xuICAgICAgICAgICAgdmFyIGR0ZCA9ICQuRGVmZXJyZWQoKTtcbiAgICAgICAgICAgIGR0ZC5yZXNvbHZlKCk7XG4gICAgICAgICAgICByZXR1cm4gZHRkLnByb21pc2UoKTtcbiAgICAgICAgfVxuICAgIH07XG5cbiAgICAkLmV4dGVuZCh0aGlzLCBwdWJsaWNBUEkpO1xufTtcbiIsIid1c2Ugc3RyaWN0JztcblxuLyoqXG4gKiAjIyBDaGFubmVsIFNlcnZpY2VcbiAqXG4gKiBUaGUgRXBpY2VudGVyIHBsYXRmb3JtIHByb3ZpZGVzIGEgcHVzaCBjaGFubmVsLCB3aGljaCBhbGxvd3MgeW91IHRvIHB1Ymxpc2ggYW5kIHN1YnNjcmliZSB0byBtZXNzYWdlcyB3aXRoaW4gYSBbcHJvamVjdF0oLi4vLi4vLi4vZ2xvc3NhcnkvI3Byb2plY3RzKSwgW2dyb3VwXSguLi8uLi8uLi9nbG9zc2FyeS8jZ3JvdXBzKSwgb3IgW211bHRpcGxheWVyIHdvcmxkXSguLi8uLi8uLi9nbG9zc2FyeS8jd29ybGQpLiBUaGVyZSBhcmUgdHdvIG1haW4gdXNlIGNhc2VzIGZvciB0aGUgY2hhbm5lbDogZXZlbnQgbm90aWZpY2F0aW9ucyBhbmQgY2hhdCBtZXNzYWdlcy5cbiAqXG4gKiBUaGUgQ2hhbm5lbCBTZXJ2aWNlIGlzIGEgYnVpbGRpbmcgYmxvY2sgZm9yIHRoaXMgZnVuY3Rpb25hbGl0eS4gSXQgY3JlYXRlcyBhIHB1Ymxpc2gtc3Vic2NyaWJlIG9iamVjdCwgYWxsb3dpbmcgeW91IHRvIHB1Ymxpc2ggbWVzc2FnZXMsIHN1YnNjcmliZSB0byBtZXNzYWdlcywgb3IgdW5zdWJzY3JpYmUgZnJvbSBtZXNzYWdlcyBmb3IgYSBnaXZlbiAndG9waWMnIG9uIGEgYCQuY29tZXRkYCB0cmFuc3BvcnQgaW5zdGFuY2UuXG4gKlxuICogVHlwaWNhbGx5LCB5b3UgdXNlIHRoZSBbRXBpY2VudGVyIENoYW5uZWwgTWFuYWdlcl0oLi4vZXBpY2VudGVyLWNoYW5uZWwtbWFuYWdlci8pIHRvIGNyZWF0ZSBvciByZXRyaWV2ZSBjaGFubmVscywgdGhlbiB1c2UgdGhlIENoYW5uZWwgU2VydmljZSBgc3Vic2NyaWJlKClgIGFuZCBgcHVibGlzaCgpYCBtZXRob2RzIHRvIGxpc3RlbiB0byBvciB1cGRhdGUgZGF0YS4gKEZvciBhZGRpdGlvbmFsIGJhY2tncm91bmQgb24gRXBpY2VudGVyJ3MgcHVzaCBjaGFubmVsLCBzZWUgdGhlIGludHJvZHVjdG9yeSBub3RlcyBvbiB0aGUgW1B1c2ggQ2hhbm5lbCBBUEldKC4uLy4uLy4uL3Jlc3RfYXBpcy9tdWx0aXBsYXllci9jaGFubmVsLykgcGFnZS4pXG4gKlxuICogWW91J2xsIG5lZWQgdG8gaW5jbHVkZSB0aGUgYGVwaWNlbnRlci1tdWx0aXBsYXllci1kZXBlbmRlbmNpZXMuanNgIGxpYnJhcnkgaW4gYWRkaXRpb24gdG8gdGhlIGBlcGljZW50ZXIuanNgIGxpYnJhcnkgaW4geW91ciBwcm9qZWN0IHRvIHVzZSB0aGUgQ2hhbm5lbCBTZXJ2aWNlLiBTZWUgW0luY2x1ZGluZyBFcGljZW50ZXIuanNdKC4uLy4uLyNpbmNsdWRlKS5cbiAqXG4gKiBUbyB1c2UgdGhlIENoYW5uZWwgU2VydmljZSwgaW5zdGFudGlhdGUgaXQsIHRoZW4gbWFrZSBjYWxscyB0byBhbnkgb2YgdGhlIG1ldGhvZHMgeW91IG5lZWQuXG4gKlxuICogICAgICAgIHZhciBjcyA9IG5ldyBGLnNlcnZpY2UuQ2hhbm5lbCgpO1xuICogICAgICAgIGNzLnB1Ymxpc2goJy9hY21lLXNpbXVsYXRpb25zL3N1cHBseS1jaGFpbi1nYW1lL2ZhbGwtc2VtaW5hci9ydW4vdmFyaWFibGVzJywgeyBwcmljZTogNTAgfSk7XG4gKlxuICogVGhlIHBhcmFtZXRlcnMgZm9yIGluc3RhbnRpYXRpbmcgYSBDaGFubmVsIFNlcnZpY2UgaW5jbHVkZTpcbiAqXG4gKiAqIGBvcHRpb25zYCBUaGUgb3B0aW9ucyBvYmplY3QgdG8gY29uZmlndXJlIHRoZSBDaGFubmVsIFNlcnZpY2UuXG4gKiAqIGBvcHRpb25zLmJhc2VgIFRoZSBiYXNlIHRvcGljLiBUaGlzIGlzIGFkZGVkIGFzIGEgcHJlZml4IHRvIGFsbCBmdXJ0aGVyIHRvcGljcyB5b3UgcHVibGlzaCBvciBzdWJzY3JpYmUgdG8gd2hpbGUgd29ya2luZyB3aXRoIHRoaXMgQ2hhbm5lbCBTZXJ2aWNlLlxuICogKiBgb3B0aW9ucy50b3BpY1Jlc29sdmVyYCBBIGZ1bmN0aW9uIHRoYXQgcHJvY2Vzc2VzIGFsbCAndG9waWNzJyBwYXNzZWQgaW50byB0aGUgYHB1Ymxpc2hgIGFuZCBgc3Vic2NyaWJlYCBtZXRob2RzLiBUaGlzIGlzIHVzZWZ1bCBpZiB5b3Ugd2FudCB0byBpbXBsZW1lbnQgeW91ciBvd24gc2VyaWFsaXplIGZ1bmN0aW9ucyBmb3IgY29udmVydGluZyBjdXN0b20gb2JqZWN0cyB0byB0b3BpYyBuYW1lcy4gUmV0dXJucyBhIFN0cmluZy4gQnkgZGVmYXVsdCwgaXQganVzdCBlY2hvZXMgdGhlIHRvcGljLlxuICogKiBgb3B0aW9ucy50cmFuc3BvcnRgIFRoZSBpbnN0YW5jZSBvZiBgJC5jb21ldGRgIHRvIGhvb2sgb250by4gU2VlIGh0dHA6Ly9kb2NzLmNvbWV0ZC5vcmcvcmVmZXJlbmNlL2phdmFzY3JpcHQuaHRtbCBmb3IgYWRkaXRpb25hbCBiYWNrZ3JvdW5kIG9uIGNvbWV0ZC5cbiAqL1xudmFyIENoYW5uZWwgPSBmdW5jdGlvbiAob3B0aW9ucykge1xuICAgIHZhciBkZWZhdWx0cyA9IHtcblxuICAgICAgICAvKipcbiAgICAgICAgICogVGhlIGJhc2UgdG9waWMuIFRoaXMgaXMgYWRkZWQgYXMgYSBwcmVmaXggdG8gYWxsIGZ1cnRoZXIgdG9waWNzIHlvdSBwdWJsaXNoIG9yIHN1YnNjcmliZSB0byB3aGlsZSB3b3JraW5nIHdpdGggdGhpcyBDaGFubmVsIFNlcnZpY2UuXG4gICAgICAgICAqIEB0eXBlIHtzdHJpbmd9XG4gICAgICAgICAqL1xuICAgICAgICBiYXNlOiAnJyxcblxuICAgICAgICAvKipcbiAgICAgICAgICogQSBmdW5jdGlvbiB0aGF0IHByb2Nlc3NlcyBhbGwgJ3RvcGljcycgcGFzc2VkIGludG8gdGhlIGBwdWJsaXNoYCBhbmQgYHN1YnNjcmliZWAgbWV0aG9kcy4gVGhpcyBpcyB1c2VmdWwgaWYgeW91IHdhbnQgdG8gaW1wbGVtZW50IHlvdXIgb3duIHNlcmlhbGl6ZSBmdW5jdGlvbnMgZm9yIGNvbnZlcnRpbmcgY3VzdG9tIG9iamVjdHMgdG8gdG9waWMgbmFtZXMuIEJ5IGRlZmF1bHQsIGl0IGp1c3QgZWNob2VzIHRoZSB0b3BpYy5cbiAgICAgICAgICpcbiAgICAgICAgICogKipQYXJhbWV0ZXJzKipcbiAgICAgICAgICpcbiAgICAgICAgICogKiBgdG9waWNgIFRvcGljIHRvIHBhcnNlLlxuICAgICAgICAgKlxuICAgICAgICAgKiAqKlJldHVybiBWYWx1ZSoqXG4gICAgICAgICAqXG4gICAgICAgICAqICogKlN0cmluZyo6IFRoaXMgZnVuY3Rpb24gc2hvdWxkIHJldHVybiBhIHN0cmluZyB0b3BpYy5cbiAgICAgICAgICpcbiAgICAgICAgICogQHR5cGUge2Z1bmN0aW9ufVxuICAgICAgICAgKi9cbiAgICAgICAgdG9waWNSZXNvbHZlcjogZnVuY3Rpb24gKHRvcGljKSB7XG4gICAgICAgICAgICByZXR1cm4gdG9waWM7XG4gICAgICAgIH0sXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIFRoZSBpbnN0YW5jZSBvZiBgJC5jb21ldGRgIHRvIGhvb2sgb250by5cbiAgICAgICAgICogQHR5cGUge29iamVjdH1cbiAgICAgICAgICovXG4gICAgICAgIHRyYW5zcG9ydDogbnVsbFxuICAgIH07XG4gICAgdGhpcy5jaGFubmVsT3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LCBkZWZhdWx0cywgb3B0aW9ucyk7XG59O1xuXG52YXIgbWFrZU5hbWUgPSBmdW5jdGlvbiAoY2hhbm5lbE5hbWUsIHRvcGljKSB7XG4gICAgLy9SZXBsYWNlIHRyYWlsaW5nL2RvdWJsZSBzbGFzaGVzXG4gICAgdmFyIG5ld05hbWUgPSAoY2hhbm5lbE5hbWUgPyAoY2hhbm5lbE5hbWUgKyAnLycgKyB0b3BpYykgOiB0b3BpYykucmVwbGFjZSgvXFwvXFwvL2csICcvJykucmVwbGFjZSgvXFwvJC8sJycpO1xuICAgIHJldHVybiBuZXdOYW1lO1xufTtcblxuXG5DaGFubmVsLnByb3RvdHlwZSA9ICQuZXh0ZW5kKENoYW5uZWwucHJvdG90eXBlLCB7XG5cbiAgICAvLyBmdXR1cmUgZnVuY3Rpb25hbGl0eTpcbiAgICAvLyAgICAgIC8vIFNldCB0aGUgY29udGV4dCBmb3IgdGhlIGNhbGxiYWNrXG4gICAgLy8gICAgICBjcy5zdWJzY3JpYmUoJ3J1bicsIGZ1bmN0aW9uICgpIHsgdGhpcy5pbm5lckhUTUwgPSAnVHJpZ2dlcmVkJ30sIGRvY3VtZW50LmJvZHkpO1xuICAgICAvL1xuICAgICAvLyAgICAgIC8vIENvbnRyb2wgdGhlIG9yZGVyIG9mIG9wZXJhdGlvbnMgYnkgc2V0dGluZyB0aGUgYHByaW9yaXR5YFxuICAgICAvLyAgICAgIGNzLnN1YnNjcmliZSgncnVuJywgY2IsIHRoaXMsIHtwcmlvcml0eTogOX0pO1xuICAgICAvL1xuICAgICAvLyAgICAgIC8vIE9ubHkgZXhlY3V0ZSB0aGUgY2FsbGJhY2ssIGBjYmAsIGlmIHRoZSB2YWx1ZSBvZiB0aGUgYHByaWNlYCB2YXJpYWJsZSBpcyA1MFxuICAgICAvLyAgICAgIGNzLnN1YnNjcmliZSgncnVuL3ZhcmlhYmxlcy9wcmljZScsIGNiLCB0aGlzLCB7cHJpb3JpdHk6IDMwLCB2YWx1ZTogNTB9KTtcbiAgICAgLy9cbiAgICAgLy8gICAgICAvLyBPbmx5IGV4ZWN1dGUgdGhlIGNhbGxiYWNrLCBgY2JgLCBpZiB0aGUgdmFsdWUgb2YgdGhlIGBwcmljZWAgdmFyaWFibGUgaXMgZ3JlYXRlciB0aGFuIDUwXG4gICAgIC8vICAgICAgc3Vic2NyaWJlKCdydW4vdmFyaWFibGVzL3ByaWNlJywgY2IsIHRoaXMsIHtwcmlvcml0eTogMzAsIHZhbHVlOiAnPjUwJ30pO1xuICAgICAvL1xuICAgICAvLyAgICAgIC8vIE9ubHkgZXhlY3V0ZSB0aGUgY2FsbGJhY2ssIGBjYmAsIGlmIHRoZSB2YWx1ZSBvZiB0aGUgYHByaWNlYCB2YXJpYWJsZSBpcyBldmVuXG4gICAgIC8vICAgICAgc3Vic2NyaWJlKCdydW4vdmFyaWFibGVzL3ByaWNlJywgY2IsIHRoaXMsIHtwcmlvcml0eTogMzAsIHZhbHVlOiBmdW5jdGlvbiAodmFsKSB7cmV0dXJuIHZhbCAlIDIgPT09IDB9fSk7XG5cblxuICAgIC8qKlxuICAgICAqIFN1YnNjcmliZSB0byBjaGFuZ2VzIG9uIGEgdG9waWMuXG4gICAgICpcbiAgICAgKiBUaGUgdG9waWMgc2hvdWxkIGluY2x1ZGUgdGhlIGZ1bGwgcGF0aCBvZiB0aGUgYWNjb3VudCBpZCAoKipUZWFtIElEKiogZm9yIHRlYW0gcHJvamVjdHMpLCBwcm9qZWN0IGlkLCBhbmQgZ3JvdXAgbmFtZS4gKEluIG1vc3QgY2FzZXMsIGl0IGlzIHNpbXBsZXIgdG8gdXNlIHRoZSBbRXBpY2VudGVyIENoYW5uZWwgTWFuYWdlcl0oLi4vZXBpY2VudGVyLWNoYW5uZWwtbWFuYWdlci8pIGluc3RlYWQsIGluIHdoaWNoIGNhc2UgdGhpcyBpcyBjb25maWd1cmVkIGZvciB5b3UuKVxuICAgICAqXG4gICAgICogICoqRXhhbXBsZXMqKlxuICAgICAqXG4gICAgICogICAgICB2YXIgY2IgPSBmdW5jdGlvbih2YWwpIHsgY29uc29sZS5sb2codmFsLmRhdGEpOyB9O1xuICAgICAqXG4gICAgICogICAgICAvLyBTdWJzY3JpYmUgdG8gY2hhbmdlcyBvbiBhIHRvcC1sZXZlbCAncnVuJyB0b3BpY1xuICAgICAqICAgICAgY3Muc3Vic2NyaWJlKCcvYWNtZS1zaW11bGF0aW9ucy9zdXBwbHktY2hhaW4tZ2FtZS9mYWxsLXNlbWluYXIvcnVuJywgY2IpO1xuICAgICAqXG4gICAgICogICAgICAvLyBTdWJzY3JpYmUgdG8gY2hhbmdlcyBvbiBjaGlsZHJlbiBvZiB0aGUgJ3J1bicgdG9waWMuIE5vdGUgdGhpcyB3aWxsIGFsc28gYmUgdHJpZ2dlcmVkIGZvciBjaGFuZ2VzIHRvIHJ1bi54Lnkuei5cbiAgICAgKiAgICAgIGNzLnN1YnNjcmliZSgnL2FjbWUtc2ltdWxhdGlvbnMvc3VwcGx5LWNoYWluLWdhbWUvZmFsbC1zZW1pbmFyL3J1bi8qJywgY2IpO1xuICAgICAqXG4gICAgICogICAgICAvLyBTdWJzY3JpYmUgdG8gY2hhbmdlcyBvbiBib3RoIHRoZSB0b3AtbGV2ZWwgJ3J1bicgdG9waWMgYW5kIGl0cyBjaGlsZHJlblxuICAgICAqICAgICAgY3Muc3Vic2NyaWJlKFsnL2FjbWUtc2ltdWxhdGlvbnMvc3VwcGx5LWNoYWluLWdhbWUvZmFsbC1zZW1pbmFyL3J1bicsXG4gICAgICogICAgICAgICAgJy9hY21lLXNpbXVsYXRpb25zL3N1cHBseS1jaGFpbi1nYW1lL2ZhbGwtc2VtaW5hci9ydW4vKiddLCBjYik7XG4gICAgICpcbiAgICAgKiAgICAgIC8vIFN1YnNjcmliZSB0byBjaGFuZ2VzIG9uIGEgcGFydGljdWxhciB2YXJpYWJsZVxuICAgICAqICAgICAgc3Vic2NyaWJlKCcvYWNtZS1zaW11bGF0aW9ucy9zdXBwbHktY2hhaW4tZ2FtZS9mYWxsLXNlbWluYXIvcnVuL3ZhcmlhYmxlcy9wcmljZScsIGNiKTtcbiAgICAgKlxuICAgICAqXG4gICAgICogKipSZXR1cm4gVmFsdWUqKlxuICAgICAqXG4gICAgICogKiAqU3RyaW5nKiBSZXR1cm5zIGEgdG9rZW4geW91IGNhbiBsYXRlciB1c2UgdG8gdW5zdWJzY3JpYmUuXG4gICAgICpcbiAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAqIEBwYXJhbSAge1N0cmluZ3xBcnJheX0gICBgdG9waWNgICAgIExpc3Qgb2YgdG9waWNzIHRvIGxpc3RlbiBmb3IgY2hhbmdlcyBvbi5cbiAgICAgKiBAcGFyYW0gIHtGdW5jdGlvbn0gYGNhbGxiYWNrYCBDYWxsYmFjayBmdW5jdGlvbiB0byBleGVjdXRlLiBDYWxsYmFjayBpcyBjYWxsZWQgd2l0aCBzaWduYXR1cmUgYChldnQsIHBheWxvYWQsIG1ldGFkYXRhKWAuXG4gICAgICogQHBhcmFtICB7T2JqZWN0fSAgIGBjb250ZXh0YCAgQ29udGV4dCBpbiB3aGljaCB0aGUgYGNhbGxiYWNrYCBpcyBleGVjdXRlZC5cbiAgICAgKiBAcGFyYW0gIHtPYmplY3R9ICAgYG9wdGlvbnNgICAoT3B0aW9uYWwpIE92ZXJyaWRlcyBmb3IgY29uZmlndXJhdGlvbiBvcHRpb25zLlxuICAgICAqIEBwYXJhbSAge051bWJlcn0gICBgb3B0aW9ucy5wcmlvcml0eWAgIFVzZWQgdG8gY29udHJvbCBvcmRlciBvZiBvcGVyYXRpb25zLiBEZWZhdWx0cyB0byAwLiBDYW4gYmUgYW55ICt2ZSBvciAtdmUgbnVtYmVyLlxuICAgICAqIEBwYXJhbSAge1N0cmluZ3xOdW1iZXJ8RnVuY3Rpb259ICAgYG9wdGlvbnMudmFsdWVgIFRoZSBgY2FsbGJhY2tgIGlzIG9ubHkgdHJpZ2dlcmVkIGlmIHRoaXMgY29uZGl0aW9uIG1hdGNoZXMuIFNlZSBleGFtcGxlcyBmb3IgZGV0YWlscy5cbiAgICAgKlxuICAgICAqL1xuICAgIHN1YnNjcmliZTogZnVuY3Rpb24gKHRvcGljLCBjYWxsYmFjaywgY29udGV4dCwgb3B0aW9ucykge1xuXG4gICAgICAgIHZhciB0b3BpY3MgPSBbXS5jb25jYXQodG9waWMpO1xuICAgICAgICB2YXIgbWUgPSB0aGlzO1xuICAgICAgICB2YXIgc3Vic2NyaXB0aW9uSWRzID0gW107XG4gICAgICAgIHZhciBvcHRzID0gbWUuY2hhbm5lbE9wdGlvbnM7XG5cbiAgICAgICAgb3B0cy50cmFuc3BvcnQuYmF0Y2goZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgJC5lYWNoKHRvcGljcywgZnVuY3Rpb24gKGluZGV4LCB0b3BpYykge1xuICAgICAgICAgICAgICAgIHRvcGljID0gbWFrZU5hbWUob3B0cy5iYXNlLCBvcHRzLnRvcGljUmVzb2x2ZXIodG9waWMpKTtcbiAgICAgICAgICAgICAgICBzdWJzY3JpcHRpb25JZHMucHVzaChvcHRzLnRyYW5zcG9ydC5zdWJzY3JpYmUodG9waWMsIGNhbGxiYWNrKSk7XG4gICAgICAgICAgICB9KTtcbiAgICAgICAgfSk7XG4gICAgICAgIHJldHVybiAoc3Vic2NyaXB0aW9uSWRzWzFdID8gc3Vic2NyaXB0aW9uSWRzIDogc3Vic2NyaXB0aW9uSWRzWzBdKTtcbiAgICB9LFxuXG4gICAgLyoqXG4gICAgICogUHVibGlzaCBkYXRhIHRvIGEgdG9waWMuXG4gICAgICpcbiAgICAgKiAqKkV4YW1wbGVzKipcbiAgICAgKlxuICAgICAqICAgICAgLy8gU2VuZCBkYXRhIHRvIGFsbCBzdWJzY3JpYmVycyBvZiB0aGUgJ3J1bicgdG9waWNcbiAgICAgKiAgICAgIGNzLnB1Ymxpc2goJy9hY21lLXNpbXVsYXRpb25zL3N1cHBseS1jaGFpbi1nYW1lL2ZhbGwtc2VtaW5hci9ydW4nLCB7IGNvbXBsZXRlZDogZmFsc2UgfSk7XG4gICAgICpcbiAgICAgKiAgICAgIC8vIFNlbmQgZGF0YSB0byBhbGwgc3Vic2NyaWJlcnMgb2YgdGhlICdydW4vdmFyaWFibGVzJyB0b3BpY1xuICAgICAqICAgICAgY3MucHVibGlzaCgnL2FjbWUtc2ltdWxhdGlvbnMvc3VwcGx5LWNoYWluLWdhbWUvZmFsbC1zZW1pbmFyL3J1bi92YXJpYWJsZXMnLCB7IHByaWNlOiA1MCB9KTtcbiAgICAgKlxuICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICpcbiAgICAgKiBAcGFyYW0gIHtTdHJpbmd9IGB0b3BpY2AgVG9waWMgdG8gcHVibGlzaCB0by5cbiAgICAgKiBAcGFyYW0gIHsqfSBgZGF0YWAgIERhdGEgdG8gcHVibGlzaCB0byB0b3BpYy5cbiAgICAgKlxuICAgICAqL1xuICAgIHB1Ymxpc2g6IGZ1bmN0aW9uICh0b3BpYywgZGF0YSkge1xuICAgICAgICB2YXIgdG9waWNzID0gW10uY29uY2F0KHRvcGljKTtcbiAgICAgICAgdmFyIG1lID0gdGhpcztcbiAgICAgICAgdmFyIHJldHVybk9ianMgPSBbXTtcbiAgICAgICAgdmFyIG9wdHMgPSBtZS5jaGFubmVsT3B0aW9ucztcblxuXG4gICAgICAgIG9wdHMudHJhbnNwb3J0LmJhdGNoKGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgICQuZWFjaCh0b3BpY3MsIGZ1bmN0aW9uIChpbmRleCwgdG9waWMpIHtcbiAgICAgICAgICAgICAgICB0b3BpYyA9IG1ha2VOYW1lKG9wdHMuYmFzZSwgb3B0cy50b3BpY1Jlc29sdmVyKHRvcGljKSk7XG4gICAgICAgICAgICAgICAgaWYgKHRvcGljLmNoYXJBdCh0b3BpYy5sZW5ndGggLSAxKSA9PT0gJyonKSB7XG4gICAgICAgICAgICAgICAgICAgIHRvcGljID0gdG9waWMucmVwbGFjZSgvXFwqKyQvLCAnJyk7XG4gICAgICAgICAgICAgICAgICAgIGNvbnNvbGUud2FybignWW91IGNhbiBjYW5ub3QgcHVibGlzaCB0byBjaGFubmVscyB3aXRoIHdpbGRjYXJkcy4gUHVibGlzaGluZyB0byAnLCB0b3BpYywgJ2luc3RlYWQnKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgcmV0dXJuT2Jqcy5wdXNoKG9wdHMudHJhbnNwb3J0LnB1Ymxpc2godG9waWMsIGRhdGEpKTtcbiAgICAgICAgICAgIH0pO1xuICAgICAgICB9KTtcbiAgICAgICAgcmV0dXJuIChyZXR1cm5PYmpzWzFdID8gcmV0dXJuT2JqcyA6IHJldHVybk9ianNbMF0pO1xuICAgIH0sXG5cbiAgICAvKipcbiAgICAgKiBVbnN1YnNjcmliZSBmcm9tIGNoYW5nZXMgdG8gYSB0b3BpYy5cbiAgICAgKlxuICAgICAqICoqRXhhbXBsZSoqXG4gICAgICpcbiAgICAgKiAgICAgIGNzLnVuc3Vic2NyaWJlKCdzYW1wbGVUb2tlbicpO1xuICAgICAqXG4gICAgICogKipQYXJhbWV0ZXJzKipcbiAgICAgKiBAcGFyYW0gIHtTdHJpbmd9IGB0b2tlbmAgVGhlIHRva2VuIGZvciB0b3BpYyBpcyByZXR1cm5lZCB3aGVuIHlvdSBpbml0aWFsbHkgc3Vic2NyaWJlLiBQYXNzIGl0IGhlcmUgdG8gdW5zdWJzY3JpYmUgZnJvbSB0aGF0IHRvcGljLlxuICAgICAqL1xuICAgIHVuc3Vic2NyaWJlOiBmdW5jdGlvbiAodG9rZW4pIHtcbiAgICAgICAgdGhpcy5jaGFubmVsT3B0aW9ucy50cmFuc3BvcnQudW5zdWJzY3JpYmUodG9rZW4pO1xuICAgICAgICByZXR1cm4gdG9rZW47XG4gICAgfSxcblxuICAgIC8qKlxuICAgICAqIFN0YXJ0IGxpc3RlbmluZyBmb3IgZXZlbnRzIG9uIHRoaXMgaW5zdGFuY2UuIFNpZ25hdHVyZSBpcyBzYW1lIGFzIGZvciBqUXVlcnkgRXZlbnRzOiBodHRwOi8vYXBpLmpxdWVyeS5jb20vb24vLlxuICAgICAqXG4gICAgICogU3VwcG9ydGVkIGV2ZW50cyBhcmU6IGBjb25uZWN0YCwgYGRpc2Nvbm5lY3RgLCBgc3Vic2NyaWJlYCwgYHVuc3Vic2NyaWJlYCwgYHB1Ymxpc2hgLCBgZXJyb3JgLlxuICAgICAqXG4gICAgICogKipQYXJhbWV0ZXJzKipcbiAgICAgKlxuICAgICAqIEBwYXJhbSB7c3RyaW5nfSBgZXZlbnRgIFRoZSBldmVudCB0eXBlLiBTZWUgbW9yZSBkZXRhaWwgYXQgalF1ZXJ5IEV2ZW50czogaHR0cDovL2FwaS5qcXVlcnkuY29tL29uLy5cbiAgICAgKi9cbiAgICBvbjogZnVuY3Rpb24gKGV2ZW50KSB7XG4gICAgICAgICQodGhpcykub24uYXBwbHkoJCh0aGlzKSwgYXJndW1lbnRzKTtcbiAgICB9LFxuXG4gICAgLyoqXG4gICAgICogU3RvcCBsaXN0ZW5pbmcgZm9yIGV2ZW50cyBvbiB0aGlzIGluc3RhbmNlLiBTaWduYXR1cmUgaXMgc2FtZSBhcyBmb3IgalF1ZXJ5IEV2ZW50czogaHR0cDovL2FwaS5qcXVlcnkuY29tL29mZi8uXG4gICAgICpcbiAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAqXG4gICAgICogQHBhcmFtIHtzdHJpbmd9IGBldmVudGAgVGhlIGV2ZW50IHR5cGUuIFNlZSBtb3JlIGRldGFpbCBhdCBqUXVlcnkgRXZlbnRzOiBodHRwOi8vYXBpLmpxdWVyeS5jb20vb2ZmLy5cbiAgICAgKi9cbiAgICBvZmY6IGZ1bmN0aW9uIChldmVudCkge1xuICAgICAgICAkKHRoaXMpLm9mZi5hcHBseSgkKHRoaXMpLCBhcmd1bWVudHMpO1xuICAgIH0sXG5cbiAgICAvKipcbiAgICAgKiBUcmlnZ2VyIGV2ZW50cyBhbmQgZXhlY3V0ZSBoYW5kbGVycy4gU2lnbmF0dXJlIGlzIHNhbWUgYXMgZm9yIGpRdWVyeSBFdmVudHM6IGh0dHA6Ly9hcGkuanF1ZXJ5LmNvbS90cmlnZ2VyLy5cbiAgICAgKlxuICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICpcbiAgICAgKiBAcGFyYW0ge3N0cmluZ30gYGV2ZW50YCBUaGUgZXZlbnQgdHlwZS4gU2VlIG1vcmUgZGV0YWlsIGF0IGpRdWVyeSBFdmVudHM6IGh0dHA6Ly9hcGkuanF1ZXJ5LmNvbS90cmlnZ2VyLy5cbiAgICAgKi9cbiAgICB0cmlnZ2VyOiBmdW5jdGlvbiAoZXZlbnQpIHtcbiAgICAgICAgJCh0aGlzKS50cmlnZ2VyLmFwcGx5KCQodGhpcyksIGFyZ3VtZW50cyk7XG4gICAgfVxuXG59KTtcblxubW9kdWxlLmV4cG9ydHMgPSBDaGFubmVsO1xuIiwiLyoqXG4gKiBAY2xhc3MgQ29uZmlndXJhdGlvblNlcnZpY2VcbiAqXG4gKiBBbGwgc2VydmljZXMgdGFrZSBpbiBhIGNvbmZpZ3VyYXRpb24gc2V0dGluZ3Mgb2JqZWN0IHRvIGNvbmZpZ3VyZSB0aGVtc2VsdmVzLiBBIEpTIGhhc2gge30gaXMgYSB2YWxpZCBjb25maWd1cmF0aW9uIG9iamVjdCwgYnV0IG9wdGlvbmFsbHkgeW91IGNhbiB1c2UgdGhlIGNvbmZpZ3VyYXRpb24gc2VydmljZSB0byB0b2dnbGUgY29uZmlncyBiYXNlZCBvbiB0aGUgZW52aXJvbm1lbnRcbiAqXG4gKiBAZXhhbXBsZVxuICogICAgIHZhciBjcyA9IHJlcXVpcmUoJ2NvbmZpZ3VyYXRpb24tc2VydmljZScpKHtcbiAqICAgICAgICAgIGRldjogeyAvL2Vudmlyb25tZW50XG4gICAgICAgICAgICAgICAgcG9ydDogMzAwMCxcbiAgICAgICAgICAgICAgICBob3N0OiAnbG9jYWxob3N0JyxcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICBwcm9kOiB7XG4gICAgICAgICAgICAgICAgcG9ydDogODA4MCxcbiAgICAgICAgICAgICAgICBob3N0OiAnYXBpLmZvcmlvLmNvbScsXG4gICAgICAgICAgICAgICAgbG9nTGV2ZWw6ICdub25lJ1xuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIGxvZ0xldmVsOiAnREVCVUcnIC8vZ2xvYmFsXG4gKiAgICAgfSk7XG4gKlxuICogICAgICBjcy5nZXQoJ2xvZ0xldmVsJyk7IC8vcmV0dXJucyAnREVCVUcnXG4gKlxuICogICAgICBjcy5zZXRFbnYoJ2RldicpO1xuICogICAgICBjcy5nZXQoJ2xvZ0xldmVsJyk7IC8vcmV0dXJucyAnREVCVUcnXG4gKlxuICogICAgICBjcy5zZXRFbnYoJ3Byb2QnKTtcbiAqICAgICAgY3MuZ2V0KCdsb2dMZXZlbCcpOyAvL3JldHVybnMgJ25vbmUnXG4gKlxuICovXG5cbid1c2Ugc3RyaWN0JztcbnZhciB1cmxTZXJ2aWNlID0gcmVxdWlyZSgnLi91cmwtY29uZmlnLXNlcnZpY2UnKTtcblxubW9kdWxlLmV4cG9ydHMgPSBmdW5jdGlvbiAoY29uZmlnKSB7XG4gICAgLy9UT0RPOiBFbnZpcm9ubWVudHNcbiAgICB2YXIgZGVmYXVsdHMgPSB7XG4gICAgICAgIGxvZ0xldmVsOiAnTk9ORSdcbiAgICB9O1xuICAgIHZhciBzZXJ2aWNlT3B0aW9ucyA9ICQuZXh0ZW5kKHt9LCBkZWZhdWx0cywgY29uZmlnKTtcbiAgICBzZXJ2aWNlT3B0aW9ucy5zZXJ2ZXIgPSB1cmxTZXJ2aWNlKHNlcnZpY2VPcHRpb25zLnNlcnZlcik7XG5cbiAgICByZXR1cm4ge1xuXG4gICAgICAgIGRhdGE6IHNlcnZpY2VPcHRpb25zLFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBTZXQgdGhlIGVudmlyb25tZW50IGtleSB0byBnZXQgY29uZmlndXJhdGlvbiBvcHRpb25zIGZyb21cbiAgICAgICAgICogQHBhcmFtIHsgc3RyaW5nfSBlbnZcbiAgICAgICAgICovXG4gICAgICAgIHNldEVudjogZnVuY3Rpb24gKGVudikge1xuXG4gICAgICAgIH0sXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIEdldCBjb25maWd1cmF0aW9uLlxuICAgICAgICAgKiBAcGFyYW0gIHsgc3RyaW5nfSBwcm9wZXJ0eSBvcHRpb25hbFxuICAgICAgICAgKiBAcmV0dXJuIHsqfSAgICAgICAgICBWYWx1ZSBvZiBwcm9wZXJ0eSBpZiBzcGVjaWZpZWQsIHRoZSBlbnRpcmUgY29uZmlnIG9iamVjdCBvdGhlcndpc2VcbiAgICAgICAgICovXG4gICAgICAgIGdldDogZnVuY3Rpb24gKHByb3BlcnR5KSB7XG4gICAgICAgICAgICByZXR1cm4gc2VydmljZU9wdGlvbnNbcHJvcGVydHldO1xuICAgICAgICB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBTZXQgY29uZmlndXJhdGlvbi5cbiAgICAgICAgICogQHBhcmFtICB7IHN0cmluZ3xPYmplY3R9IGtleSBpZiBhIGtleSBpcyBwcm92aWRlZCwgc2V0IGEga2V5IHRvIHRoYXQgdmFsdWUuIE90aGVyd2lzZSBtZXJnZSBvYmplY3Qgd2l0aCBjdXJyZW50IGNvbmZpZ1xuICAgICAgICAgKiBAcGFyYW0gIHsqfSB2YWx1ZSAgdmFsdWUgZm9yIHByb3ZpZGVkIGtleVxuICAgICAgICAgKi9cbiAgICAgICAgc2V0OiBmdW5jdGlvbiAoa2V5LCB2YWx1ZSkge1xuICAgICAgICAgICAgc2VydmljZU9wdGlvbnNba2V5XSA9IHZhbHVlO1xuICAgICAgICB9XG4gICAgfTtcbn07XG5cbiIsIi8qKlxuICogIyMgRGF0YSBBUEkgU2VydmljZVxuICpcbiAqIFRoZSBEYXRhIEFQSSBTZXJ2aWNlIGFsbG93cyB5b3UgdG8gY3JlYXRlLCBhY2Nlc3MsIGFuZCBtYW5pcHVsYXRlIGRhdGEgcmVsYXRlZCB0byBhbnkgb2YgeW91ciBwcm9qZWN0cy4gRGF0YSBhcmUgb3JnYW5pemVkIGluIGNvbGxlY3Rpb25zLiBFYWNoIGNvbGxlY3Rpb24gY29udGFpbnMgYSBkb2N1bWVudDsgZWFjaCBlbGVtZW50IG9mIHRoaXMgdG9wLWxldmVsIGRvY3VtZW50IGlzIGEgSlNPTiBvYmplY3QuIChTZWUgYWRkaXRpb25hbCBpbmZvcm1hdGlvbiBvbiB0aGUgdW5kZXJseWluZyBbRGF0YSBBUEldKC4uLy4uLy4uL3Jlc3RfYXBpcy9kYXRhX2FwaS8pLilcbiAqXG4gKiBBbGwgQVBJIGNhbGxzIHRha2UgaW4gYW4gXCJvcHRpb25zXCIgb2JqZWN0IGFzIHRoZSBsYXN0IHBhcmFtZXRlci4gVGhlIG9wdGlvbnMgY2FuIGJlIHVzZWQgdG8gZXh0ZW5kL292ZXJyaWRlIHRoZSBEYXRhIEFQSSBTZXJ2aWNlIGRlZmF1bHRzLiBJbiBwYXJ0aWN1bGFyLCB0aGVyZSBhcmUgdGhyZWUgcmVxdWlyZWQgcGFyYW1ldGVycyB3aGVuIHlvdSBpbnN0YW50aWF0ZSB0aGUgRGF0YSBTZXJ2aWNlOlxuICpcbiAqICogYGFjY291bnRgOiBFcGljZW50ZXIgYWNjb3VudCBpZCAoKipUZWFtIElEKiogZm9yIHRlYW0gcHJvamVjdHMsICoqVXNlciBJRCoqIGZvciBwZXJzb25hbCBwcm9qZWN0cykuXG4gKiAqIGBwcm9qZWN0YDogRXBpY2VudGVyIHByb2plY3QgaWQuXG4gKiAqIGByb290YDogVGhlIHRoZSBuYW1lIG9mIHRoZSBjb2xsZWN0aW9uLiBJZiB5b3UgaGF2ZSBtdWx0aXBsZSBjb2xsZWN0aW9ucyB3aXRoaW4gZWFjaCBvZiB5b3VyIHByb2plY3RzLCB5b3UgY2FuIGFsc28gcGFzcyB0aGUgY29sbGVjdGlvbiBuYW1lIGFzIGFuIG9wdGlvbiBmb3IgZWFjaCBjYWxsLlxuICpcbiAqICAgICAgIHZhciBkcyA9IG5ldyBGLnNlcnZpY2UuRGF0YSh7XG4gKiAgICAgICAgICBhY2NvdW50OiAnYWNtZS1zaW11bGF0aW9ucycsXG4gKiAgICAgICAgICBwcm9qZWN0OiAnc3VwcGx5LWNoYWluLWdhbWUnLFxuICogICAgICAgICAgcm9vdDogJ3N1cnZleS1yZXNwb25zZXMnLFxuICogICAgICAgICAgc2VydmVyOiB7IGhvc3Q6ICdhcGkuZm9yaW8uY29tJyB9XG4gKiAgICAgICB9KTtcbiAqICAgICAgIGRzLnNhdmVBcygndXNlcjEnLFxuICogICAgICAgICAgeyAncXVlc3Rpb24xJzogMiwgJ3F1ZXN0aW9uMic6IDEwLFxuICogICAgICAgICAgJ3F1ZXN0aW9uMyc6IGZhbHNlLCAncXVlc3Rpb240JzogJ3NvbWV0aW1lcycgfSApO1xuICogICAgICAgZHMuc2F2ZUFzKCd1c2VyMicsXG4gKiAgICAgICAgICB7ICdxdWVzdGlvbjEnOiAzLCAncXVlc3Rpb24yJzogOCxcbiAqICAgICAgICAgICdxdWVzdGlvbjMnOiB0cnVlLCAncXVlc3Rpb240JzogJ2Fsd2F5cycgfSApO1xuICogICAgICAgZHMucXVlcnkoJycseyAncXVlc3Rpb24yJzogeyAnJGd0JzogOX0gfSk7XG4gKlxuICogTm90ZSB0aGF0IGluIGFkZGl0aW9uIHRvIHRoZSBgYWNjb3VudGAsIGBwcm9qZWN0YCwgYW5kIGByb290YCwgdGhlIERhdGEgU2VydmljZSBwYXJhbWV0ZXJzIG9wdGlvbmFsbHkgaW5jbHVkZSBhIGBzZXJ2ZXJgIG9iamVjdCwgd2hvc2UgYGhvc3RgIGZpZWxkIGNvbnRhaW5zIHRoZSBVUkkgb2YgdGhlIEZvcmlvIHNlcnZlci4gVGhpcyBpcyBhdXRvbWF0aWNhbGx5IHNldCwgYnV0IHlvdSBjYW4gcGFzcyBpdCBleHBsaWNpdGx5IGlmIGRlc2lyZWQuIEl0IGlzIG1vc3QgY29tbW9ubHkgdXNlZCBmb3IgY2xhcml0eSB3aGVuIHlvdSBhcmUgW2hvc3RpbmcgYW4gRXBpY2VudGVyIHByb2plY3Qgb24geW91ciBvd24gc2VydmVyXSguLi8uLi8uLi9ob3dfdG8vc2VsZl9ob3N0aW5nLykuXG4gKi9cblxuJ3VzZSBzdHJpY3QnO1xuXG52YXIgQ29uZmlnU2VydmljZSA9IHJlcXVpcmUoJy4vY29uZmlndXJhdGlvbi1zZXJ2aWNlJyk7XG52YXIgcXV0aWwgPSByZXF1aXJlKCcuLi91dGlsL3F1ZXJ5LXV0aWwnKTtcbnZhciBUcmFuc3BvcnRGYWN0b3J5ID0gcmVxdWlyZSgnLi4vdHJhbnNwb3J0L2h0dHAtdHJhbnNwb3J0LWZhY3RvcnknKTtcbnZhciBTZXNzaW9uTWFuYWdlciA9IHJlcXVpcmUoJy4uL3N0b3JlL3Nlc3Npb24tbWFuYWdlcicpO1xuXG5tb2R1bGUuZXhwb3J0cyA9IGZ1bmN0aW9uIChjb25maWcpIHtcbiAgICB2YXIgZGVmYXVsdHMgPSB7XG4gICAgICAgIC8qKlxuICAgICAgICAgKiBOYW1lIG9mIGNvbGxlY3Rpb24uIERlZmF1bHRzIHRvIGAvYCwgdGhhdCBpcywgdGhlIHJvb3QgbGV2ZWwgb2YgeW91ciBwcm9qZWN0IGF0IGBmb3Jpby5jb20vYXBwL3lvdXItYWNjb3VudC1pZC95b3VyLXByb2plY3QtaWQvYC4gUmVxdWlyZWQuXG4gICAgICAgICAqIEB0eXBlIHtTdHJpbmd9XG4gICAgICAgICAqL1xuICAgICAgICByb290OiAnLycsXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIFRoZSBhY2NvdW50IGlkLiBJbiB0aGUgRXBpY2VudGVyIFVJLCB0aGlzIGlzIHRoZSAqKlRlYW0gSUQqKiAoZm9yIHRlYW0gcHJvamVjdHMpIG9yICoqVXNlciBJRCoqIChmb3IgcGVyc29uYWwgcHJvamVjdHMpLiBEZWZhdWx0cyB0byBlbXB0eSBzdHJpbmcuIElmIGxlZnQgdW5kZWZpbmVkLCB0YWtlbiBmcm9tIHRoZSBVUkwuXG4gICAgICAgICAqIEB0eXBlIHtTdHJpbmd9XG4gICAgICAgICAqL1xuICAgICAgICBhY2NvdW50OiB1bmRlZmluZWQsXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIFRoZSBwcm9qZWN0IGlkLiBEZWZhdWx0cyB0byBlbXB0eSBzdHJpbmcuIElmIGxlZnQgdW5kZWZpbmVkLCB0YWtlbiBmcm9tIHRoZSBVUkwuXG4gICAgICAgICAqIEB0eXBlIHtTdHJpbmd9XG4gICAgICAgICAqL1xuICAgICAgICBwcm9qZWN0OiB1bmRlZmluZWQsXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIEZvciBvcGVyYXRpb25zIHRoYXQgcmVxdWlyZSBhdXRoZW50aWNhdGlvbiwgcGFzcyBpbiB0aGUgdXNlciBhY2Nlc3MgdG9rZW4gKGRlZmF1bHRzIHRvIGVtcHR5IHN0cmluZykuIElmIHRoZSB1c2VyIGlzIGFscmVhZHkgbG9nZ2VkIGluIHRvIEVwaWNlbnRlciwgdGhlIHVzZXIgYWNjZXNzIHRva2VuIGlzIGFscmVhZHkgc2V0IGluIGEgY29va2llIGFuZCBhdXRvbWF0aWNhbGx5IGxvYWRlZCBmcm9tIHRoZXJlLiAoU2VlIFttb3JlIGJhY2tncm91bmQgb24gYWNjZXNzIHRva2Vuc10oLi4vLi4vLi4vcHJvamVjdF9hY2Nlc3MvKSkuXG4gICAgICAgICAqIEBzZWUgW0F1dGhlbnRpY2F0aW9uIEFQSSBTZXJ2aWNlXSguLi9hdXRoLWFwaS1zZXJ2aWNlLykgZm9yIGdldHRpbmcgdG9rZW5zLlxuICAgICAgICAgKiBAdHlwZSB7U3RyaW5nfVxuICAgICAgICAgKi9cbiAgICAgICAgdG9rZW46IHVuZGVmaW5lZCxcblxuICAgICAgICAvL09wdGlvbnMgdG8gcGFzcyBvbiB0byB0aGUgdW5kZXJseWluZyB0cmFuc3BvcnQgbGF5ZXJcbiAgICAgICAgdHJhbnNwb3J0OiB7fVxuICAgIH07XG4gICAgdGhpcy5zZXNzaW9uTWFuYWdlciA9IG5ldyBTZXNzaW9uTWFuYWdlcigpO1xuICAgIHZhciBzZXJ2aWNlT3B0aW9ucyA9IHRoaXMuc2Vzc2lvbk1hbmFnZXIuZ2V0TWVyZ2VkT3B0aW9ucyhkZWZhdWx0cywgY29uZmlnKTtcblxuICAgIHZhciB1cmxDb25maWcgPSBuZXcgQ29uZmlnU2VydmljZShzZXJ2aWNlT3B0aW9ucykuZ2V0KCdzZXJ2ZXInKTtcbiAgICBpZiAoc2VydmljZU9wdGlvbnMuYWNjb3VudCkge1xuICAgICAgICB1cmxDb25maWcuYWNjb3VudFBhdGggPSBzZXJ2aWNlT3B0aW9ucy5hY2NvdW50O1xuICAgIH1cbiAgICBpZiAoc2VydmljZU9wdGlvbnMucHJvamVjdCkge1xuICAgICAgICB1cmxDb25maWcucHJvamVjdFBhdGggPSBzZXJ2aWNlT3B0aW9ucy5wcm9qZWN0O1xuICAgIH1cblxuICAgIHZhciBnZXRVUkwgPSBmdW5jdGlvbiAoa2V5LCByb290KSB7XG4gICAgICAgIGlmICghcm9vdCkge1xuICAgICAgICAgICAgcm9vdCA9IHNlcnZpY2VPcHRpb25zLnJvb3Q7XG4gICAgICAgIH1cbiAgICAgICAgdmFyIHVybCA9IHVybENvbmZpZy5nZXRBUElQYXRoKCdkYXRhJykgKyBxdXRpbC5hZGRUcmFpbGluZ1NsYXNoKHJvb3QpO1xuICAgICAgICBpZiAoa2V5KSB7XG4gICAgICAgICAgICB1cmwrPSBxdXRpbC5hZGRUcmFpbGluZ1NsYXNoKGtleSk7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIHVybDtcbiAgICB9O1xuXG4gICAgdmFyIGh0dHBPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sIHNlcnZpY2VPcHRpb25zLnRyYW5zcG9ydCwge1xuICAgICAgICB1cmw6IGdldFVSTFxuICAgIH0pO1xuICAgIGlmIChzZXJ2aWNlT3B0aW9ucy50b2tlbikge1xuICAgICAgICBodHRwT3B0aW9ucy5oZWFkZXJzID0ge1xuICAgICAgICAgICAgJ0F1dGhvcml6YXRpb24nOiAnQmVhcmVyICcgKyBzZXJ2aWNlT3B0aW9ucy50b2tlblxuICAgICAgICB9O1xuICAgIH1cbiAgICB2YXIgaHR0cCA9IG5ldyBUcmFuc3BvcnRGYWN0b3J5KGh0dHBPcHRpb25zKTtcblxuICAgIHZhciBwdWJsaWNBUEkgPSB7XG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIFNlYXJjaCBmb3IgZGF0YSB3aXRoaW4gYSBjb2xsZWN0aW9uLlxuICAgICAgICAgKlxuICAgICAgICAgKiBTZWFyY2hpbmcgdXNpbmcgY29tcGFyaXNvbiBvciBsb2dpY2FsIG9wZXJhdG9ycyAoYXMgb3Bwb3NlZCB0byBleGFjdCBtYXRjaGVzKSByZXF1aXJlcyBNb25nb0RCIHN5bnRheC4gU2VlIHRoZSB1bmRlcmx5aW5nIFtEYXRhIEFQSV0oLi4vLi4vLi4vcmVzdF9hcGlzL2RhdGFfYXBpLyNzZWFyY2hpbmcpIGZvciBhZGRpdGlvbmFsIGRldGFpbHMuXG4gICAgICAgICAqXG4gICAgICAgICAqICoqRXhhbXBsZXMqKlxuICAgICAgICAgKlxuICAgICAgICAgKiAgICAgIC8vIHJlcXVlc3QgYWxsIGRhdGEgYXNzb2NpYXRlZCB3aXRoIGRvY3VtZW50ICd1c2VyMSdcbiAgICAgICAgICogICAgICBkcy5xdWVyeSgndXNlcjEnKTtcbiAgICAgICAgICpcbiAgICAgICAgICogICAgICAvLyBleGFjdCBtYXRjaGluZzpcbiAgICAgICAgICogICAgICAvLyByZXF1ZXN0IGFsbCBkb2N1bWVudHMgaW4gY29sbGVjdGlvbiB3aGVyZSAncXVlc3Rpb24yJyBpcyA5XG4gICAgICAgICAqICAgICAgZHMucXVlcnkoJycsIHsgJ3F1ZXN0aW9uMic6IDl9KTtcbiAgICAgICAgICpcbiAgICAgICAgICogICAgICAvLyBjb21wYXJpc29uIG9wZXJhdG9yczpcbiAgICAgICAgICogICAgICAvLyByZXF1ZXN0IGFsbCBkb2N1bWVudHMgaW4gY29sbGVjdGlvblxuICAgICAgICAgKiAgICAgIC8vIHdoZXJlICdxdWVzdGlvbjInIGlzIGdyZWF0ZXIgdGhhbiA5XG4gICAgICAgICAqICAgICAgZHMucXVlcnkoJycsIHsgJ3F1ZXN0aW9uMic6IHsgJyRndCc6IDl9IH0pO1xuICAgICAgICAgKlxuICAgICAgICAgKiAgICAgIC8vIGxvZ2ljYWwgb3BlcmF0b3JzOlxuICAgICAgICAgKiAgICAgIC8vIHJlcXVlc3QgYWxsIGRvY3VtZW50cyBpbiBjb2xsZWN0aW9uXG4gICAgICAgICAqICAgICAgLy8gd2hlcmUgJ3F1ZXN0aW9uMicgaXMgbGVzcyB0aGFuIDEwLCBhbmQgJ3F1ZXN0aW9uMycgaXMgZmFsc2VcbiAgICAgICAgICogICAgICBkcy5xdWVyeSgnJywgeyAnJGFuZCc6IFsgeyAncXVlc3Rpb24yJzogeyAnJGx0JzoxMH0gfSwgeyAncXVlc3Rpb24zJzogZmFsc2UgfV0gfSk7XG4gICAgICAgICAqXG4gICAgICAgICAqICAgICAgLy8gcmVndWxhciBleHByZXNzc2lvbnM6IHVzZSBhbnkgUGVybC1jb21wYXRpYmxlIHJlZ3VsYXIgZXhwcmVzc2lvbnNcbiAgICAgICAgICogICAgICAvLyByZXF1ZXN0IGFsbCBkb2N1bWVudHMgaW4gY29sbGVjdGlvblxuICAgICAgICAgKiAgICAgIC8vIHdoZXJlICdxdWVzdGlvbjUnIGNvbnRhaW5zIHRoZSBzdHJpbmcgJy4qZGF5J1xuICAgICAgICAgKiAgICAgIGRzLnF1ZXJ5KCcnLCB7ICdxdWVzdGlvbjUnOiB7ICckcmVnZXgnOiAnLipkYXknIH0gfSk7XG4gICAgICAgICAqXG4gICAgICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICAgICAqIEBwYXJhbSB7U3RyaW5nfSBga2V5YCBUaGUgbmFtZSBvZiB0aGUgZG9jdW1lbnQgdG8gc2VhcmNoLiBQYXNzIHRoZSBlbXB0eSBzdHJpbmcgKCcnKSB0byBzZWFyY2ggdGhlIGVudGlyZSBjb2xsZWN0aW9uLlxuICAgICAgICAgKiBAcGFyYW0ge09iamVjdH0gYHF1ZXJ5YCBUaGUgcXVlcnkgb2JqZWN0LiBGb3IgZXhhY3QgbWF0Y2hpbmcsIHRoaXMgb2JqZWN0IGNvbnRhaW5zIHRoZSBmaWVsZCBuYW1lIGFuZCBmaWVsZCB2YWx1ZSB0byBtYXRjaC4gRm9yIG1hdGNoaW5nIGJhc2VkIG9uIGNvbXBhcmlzb24sIHRoaXMgb2JqZWN0IGNvbnRhaW5zIHRoZSBmaWVsZCBuYW1lIGFuZCB0aGUgY29tcGFyaXNvbiBleHByZXNzaW9uLiBGb3IgbWF0Y2hpbmcgYmFzZWQgb24gbG9naWNhbCBvcGVyYXRvcnMsIHRoaXMgb2JqZWN0IGNvbnRhaW5zIGFuIGV4cHJlc3Npb24gdXNpbmcgTW9uZ29EQiBzeW50YXguIFNlZSB0aGUgdW5kZXJseWluZyBbRGF0YSBBUEldKC4uLy4uLy4uL3Jlc3RfYXBpcy9kYXRhX2FwaS8jc2VhcmNoaW5nKSBmb3IgYWRkaXRpb25hbCBleGFtcGxlcy5cbiAgICAgICAgICogQHBhcmFtIHtPYmplY3R9IGBvdXRwdXRNb2RpZmllcmAgKE9wdGlvbmFsKSBBdmFpbGFibGUgZmllbGRzIGluY2x1ZGU6IGBzdGFydHJlY29yZGAsIGBlbmRyZWNvcmRgLCBgc29ydGAsIGFuZCBgZGlyZWN0aW9uYCAoYGFzY2Agb3IgYGRlc2NgKS5cbiAgICAgICAgICogQHBhcmFtIHtPYmplY3R9IGBvcHRpb25zYCAoT3B0aW9uYWwpIE92ZXJyaWRlcyBmb3IgY29uZmlndXJhdGlvbiBvcHRpb25zLlxuICAgICAgICAgKlxuICAgICAgICAgKi9cbiAgICAgICAgcXVlcnk6IGZ1bmN0aW9uIChrZXksIHF1ZXJ5LCBvdXRwdXRNb2RpZmllciwgb3B0aW9ucykge1xuICAgICAgICAgICAgdmFyIHBhcmFtcyA9ICQuZXh0ZW5kKHRydWUsIHsgcTogcXVlcnkgfSwgb3V0cHV0TW9kaWZpZXIpO1xuICAgICAgICAgICAgdmFyIGh0dHBPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sIHNlcnZpY2VPcHRpb25zLCBvcHRpb25zKTtcbiAgICAgICAgICAgIGh0dHBPcHRpb25zLnVybCA9IGdldFVSTChrZXksIGh0dHBPcHRpb25zLnJvb3QpO1xuICAgICAgICAgICAgcmV0dXJuIGh0dHAuZ2V0KHBhcmFtcywgaHR0cE9wdGlvbnMpO1xuICAgICAgICB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBTYXZlIGRhdGEgdG8gYW4gYW5vbnltb3VzIGRvY3VtZW50IHdpdGhpbiB0aGUgY29sbGVjdGlvbi5cbiAgICAgICAgICpcbiAgICAgICAgICogKERvY3VtZW50cyBhcmUgdG9wLWxldmVsIGVsZW1lbnRzIHdpdGhpbiBhIGNvbGxlY3Rpb24uIENvbGxlY3Rpb25zIG11c3QgYmUgdW5pcXVlIHdpdGhpbiB0aGlzIGFjY291bnQgKHRlYW0gb3IgcGVyc29uYWwgYWNjb3VudCkgYW5kIHByb2plY3QgYW5kIGFyZSBzZXQgd2l0aCB0aGUgYHJvb3RgIGZpZWxkIGluIHRoZSBgb3B0aW9uYCBwYXJhbWV0ZXIuIFNlZSB0aGUgdW5kZXJseWluZyBbRGF0YSBBUEldKC4uLy4uLy4uL3Jlc3RfYXBpcy9kYXRhX2FwaS8pIGZvciBhZGRpdGlvbmFsIGJhY2tncm91bmQuKVxuICAgICAgICAgKlxuICAgICAgICAgKiAqKkV4YW1wbGUqKlxuICAgICAgICAgKlxuICAgICAgICAgKiAgICAgIGRzLnNhdmUoJ3F1ZXN0aW9uMScsICd5ZXMnKTtcbiAgICAgICAgICogICAgICBkcy5zYXZlKHtxdWVzdGlvbjE6J3llcycsIHF1ZXN0aW9uMjogMzIgfSk7XG4gICAgICAgICAqICAgICAgZHMuc2F2ZSh7IG5hbWU6J0pvaG4nLCBjbGFzc05hbWU6ICdDUzEwMScgfSwgeyByb290OiAnc3R1ZGVudHMnIH0pO1xuICAgICAgICAgKlxuICAgICAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAgKlxuICAgICAgICAgKiBAcGFyYW0ge1N0cmluZ3xPYmplY3R9IGBrZXlgIElmIGBrZXlgIGlzIGEgc3RyaW5nLCBpdCBpcyB0aGUgaWQgb2YgdGhlIGVsZW1lbnQgdG8gc2F2ZSAoY3JlYXRlKSBpbiB0aGlzIGRvY3VtZW50LiBJZiBga2V5YCBpcyBhbiBvYmplY3QsIHRoZSBvYmplY3QgaXMgdGhlIGRhdGEgdG8gc2F2ZSAoY3JlYXRlKSBpbiB0aGlzIGRvY3VtZW50LiBJbiBib3RoIGNhc2VzLCB0aGUgaWQgZm9yIHRoZSBkb2N1bWVudCBpcyBnZW5lcmF0ZWQgYXV0b21hdGljYWxseS5cbiAgICAgICAgICogQHBhcmFtIHtPYmplY3R9IGB2YWx1ZWAgKE9wdGlvbmFsKSBUaGUgZGF0YSB0byBzYXZlLiBJZiBga2V5YCBpcyBhIHN0cmluZywgdGhpcyBpcyB0aGUgdmFsdWUgdG8gc2F2ZS4gSWYgYGtleWAgaXMgYW4gb2JqZWN0LCB0aGUgdmFsdWUocykgdG8gc2F2ZSBhcmUgYWxyZWFkeSBwYXJ0IG9mIGBrZXlgIGFuZCB0aGlzIGFyZ3VtZW50IGlzIG5vdCByZXF1aXJlZC5cbiAgICAgICAgICogQHBhcmFtIHtPYmplY3R9IGBvcHRpb25zYCAoT3B0aW9uYWwpIE92ZXJyaWRlcyBmb3IgY29uZmlndXJhdGlvbiBvcHRpb25zLlxuICAgICAgICAgKi9cbiAgICAgICAgc2F2ZTogZnVuY3Rpb24gKGtleSwgdmFsdWUsIG9wdGlvbnMpIHtcbiAgICAgICAgICAgIHZhciBhdHRycztcbiAgICAgICAgICAgIGlmICh0eXBlb2Yga2V5ID09PSAnb2JqZWN0Jykge1xuICAgICAgICAgICAgICAgIGF0dHJzID0ga2V5O1xuICAgICAgICAgICAgICAgIG9wdGlvbnMgPSB2YWx1ZTtcbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgKGF0dHJzID0ge30pW2tleV0gPSB2YWx1ZTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHZhciBodHRwT3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LCBzZXJ2aWNlT3B0aW9ucywgb3B0aW9ucyk7XG4gICAgICAgICAgICBodHRwT3B0aW9ucy51cmwgPSBnZXRVUkwoJycsIGh0dHBPcHRpb25zLnJvb3QpO1xuXG4gICAgICAgICAgICByZXR1cm4gaHR0cC5wb3N0KGF0dHJzLCBodHRwT3B0aW9ucyk7XG4gICAgICAgIH0sXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIFNhdmUgZGF0YSB0byBhIG5hbWVkIGRvY3VtZW50IG9yIGVsZW1lbnQgd2l0aGluIHRoZSBjb2xsZWN0aW9uLiBUaGUgYHJvb3RgIG9mIHRoZSBjb2xsZWN0aW9uIG11c3QgYmUgc3BlY2lmaWVkIHNlcGFyYXRlbHkgaW4gY29uZmlndXJhdGlvbiBvcHRpb25zLCBlaXRoZXIgYXMgcGFydCBvZiB0aGUgY2FsbCBvciBhcyBwYXJ0IG9mIHRoZSBpbml0aWFsaXphdGlvbiBvZiBkcy5cbiAgICAgICAgICpcbiAgICAgICAgICogKERvY3VtZW50cyBhcmUgdG9wLWxldmVsIGVsZW1lbnRzIHdpdGhpbiBhIGNvbGxlY3Rpb24uIENvbGxlY3Rpb25zIG11c3QgYmUgdW5pcXVlIHdpdGhpbiB0aGlzIGFjY291bnQgKHRlYW0gb3IgcGVyc29uYWwgYWNjb3VudCkgYW5kIHByb2plY3QgYW5kIGFyZSBzZXQgd2l0aCB0aGUgYHJvb3RgIGZpZWxkIGluIHRoZSBgb3B0aW9uYCBwYXJhbWV0ZXIuIFNlZSB0aGUgdW5kZXJseWluZyBbRGF0YSBBUEldKC4uLy4uLy4uL3Jlc3RfYXBpcy9kYXRhX2FwaS8pIGZvciBhZGRpdGlvbmFsIGJhY2tncm91bmQuKVxuICAgICAgICAgKlxuICAgICAgICAgKiAqKkV4YW1wbGUqKlxuICAgICAgICAgKlxuICAgICAgICAgKiAgICAgIGRzLnNhdmVBcygndXNlcjEnLFxuICAgICAgICAgKiAgICAgICAgICB7ICdxdWVzdGlvbjEnOiAyLCAncXVlc3Rpb24yJzogMTAsXG4gICAgICAgICAqICAgICAgICAgICAncXVlc3Rpb24zJzogZmFsc2UsICdxdWVzdGlvbjQnOiAnc29tZXRpbWVzJyB9ICk7XG4gICAgICAgICAqICAgICAgZHMuc2F2ZUFzKCdzdHVkZW50MScsXG4gICAgICAgICAqICAgICAgICAgIHsgZmlyc3ROYW1lOiAnam9obicsIGxhc3ROYW1lOiAnc21pdGgnIH0sXG4gICAgICAgICAqICAgICAgICAgIHsgcm9vdDogJ3N0dWRlbnRzJyB9KTtcbiAgICAgICAgICogICAgICBkcy5zYXZlQXMoJ21nbXQxMDAvZ3JvdXBCJyxcbiAgICAgICAgICogICAgICAgICAgeyBzY2VuYXJpb1llYXI6ICcyMDE1JyB9LFxuICAgICAgICAgKiAgICAgICAgICB7IHJvb3Q6ICdteWNsYXNzZXMnIH0pO1xuICAgICAgICAgKlxuICAgICAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAgKlxuICAgICAgICAgKiBAcGFyYW0ge1N0cmluZ30gYGtleWAgSWQgb2YgdGhlIGRvY3VtZW50LlxuICAgICAgICAgKiBAcGFyYW0ge09iamVjdH0gYHZhbHVlYCAoT3B0aW9uYWwpIFRoZSBkYXRhIHRvIHNhdmUsIGluIGtleTp2YWx1ZSBwYWlycy5cbiAgICAgICAgICogQHBhcmFtIHtPYmplY3R9IGBvcHRpb25zYCAoT3B0aW9uYWwpIE92ZXJyaWRlcyBmb3IgY29uZmlndXJhdGlvbiBvcHRpb25zLlxuICAgICAgICAgKi9cbiAgICAgICAgc2F2ZUFzOiBmdW5jdGlvbiAoa2V5LCB2YWx1ZSwgb3B0aW9ucykge1xuICAgICAgICAgICAgdmFyIGh0dHBPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sIHNlcnZpY2VPcHRpb25zLCBvcHRpb25zKTtcbiAgICAgICAgICAgIGh0dHBPcHRpb25zLnVybCA9IGdldFVSTChrZXksIGh0dHBPcHRpb25zLnJvb3QpO1xuXG4gICAgICAgICAgICByZXR1cm4gaHR0cC5wdXQodmFsdWUsIGh0dHBPcHRpb25zKTtcbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgICogR2V0IGRhdGEgZm9yIGEgc3BlY2lmaWMgZG9jdW1lbnQgb3IgZmllbGQuXG4gICAgICAgICAqXG4gICAgICAgICAqICoqRXhhbXBsZSoqXG4gICAgICAgICAqXG4gICAgICAgICAqICAgICAgZHMubG9hZCgndXNlcjEnKTtcbiAgICAgICAgICogICAgICBkcy5sb2FkKCd1c2VyMS9xdWVzdGlvbjMnKTtcbiAgICAgICAgICpcbiAgICAgICAgICogKipQYXJhbWV0ZXJzKipcbiAgICAgICAgICogQHBhcmFtICB7U3RyaW5nfE9iamVjdH0gYGtleWAgVGhlIGlkIG9mIHRoZSBkYXRhIHRvIHJldHVybi4gQ2FuIGJlIHRoZSBpZCBvZiBhIGRvY3VtZW50LCBvciBhIHBhdGggdG8gZGF0YSB3aXRoaW4gdGhhdCBkb2N1bWVudC5cbiAgICAgICAgICogQHBhcmFtIHtPYmplY3R9IGBvdXRwdXRNb2RpZmllcmAgKE9wdGlvbmFsKSBBdmFpbGFibGUgZmllbGRzIGluY2x1ZGU6IGBzdGFydHJlY29yZGAsIGBlbmRyZWNvcmRgLCBgc29ydGAsIGFuZCBgZGlyZWN0aW9uYCAoYGFzY2Agb3IgYGRlc2NgKS5cbiAgICAgICAgICogQHBhcmFtIHtPYmplY3R9IGBvcHRpb25zYCBPdmVycmlkZXMgZm9yIGNvbmZpZ3VyYXRpb24gb3B0aW9ucy5cbiAgICAgICAgICovXG4gICAgICAgIGxvYWQ6IGZ1bmN0aW9uIChrZXksIG91dHB1dE1vZGlmaWVyLCBvcHRpb25zKSB7XG4gICAgICAgICAgICB2YXIgaHR0cE9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSwgc2VydmljZU9wdGlvbnMsIG9wdGlvbnMpO1xuICAgICAgICAgICAgaHR0cE9wdGlvbnMudXJsID0gZ2V0VVJMKGtleSwgaHR0cE9wdGlvbnMucm9vdCk7XG4gICAgICAgICAgICByZXR1cm4gaHR0cC5nZXQob3V0cHV0TW9kaWZpZXIsIGh0dHBPcHRpb25zKTtcbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgICogUmVtb3ZlcyBkYXRhIGZyb20gY29sbGVjdGlvbi4gT25seSBkb2N1bWVudHMgKHRvcC1sZXZlbCBlbGVtZW50cyBpbiBlYWNoIGNvbGxlY3Rpb24pIGNhbiBiZSBkZWxldGVkLlxuICAgICAgICAgKlxuICAgICAgICAgKiAqKkV4YW1wbGUqKlxuICAgICAgICAgKlxuICAgICAgICAgKiAgICAgZHMucmVtb3ZlKCd1c2VyMScpO1xuICAgICAgICAgKlxuICAgICAgICAgKlxuICAgICAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAgKlxuICAgICAgICAgKiBAcGFyYW0ge1N0cmluZ3xBcnJheX0gYGtleXNgIFRoZSBpZCBvZiB0aGUgZG9jdW1lbnQgdG8gcmVtb3ZlIGZyb20gdGhpcyBjb2xsZWN0aW9uLCBvciBhbiBhcnJheSBvZiBzdWNoIGlkcy5cbiAgICAgICAgICogQHBhcmFtIHtPYmplY3R9IGBvcHRpb25zYCAoT3B0aW9uYWwpIE92ZXJyaWRlcyBmb3IgY29uZmlndXJhdGlvbiBvcHRpb25zLlxuICAgICAgICAgKi9cbiAgICAgICAgcmVtb3ZlOiBmdW5jdGlvbiAoa2V5cywgb3B0aW9ucykge1xuICAgICAgICAgICAgdmFyIGh0dHBPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sIHNlcnZpY2VPcHRpb25zLCBvcHRpb25zKTtcbiAgICAgICAgICAgIHZhciBwYXJhbXM7XG4gICAgICAgICAgICBpZiAoJC5pc0FycmF5KGtleXMpKSB7XG4gICAgICAgICAgICAgICAgcGFyYW1zID0geyBpZDoga2V5cyB9O1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICBwYXJhbXMgPSAnJztcbiAgICAgICAgICAgICAgICBodHRwT3B0aW9ucy51cmwgPSBnZXRVUkwoa2V5cywgaHR0cE9wdGlvbnMucm9vdCk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICByZXR1cm4gaHR0cC5kZWxldGUocGFyYW1zLCBodHRwT3B0aW9ucyk7XG4gICAgICAgIH1cblxuICAgICAgICAvLyBFcGljZW50ZXIgZG9lc24ndCBhbGxvdyBudWtpbmcgY29sbGVjdGlvbnNcbiAgICAgICAgLy8gICAgIC8qKlxuICAgICAgICAvLyAgICAgICogUmVtb3ZlcyBjb2xsZWN0aW9uIGJlaW5nIHJlZmVyZW5jZWRcbiAgICAgICAgLy8gICAgICAqIEByZXR1cm4gbnVsbFxuICAgICAgICAvLyAgICAgICovXG4gICAgICAgIC8vICAgICBkZXN0cm95OiBmdW5jdGlvbiAob3B0aW9ucykge1xuICAgICAgICAvLyAgICAgICAgIHJldHVybiB0aGlzLnJlbW92ZSgnJywgb3B0aW9ucyk7XG4gICAgICAgIC8vICAgICB9XG4gICAgfTtcblxuICAgICQuZXh0ZW5kKHRoaXMsIHB1YmxpY0FQSSk7XG59O1xuIiwiLyoqXG4gKlxuICogIyMgSW50cm9zcGVjdGlvbiBBUEkgU2VydmljZVxuICpcbiAqIFVzZWQgaW4gY29uanVuY3Rpb24gd2l0aCB0aGUgW1J1biBBUEkgU2VydmljZV0oLi4vcnVuLWFwaS1zZXJ2aWNlLykgdG8gYWNjZXNzIE5hdGl2ZSBETVMgMyBJbnRyb3NwZWN0aW9uIGNhbGxzXG4gKlxuICogICAgIHZhciBybSA9IG5ldyBGLm1hbmFnZXIuUnVuTWFuYWdlcih7XG4gKiAgICAgICAgICAgcnVuOiB7XG4gKiAgICAgICAgICAgICAgIGFjY291bnQ6ICdhY21lLXNpbXVsYXRpb25zJyxcbiAqICAgICAgICAgICAgICAgcHJvamVjdDogJ3N1cHBseS1jaGFpbi1nYW1lJyxcbiAqICAgICAgICAgICAgICAgbW9kZWw6ICdzdXBwbHktY2hhaW4tbW9kZWwuamwnXG4gKiAgICAgICAgICAgfVxuICogICAgICB9KTtcbiAqICAgICBybS5nZXRSdW4oKVxuICogICAgICAgLnRoZW4oZnVuY3Rpb24oKSB7XG4gKiAgICAgICAgICB2YXIgaXMgPSBybS5ydW4uaW50cm9zcGVjdGlvbigpO1xuICogICAgICAgIH0pO1xuICpcbiAqL1xuXG4ndXNlIHN0cmljdCc7XG5cbnZhciBDb25maWdTZXJ2aWNlID0gcmVxdWlyZSgnLi9jb25maWd1cmF0aW9uLXNlcnZpY2UnKTtcbnZhciBUcmFuc3BvcnRGYWN0b3J5ID0gcmVxdWlyZSgnLi4vdHJhbnNwb3J0L2h0dHAtdHJhbnNwb3J0LWZhY3RvcnknKTtcblxubW9kdWxlLmV4cG9ydHMgPSBmdW5jdGlvbiAoY29uZmlnKSB7XG4gICAgdmFyIGRlZmF1bHRzID0ge1xuICAgICAgICBzZXJ2ZXI6IHtcbiAgICAgICAgICAgIHZlcnNpb25QYXRoOiAndjMvJ1xuICAgICAgICB9XG4gICAgfTtcbiAgICB2YXIgc2VydmljZU9wdGlvbnMgPSAkLmV4dGVuZCh7fSwgZGVmYXVsdHMsIGNvbmZpZyk7XG5cbiAgICB2YXIgdXJsQ29uZmlnID0gbmV3IENvbmZpZ1NlcnZpY2Uoc2VydmljZU9wdGlvbnMpLmdldCgnc2VydmVyJyk7XG4gICAgaWYgKHNlcnZpY2VPcHRpb25zLmFjY291bnQpIHtcbiAgICAgICAgdXJsQ29uZmlnLmFjY291bnRQYXRoID0gc2VydmljZU9wdGlvbnMuYWNjb3VudDtcbiAgICB9XG4gICAgaWYgKHNlcnZpY2VPcHRpb25zLnByb2plY3QpIHtcbiAgICAgICAgdXJsQ29uZmlnLnByb2plY3RQYXRoID0gc2VydmljZU9wdGlvbnMucHJvamVjdDtcbiAgICB9XG5cbiAgICB1cmxDb25maWcuZmlsdGVyID0gJzsnO1xuXG4gICAgdmFyIGh0dHBPcHRpb25zID0ge1xuICAgICAgICB1cmw6IHVybENvbmZpZy5nZXRBUElQYXRoKCdtb2RlbCcpICsgJ3B1Ymxpc2gnXG4gICAgfTtcbiAgICBpZiAoc2VydmljZU9wdGlvbnMudG9rZW4pIHtcbiAgICAgICAgaHR0cE9wdGlvbnMuaGVhZGVycyA9IHtcbiAgICAgICAgICAgICdBdXRob3JpemF0aW9uJzogJ0JlYXJlciAnICsgc2VydmljZU9wdGlvbnMudG9rZW5cbiAgICAgICAgfTtcbiAgICB9XG4gICAgdmFyIGh0dHAgPSBuZXcgVHJhbnNwb3J0RmFjdG9yeShodHRwT3B0aW9ucyk7XG5cbiAgICB2YXIgcHVibGljQVBJID0ge1xuICAgICAgICAvKipcbiAgICAgICAgICogR2V0IHRoZSBhdmFpbGFibGUgRnVuY3Rpb25zIGFuZCBWYXJpYWJsZXNcbiAgICAgICAgICpcbiAgICAgICAgICogKipFeGFtcGxlKipcbiAgICAgICAgICpcbiAgICAgICAgICogICAgICB2cy5nZXQoKVxuICAgICAgICAgKiAgICAgICAgICAudGhlbihmdW5jdGlvbihkYXRhKSB7XG4gICAgICAgICAqICAgICAgICAgICAgICAvLyBkYXRhIGNvbnRhaW5zIGFuIG9iamVjdCB3aXRoIGF2YWlsYWJsZSBmdW5jdGlvbnMgKHVzZWQgd2l0aCBvcGVyYXRpb25zIEFQSSkgYW5kIGF2YWlsYWJsZSB2YXJpYWJsZXMgKHVzZWQgd2l0aCB2YXJpYWJsZXMgQVBJKVxuICAgICAgICAgKiAgICAgICAgICAgICAgY29uc29sZS5sb2coZGF0YS5mdW5jdGlvbnMpO1xuICAgICAgICAgKiAgICAgICAgICAgICAgY29uc29sZS5sb2coZGF0YS52YXJpYWJsZXMpO1xuICAgICAgICAgKiAgICAgICAgICB9KTtcbiAgICAgICAgICpcbiAgICAgICAgICogKipQYXJhbWV0ZXJzKipcbiAgICAgICAgICogQHBhcmFtICB7U3RyaW5nfSBgcnVuSWRgICAgKE9wdGlvbmFsKSBPdmVycmlkZXMgdGhlIHJ1biBpZCB1c2VkIHdoZW4gdGhlIHNlcnZpY2Ugd2FzIGNyZWF0ZWRcbiAgICAgICAgICogQHBhcmFtICB7T2JqZWN0fSBgb3B0aW9uc2AgKE9wdGlvbmFsKSBPdmVycmlkZXMgZm9yIGNvbmZpZ3VyYXRpb24gb3B0aW9ucy5cbiAgICAgICAgICovXG4gICAgICAgIGdldDogZnVuY3Rpb24gKHJ1bklkLCBvcHRpb25zKSB7XG4gICAgICAgICAgICB2YXIgaHR0cE9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSwgc2VydmljZU9wdGlvbnMsIG9wdGlvbnMpO1xuICAgICAgICAgICAgdmFyIHBhcmFtcyA9IHtcbiAgICAgICAgICAgICAgICBydW5JZDogcnVuSWQgfHwgaHR0cE9wdGlvbnMuZmlsdGVyLFxuICAgICAgICAgICAgICAgIGNvbW1hbmRXcmFwcGVyOiB7IGNvbW1hbmQ6IHsgaW50cm9zcGVjdDoge30gfSB9LFxuICAgICAgICAgICAgICAgIHJlYW5pbWF0ZTogZmFsc2VcbiAgICAgICAgICAgIH07XG4gICAgICAgICAgICByZXR1cm4gaHR0cC5wb3N0KHBhcmFtcywgaHR0cE9wdGlvbnMpO1xuICAgICAgICB9XG4gICAgfTtcbiAgICAkLmV4dGVuZCh0aGlzLCBwdWJsaWNBUEkpO1xufTtcbiIsIi8qKlxuICpcbiAqICMjIE1lbWJlciBBUEkgQWRhcHRlclxuICpcbiAqIFRoZSBNZW1iZXIgQVBJIEFkYXB0ZXIgcHJvdmlkZXMgbWV0aG9kcyB0byBsb29rIHVwIGluZm9ybWF0aW9uIGFib3V0IGVuZCB1c2VycyBmb3IgeW91ciBwcm9qZWN0IGFuZCBob3cgdGhleSBhcmUgZGl2aWRlZCBhY3Jvc3MgZ3JvdXBzLiBJdCBpcyBiYXNlZCBvbiBxdWVyeSBjYXBhYmlsaXRpZXMgb2YgdGhlIHVuZGVybHlpbmcgUkVTVGZ1bCBbTWVtYmVyIEFQSV0oLi4vLi4vLi4vcmVzdF9hcGlzL3VzZXJfbWFuYWdlbWVudC9tZW1iZXIvKS5cbiAqXG4gKiBUaGlzIGlzIG9ubHkgbmVlZGVkIGZvciBBdXRoZW50aWNhdGVkIHByb2plY3RzLCB0aGF0IGlzLCB0ZWFtIHByb2plY3RzIHdpdGggW2VuZCB1c2VycyBhbmQgZ3JvdXBzXSguLi8uLi8uLi9ncm91cHNfYW5kX2VuZF91c2Vycy8pLiBGb3IgZXhhbXBsZSwgaWYgc29tZSBvZiB5b3VyIGVuZCB1c2VycyBhcmUgZmFjaWxpdGF0b3JzLCBvciBpZiB5b3VyIGVuZCB1c2VycyBzaG91bGQgYmUgdHJlYXRlZCBkaWZmZXJlbnRseSBiYXNlZCBvbiB3aGljaCBncm91cCB0aGV5IGFyZSBpbiwgdXNlIHRoZSBNZW1iZXIgQVBJIHRvIGZpbmQgdGhhdCBpbmZvcm1hdGlvbi5cbiAqXG4gKiAgICAgIHZhciBtYSA9IG5ldyBGLnNlcnZpY2UuTWVtYmVyKHsgdG9rZW46ICd1c2VyLW9yLXByb2plY3QtYWNjZXNzLXRva2VuJyB9KTtcbiAqICAgICAgbWEuZ2V0R3JvdXBzRm9yVXNlcih7IHVzZXJJZDogJ2I2YjMxM2EzLWFiODQtNDc5Yy1iYWVhLTIwNmY2YmZmMzM3JyB9KTtcbiAqICAgICAgbWEuZ2V0R3JvdXBEZXRhaWxzKHsgZ3JvdXBJZDogJzAwYjUzMzA4LTk4MzMtNDdmMi1iMjFlLTEyNzhjMDdkNTNiOCcgfSk7XG4gKi9cblxuJ3VzZSBzdHJpY3QnO1xuXG52YXIgQ29uZmlnU2VydmljZSA9IHJlcXVpcmUoJy4vY29uZmlndXJhdGlvbi1zZXJ2aWNlJyk7XG52YXIgVHJhbnNwb3J0RmFjdG9yeSA9IHJlcXVpcmUoJy4uL3RyYW5zcG9ydC9odHRwLXRyYW5zcG9ydC1mYWN0b3J5Jyk7XG52YXIgU2Vzc2lvbk1hbmFnZXIgPSByZXF1aXJlKCcuLi9zdG9yZS9zZXNzaW9uLW1hbmFnZXInKTtcbnZhciBfcGljayA9IHJlcXVpcmUoJy4uL3V0aWwvb2JqZWN0LXV0aWwnKS5fcGljaztcbnZhciBhcGlFbmRwb2ludCA9ICdtZW1iZXIvbG9jYWwnO1xuXG5tb2R1bGUuZXhwb3J0cyA9IGZ1bmN0aW9uIChjb25maWcpIHtcbiAgICB2YXIgZGVmYXVsdHMgPSB7XG4gICAgICAgIC8qKlxuICAgICAgICAgKiBFcGljZW50ZXIgdXNlciBpZC4gRGVmYXVsdHMgdG8gYSBibGFuayBzdHJpbmcuXG4gICAgICAgICAqIEB0eXBlIHtzdHJpbmd9XG4gICAgICAgICAqL1xuICAgICAgICB1c2VySWQ6IHVuZGVmaW5lZCxcblxuICAgICAgICAvKipcbiAgICAgICAgICogRXBpY2VudGVyIGdyb3VwIGlkLiBEZWZhdWx0cyB0byBhIGJsYW5rIHN0cmluZy4gTm90ZSB0aGF0IHRoaXMgaXMgdGhlIGdyb3VwICppZCosIG5vdCB0aGUgZ3JvdXAgKm5hbWUqLlxuICAgICAgICAgKiBAdHlwZSB7c3RyaW5nfVxuICAgICAgICAgKi9cbiAgICAgICAgZ3JvdXBJZDogdW5kZWZpbmVkLFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBPcHRpb25zIHRvIHBhc3Mgb24gdG8gdGhlIHVuZGVybHlpbmcgdHJhbnNwb3J0IGxheWVyLiBBbGwganF1ZXJ5LmFqYXggb3B0aW9ucyBhdCBodHRwOi8vYXBpLmpxdWVyeS5jb20valF1ZXJ5LmFqYXgvIGFyZSBhdmFpbGFibGUuIERlZmF1bHRzIHRvIGVtcHR5IG9iamVjdC5cbiAgICAgICAgICogQHR5cGUge29iamVjdH1cbiAgICAgICAgICovXG4gICAgICAgIHRyYW5zcG9ydDoge31cbiAgICB9O1xuICAgIHRoaXMuc2Vzc2lvbk1hbmFnZXIgPSBuZXcgU2Vzc2lvbk1hbmFnZXIoKTtcbiAgICB2YXIgc2VydmljZU9wdGlvbnMgPSB0aGlzLnNlc3Npb25NYW5hZ2VyLmdldE1lcmdlZE9wdGlvbnMoZGVmYXVsdHMsIGNvbmZpZyk7XG4gICAgdmFyIHVybENvbmZpZyA9IG5ldyBDb25maWdTZXJ2aWNlKHNlcnZpY2VPcHRpb25zKS5nZXQoJ3NlcnZlcicpO1xuXG4gICAgdmFyIHRyYW5zcG9ydE9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSwgc2VydmljZU9wdGlvbnMudHJhbnNwb3J0LCB7XG4gICAgICAgIHVybDogdXJsQ29uZmlnLmdldEFQSVBhdGgoYXBpRW5kcG9pbnQpXG4gICAgfSk7XG5cbiAgICBpZiAoc2VydmljZU9wdGlvbnMudG9rZW4pIHtcbiAgICAgICAgdHJhbnNwb3J0T3B0aW9ucy5oZWFkZXJzID0ge1xuICAgICAgICAgICAgJ0F1dGhvcml6YXRpb24nOiAnQmVhcmVyICcgKyBzZXJ2aWNlT3B0aW9ucy50b2tlblxuICAgICAgICB9O1xuICAgIH1cbiAgICB2YXIgaHR0cCA9IG5ldyBUcmFuc3BvcnRGYWN0b3J5KHRyYW5zcG9ydE9wdGlvbnMsIHNlcnZpY2VPcHRpb25zKTtcblxuICAgIHZhciBnZXRGaW5hbFBhcmFtcyA9IGZ1bmN0aW9uIChwYXJhbXMpIHtcbiAgICAgICAgaWYgKHR5cGVvZiBwYXJhbXMgPT09ICdvYmplY3QnKSB7XG4gICAgICAgICAgICByZXR1cm4gJC5leHRlbmQodHJ1ZSwgc2VydmljZU9wdGlvbnMsIHBhcmFtcyk7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIHNlcnZpY2VPcHRpb25zO1xuICAgIH07XG5cbiAgICB2YXIgcGF0Y2hVc2VyQWN0aXZlRmllbGQgPSBmdW5jdGlvbiAocGFyYW1zLCBhY3RpdmUsIG9wdGlvbnMpIHtcbiAgICAgICAgdmFyIGh0dHBPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwgc2VydmljZU9wdGlvbnMsIG9wdGlvbnMsIHtcbiAgICAgICAgICAgIHVybDogdXJsQ29uZmlnLmdldEFQSVBhdGgoYXBpRW5kcG9pbnQpICsgcGFyYW1zLmdyb3VwSWQgKyAnLycgKyBwYXJhbXMudXNlcklkXG4gICAgICAgIH0pO1xuXG4gICAgICAgIHJldHVybiBodHRwLnBhdGNoKHsgYWN0aXZlOiBhY3RpdmUgfSwgaHR0cE9wdGlvbnMpO1xuICAgIH07XG5cbiAgICB2YXIgcHVibGljQVBJID0ge1xuXG4gICAgICAgIC8qKlxuICAgICAgICAqIFJldHJpZXZlIGRldGFpbHMgYWJvdXQgYWxsIG9mIHRoZSBncm91cCBtZW1iZXJzaGlwcyBmb3Igb25lIGVuZCB1c2VyLiBUaGUgbWVtYmVyc2hpcCBkZXRhaWxzIGFyZSByZXR1cm5lZCBpbiBhbiBhcnJheSwgd2l0aCBvbmUgZWxlbWVudCAoZ3JvdXAgcmVjb3JkKSBmb3IgZWFjaCBncm91cCB0byB3aGljaCB0aGUgZW5kIHVzZXIgYmVsb25ncy5cbiAgICAgICAgKlxuICAgICAgICAqIEluIHRoZSBtZW1iZXJzaGlwIGFycmF5LCBlYWNoIGdyb3VwIHJlY29yZCBpbmNsdWRlcyB0aGUgZ3JvdXAgaWQsIHByb2plY3QgaWQsIGFjY291bnQgKHRlYW0pIGlkLCBhbmQgYW4gYXJyYXkgb2YgbWVtYmVycy4gSG93ZXZlciwgb25seSB0aGUgdXNlciB3aG9zZSB1c2VySWQgaXMgaW5jbHVkZWQgaW4gdGhlIGNhbGwgaXMgbGlzdGVkIGluIHRoZSBtZW1iZXJzIGFycmF5IChyZWdhcmRsZXNzIG9mIHdoZXRoZXIgdGhlcmUgYXJlIG90aGVyIG1lbWJlcnMgaW4gdGhpcyBncm91cCkuXG4gICAgICAgICpcbiAgICAgICAgKiAqKkV4YW1wbGUqKlxuICAgICAgICAqXG4gICAgICAgICogICAgICAgdmFyIG1hID0gbmV3IEYuc2VydmljZS5NZW1iZXIoeyB0b2tlbjogJ3VzZXItb3ItcHJvamVjdC1hY2Nlc3MtdG9rZW4nIH0pO1xuICAgICAgICAqICAgICAgIG1hLmdldEdyb3Vwc0ZvclVzZXIoJzQyODM2ZDRiLTViNjEtNGZlNC04MGViLTMxMzZlOTU2ZWU1YycpXG4gICAgICAgICogICAgICAgICAgIC50aGVuKGZ1bmN0aW9uKG1lbWJlcnNoaXBzKXtcbiAgICAgICAgKiAgICAgICAgICAgICAgIGZvciAodmFyIGk9MDsgaTxtZW1iZXJzaGlwcy5sZW5ndGg7IGkrKykge1xuICAgICAgICAqICAgICAgICAgICAgICAgICAgIGNvbnNvbGUubG9nKG1lbWJlcnNoaXBzW2ldLmdyb3VwSWQpO1xuICAgICAgICAqICAgICAgICAgICAgICAgfVxuICAgICAgICAqICAgICAgICAgICB9KTtcbiAgICAgICAgKlxuICAgICAgICAqICAgICAgIG1hLmdldEdyb3Vwc0ZvclVzZXIoeyB1c2VySWQ6ICc0MjgzNmQ0Yi01YjYxLTRmZTQtODBlYi0zMTM2ZTk1NmVlNWMnIH0pO1xuICAgICAgICAqXG4gICAgICAgICogKipQYXJhbWV0ZXJzKipcbiAgICAgICAgKiBAcGFyYW0ge3N0cmluZ3xvYmplY3R9IGBwYXJhbXNgIFRoZSB1c2VyIGlkIGZvciB0aGUgZW5kIHVzZXIuIEFsdGVybmF0aXZlbHksIGFuIG9iamVjdCB3aXRoIGZpZWxkIGB1c2VySWRgIGFuZCB2YWx1ZSB0aGUgdXNlciBpZC5cbiAgICAgICAgKiBAcGFyYW0ge29iamVjdH0gYG9wdGlvbnNgIChPcHRpb25hbCkgT3ZlcnJpZGVzIGZvciBjb25maWd1cmF0aW9uIG9wdGlvbnMuXG4gICAgICAgICovXG5cbiAgICAgICAgZ2V0R3JvdXBzRm9yVXNlcjogZnVuY3Rpb24gKHBhcmFtcywgb3B0aW9ucykge1xuICAgICAgICAgICAgb3B0aW9ucyA9IG9wdGlvbnMgfHwge307XG4gICAgICAgICAgICB2YXIgaHR0cE9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCBzZXJ2aWNlT3B0aW9ucywgb3B0aW9ucyk7XG4gICAgICAgICAgICB2YXIgaXNTdHJpbmcgPSB0eXBlb2YgcGFyYW1zID09PSAnc3RyaW5nJztcbiAgICAgICAgICAgIHZhciBvYmpQYXJhbXMgPSBnZXRGaW5hbFBhcmFtcyhwYXJhbXMpO1xuICAgICAgICAgICAgaWYgKCFpc1N0cmluZyAmJiAhb2JqUGFyYW1zLnVzZXJJZCkge1xuICAgICAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcignTm8gdXNlcklkIHNwZWNpZmllZC4nKTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgdmFyIGdldFBhcm1zID0gaXNTdHJpbmcgPyB7IHVzZXJJZDogcGFyYW1zIH0gOiBfcGljayhvYmpQYXJhbXMsICd1c2VySWQnKTtcbiAgICAgICAgICAgIHJldHVybiBodHRwLmdldChnZXRQYXJtcywgaHR0cE9wdGlvbnMpO1xuICAgICAgICB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAqIFJldHJpZXZlIGRldGFpbHMgYWJvdXQgb25lIGdyb3VwLCBpbmNsdWRpbmcgYW4gYXJyYXkgb2YgYWxsIGl0cyBtZW1iZXJzLlxuICAgICAgICAqXG4gICAgICAgICogKipFeGFtcGxlKipcbiAgICAgICAgKlxuICAgICAgICAqICAgICAgIHZhciBtYSA9IG5ldyBGLnNlcnZpY2UuTWVtYmVyKHsgdG9rZW46ICd1c2VyLW9yLXByb2plY3QtYWNjZXNzLXRva2VuJyB9KTtcbiAgICAgICAgKiAgICAgICBtYS5nZXRHcm91cERldGFpbHMoJzgwMjU3YTI1LWFhMTAtNDk1OS05NjhiLWZkMDUzOTAxZjcyZicpXG4gICAgICAgICogICAgICAgICAgIC50aGVuKGZ1bmN0aW9uKGdyb3VwKXtcbiAgICAgICAgKiAgICAgICAgICAgICAgIGZvciAodmFyIGk9MDsgaTxncm91cC5tZW1iZXJzLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgICogICAgICAgICAgICAgICAgICAgY29uc29sZS5sb2coZ3JvdXAubWVtYmVyc1tpXS51c2VyTmFtZSk7XG4gICAgICAgICogICAgICAgICAgICAgICB9XG4gICAgICAgICogICAgICAgICAgIH0pO1xuICAgICAgICAqXG4gICAgICAgICogICAgICAgbWEuZ2V0R3JvdXBEZXRhaWxzKHsgZ3JvdXBJZDogJzgwMjU3YTI1LWFhMTAtNDk1OS05NjhiLWZkMDUzOTAxZjcyZicgfSk7XG4gICAgICAgICpcbiAgICAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAqIEBwYXJhbSB7c3RyaW5nfG9iamVjdH0gYHBhcmFtc2AgVGhlIGdyb3VwIGlkLiBBbHRlcm5hdGl2ZWx5LCBhbiBvYmplY3Qgd2l0aCBmaWVsZCBgZ3JvdXBJZGAgYW5kIHZhbHVlIHRoZSBncm91cCBpZC5cbiAgICAgICAgKiBAcGFyYW0ge29iamVjdH0gYG9wdGlvbnNgIChPcHRpb25hbCkgT3ZlcnJpZGVzIGZvciBjb25maWd1cmF0aW9uIG9wdGlvbnMuXG4gICAgICAgICovXG4gICAgICAgIGdldEdyb3VwRGV0YWlsczogZnVuY3Rpb24gKHBhcmFtcywgb3B0aW9ucykge1xuICAgICAgICAgICAgb3B0aW9ucyA9IG9wdGlvbnMgfHwge307XG4gICAgICAgICAgICB2YXIgaXNTdHJpbmcgPSB0eXBlb2YgcGFyYW1zID09PSAnc3RyaW5nJztcbiAgICAgICAgICAgIHZhciBvYmpQYXJhbXMgPSBnZXRGaW5hbFBhcmFtcyhwYXJhbXMpO1xuICAgICAgICAgICAgaWYgKCFpc1N0cmluZyAmJiAhb2JqUGFyYW1zLmdyb3VwSWQpIHtcbiAgICAgICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ05vIGdyb3VwSWQgc3BlY2lmaWVkLicpO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICB2YXIgZ3JvdXBJZCA9IGlzU3RyaW5nID8gcGFyYW1zIDogb2JqUGFyYW1zLmdyb3VwSWQ7XG4gICAgICAgICAgICB2YXIgaHR0cE9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCBzZXJ2aWNlT3B0aW9ucyxcbiAgICAgICAgICAgICAgICBvcHRpb25zLFxuICAgICAgICAgICAgICAgIHsgdXJsOiB1cmxDb25maWcuZ2V0QVBJUGF0aChhcGlFbmRwb2ludCkgKyBncm91cElkIH1cbiAgICAgICAgICAgICk7XG5cbiAgICAgICAgICAgIHJldHVybiBodHRwLmdldCh7fSwgaHR0cE9wdGlvbnMpO1xuICAgICAgICB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAqIFNldCBhIHBhcnRpY3VsYXIgZW5kIHVzZXIgYXMgYGFjdGl2ZWAuIEFjdGl2ZSBlbmQgdXNlcnMgY2FuIGJlIGFzc2lnbmVkIHRvIFt3b3JsZHNdKC4uL3dvcmxkLW1hbmFnZXIvKSBpbiBtdWx0aXBsYXllciBnYW1lcyBkdXJpbmcgYXV0b21hdGljIGFzc2lnbm1lbnQuXG4gICAgICAgICpcbiAgICAgICAgKiAqKkV4YW1wbGUqKlxuICAgICAgICAqXG4gICAgICAgICogICAgICAgdmFyIG1hID0gbmV3IEYuc2VydmljZS5NZW1iZXIoeyB0b2tlbjogJ3VzZXItb3ItcHJvamVjdC1hY2Nlc3MtdG9rZW4nIH0pO1xuICAgICAgICAqICAgICAgIG1hLm1ha2VVc2VyQWN0aXZlKHsgdXNlcklkOiAnNDI4MzZkNGItNWI2MS00ZmU0LTgwZWItMzEzNmU5NTZlZTVjJyxcbiAgICAgICAgKiAgICAgICAgICAgICAgICAgICAgICAgICAgIGdyb3VwSWQ6ICc4MDI1N2EyNS1hYTEwLTQ5NTktOTY4Yi1mZDA1MzkwMWY3MmYnIH0pO1xuICAgICAgICAqXG4gICAgICAgICogKipQYXJhbWV0ZXJzKipcbiAgICAgICAgKiBAcGFyYW0ge29iamVjdH0gYHBhcmFtc2AgVGhlIGVuZCB1c2VyIGFuZCBncm91cCBpbmZvcm1hdGlvbi5cbiAgICAgICAgKiBAcGFyYW0ge3N0cmluZ30gYHBhcmFtcy51c2VySWRgIFRoZSBpZCBvZiB0aGUgZW5kIHVzZXIgdG8gbWFrZSBhY3RpdmUuXG4gICAgICAgICogQHBhcmFtIHtzdHJpbmd9IGBwYXJhbXMuZ3JvdXBJZGAgVGhlIGlkIG9mIHRoZSBncm91cCB0byB3aGljaCB0aGlzIGVuZCB1c2VyIGJlbG9uZ3MsIGFuZCBpbiB3aGljaCB0aGUgZW5kIHVzZXIgc2hvdWxkIGJlY29tZSBhY3RpdmUuXG4gICAgICAgICogQHBhcmFtIHtvYmplY3R9IGBvcHRpb25zYCAoT3B0aW9uYWwpIE92ZXJyaWRlcyBmb3IgY29uZmlndXJhdGlvbiBvcHRpb25zLlxuICAgICAgICAqL1xuICAgICAgICBtYWtlVXNlckFjdGl2ZTogZnVuY3Rpb24gKHBhcmFtcywgb3B0aW9ucykge1xuICAgICAgICAgICAgcmV0dXJuIHBhdGNoVXNlckFjdGl2ZUZpZWxkKHBhcmFtcywgdHJ1ZSwgb3B0aW9ucyk7XG4gICAgICAgIH0sXG5cbiAgICAgICAgLyoqXG4gICAgICAgICogU2V0IGEgcGFydGljdWxhciBlbmQgdXNlciBhcyBgaW5hY3RpdmVgLiBJbmFjdGl2ZSBlbmQgdXNlcnMgYXJlIG5vdCBhc3NpZ25lZCB0byBbd29ybGRzXSguLi93b3JsZC1tYW5hZ2VyLykgaW4gbXVsdGlwbGF5ZXIgZ2FtZXMgZHVyaW5nIGF1dG9tYXRpYyBhc3NpZ25tZW50LlxuICAgICAgICAqXG4gICAgICAgICogKipFeGFtcGxlKipcbiAgICAgICAgKlxuICAgICAgICAqICAgICAgIHZhciBtYSA9IG5ldyBGLnNlcnZpY2UuTWVtYmVyKHsgdG9rZW46ICd1c2VyLW9yLXByb2plY3QtYWNjZXNzLXRva2VuJyB9KTtcbiAgICAgICAgKiAgICAgICBtYS5tYWtlVXNlckluYWN0aXZlKHsgdXNlcklkOiAnNDI4MzZkNGItNWI2MS00ZmU0LTgwZWItMzEzNmU5NTZlZTVjJyxcbiAgICAgICAgKiAgICAgICAgICAgICAgICAgICAgICAgICAgIGdyb3VwSWQ6ICc4MDI1N2EyNS1hYTEwLTQ5NTktOTY4Yi1mZDA1MzkwMWY3MmYnIH0pO1xuICAgICAgICAqXG4gICAgICAgICogKipQYXJhbWV0ZXJzKipcbiAgICAgICAgKiBAcGFyYW0ge29iamVjdH0gYHBhcmFtc2AgVGhlIGVuZCB1c2VyIGFuZCBncm91cCBpbmZvcm1hdGlvbi5cbiAgICAgICAgKiBAcGFyYW0ge3N0cmluZ30gYHBhcmFtcy51c2VySWRgIFRoZSBpZCBvZiB0aGUgZW5kIHVzZXIgdG8gbWFrZSBpbmFjdGl2ZS5cbiAgICAgICAgKiBAcGFyYW0ge3N0cmluZ30gYHBhcmFtcy5ncm91cElkYCBUaGUgaWQgb2YgdGhlIGdyb3VwIHRvIHdoaWNoIHRoaXMgZW5kIHVzZXIgYmVsb25ncywgYW5kIGluIHdoaWNoIHRoZSBlbmQgdXNlciBzaG91bGQgYmVjb21lIGluYWN0aXZlLlxuICAgICAgICAqIEBwYXJhbSB7b2JqZWN0fSBgb3B0aW9uc2AgKE9wdGlvbmFsKSBPdmVycmlkZXMgZm9yIGNvbmZpZ3VyYXRpb24gb3B0aW9ucy5cbiAgICAgICAgKi9cbiAgICAgICAgbWFrZVVzZXJJbmFjdGl2ZTogZnVuY3Rpb24gKHBhcmFtcywgb3B0aW9ucykge1xuICAgICAgICAgICAgcmV0dXJuIHBhdGNoVXNlckFjdGl2ZUZpZWxkKHBhcmFtcywgZmFsc2UsIG9wdGlvbnMpO1xuICAgICAgICB9XG4gICAgfTtcblxuICAgICQuZXh0ZW5kKHRoaXMsIHB1YmxpY0FQSSk7XG59O1xuIiwiLyoqXG4gKlxuICogIyMgUnVuIEFQSSBTZXJ2aWNlXG4gKlxuICogVGhlIFJ1biBBUEkgU2VydmljZSBhbGxvd3MgeW91IHRvIHBlcmZvcm0gY29tbW9uIHRhc2tzIGFyb3VuZCBjcmVhdGluZyBhbmQgdXBkYXRpbmcgcnVucywgdmFyaWFibGVzLCBhbmQgZGF0YS5cbiAqXG4gKiBXaGVuIGJ1aWxkaW5nIGludGVyZmFjZXMgdG8gc2hvdyBydW4gb25lIGF0IGEgdGltZSAoYXMgZm9yIHN0YW5kYXJkIGVuZCB1c2VycyksIHR5cGljYWxseSB5b3UgZmlyc3QgaW5zdGFudGlhdGUgYSBbUnVuIE1hbmFnZXJdKC4uL3J1bi1tYW5hZ2VyLykgYW5kIHRoZW4gYWNjZXNzIHRoZSBSdW4gU2VydmljZSB0aGF0IGlzIGF1dG9tYXRpY2FsbHkgcGFydCBvZiB0aGUgbWFuYWdlciwgcmF0aGVyIHRoYW4gaW5zdGFudGlhdGluZyB0aGUgUnVuIFNlcnZpY2UgZGlyZWN0bHkuIFRoaXMgaXMgYmVjYXVzZSB0aGUgUnVuIE1hbmFnZXIgZ2l2ZXMgeW91IGNvbnRyb2wgb3ZlciBydW4gY3JlYXRpb24gZGVwZW5kaW5nIG9uIHJ1biBzdGF0ZXMuXG4gKlxuICogSG93ZXZlciwgbWFueSBvZiB0aGUgRXBpY2VudGVyIHNhbXBsZSBwcm9qZWN0cyB1c2UgYSBSdW4gU2VydmljZSwgYmVjYXVzZSBnZW5lcmFsbHkgdGhlIHNhbXBsZSBwcm9qZWN0cyBhcmUgcGxheWVkIGluIG9uZSBlbmQgdXNlciBzZXNzaW9uIGFuZCBkb24ndCBjYXJlIGFib3V0IHJ1biBzdGF0ZXMgb3IgW3J1biBzdHJhdGVnaWVzXSguLi8uLi9zdHJhdGVneS8pLiBUaGUgUnVuIEFQSSBTZXJ2aWNlIGlzIGFsc28gdXNlZnVsIGZvciBidWlsZGluZyBhbiBpbnRlcmZhY2UgZm9yIGEgZmFjaWxpdGF0b3IsIGJlY2F1c2UgaXQgbWFrZXMgaXQgZWFzeSB0byBsaXN0IGRhdGEgYWNyb3NzIG11bHRpcGxlIHJ1bnMgKHVzaW5nIHRoZSBgZmlsdGVyKClgIGFuZCBgcXVlcnkoKWAgbWV0aG9kcykuXG4gKlxuICogVG8gdXNlIHRoZSBSdW4gQVBJIFNlcnZpY2UsIGluc3RhbnRpYXRlIGl0IGJ5IHBhc3NpbmcgaW46XG4gKlxuICogKiBgYWNjb3VudGA6IEVwaWNlbnRlciBhY2NvdW50IGlkICgqKlRlYW0gSUQqKiBmb3IgdGVhbSBwcm9qZWN0cywgKipVc2VyIElEKiogZm9yIHBlcnNvbmFsIHByb2plY3RzKS5cbiAqICogYHByb2plY3RgOiBFcGljZW50ZXIgcHJvamVjdCBpZC5cbiAqXG4gKiBGb3IgZXhhbXBsZSxcbiAqXG4gKiAgICAgICB2YXIgcnMgPSBuZXcgRi5zZXJ2aWNlLlJ1bih7XG4gKiAgICAgICAgICAgIGFjY291bnQ6ICdhY21lLXNpbXVsYXRpb25zJyxcbiAqICAgICAgICAgICAgcHJvamVjdDogJ3N1cHBseS1jaGFpbi1nYW1lJyxcbiAqICAgICAgfSk7XG4gKiAgICAgIHJzLmNyZWF0ZSgnc3VwcGx5X2NoYWluX2dhbWUucHknKS50aGVuKGZ1bmN0aW9uKHJ1bikge1xuICogICAgICAgICAgICAgcnMuZG8oJ3NvbWVPcGVyYXRpb24nKTtcbiAqICAgICAgfSk7XG4gKlxuICpcbiAqIEFkZGl0aW9uYWxseSwgYWxsIEFQSSBjYWxscyB0YWtlIGluIGFuIFwib3B0aW9uc1wiIG9iamVjdCBhcyB0aGUgbGFzdCBwYXJhbWV0ZXIuIFRoZSBvcHRpb25zIGNhbiBiZSB1c2VkIHRvIGV4dGVuZC9vdmVycmlkZSB0aGUgUnVuIEFQSSBTZXJ2aWNlIGRlZmF1bHRzIGxpc3RlZCBiZWxvdy5cbiAqXG4gKiBOb3RlIHRoYXQgaW4gYWRkaXRpb24gdG8gdGhlIGBhY2NvdW50YCwgYHByb2plY3RgLCBhbmQgYG1vZGVsYCwgdGhlIFJ1biBTZXJ2aWNlIHBhcmFtZXRlcnMgb3B0aW9uYWxseSBpbmNsdWRlIGEgYHNlcnZlcmAgb2JqZWN0LCB3aG9zZSBgaG9zdGAgZmllbGQgY29udGFpbnMgdGhlIFVSSSBvZiB0aGUgRm9yaW8gc2VydmVyLiBUaGlzIGlzIGF1dG9tYXRpY2FsbHkgc2V0LCBidXQgeW91IGNhbiBwYXNzIGl0IGV4cGxpY2l0bHkgaWYgZGVzaXJlZC4gSXQgaXMgbW9zdCBjb21tb25seSB1c2VkIGZvciBjbGFyaXR5IHdoZW4geW91IGFyZSBbaG9zdGluZyBhbiBFcGljZW50ZXIgcHJvamVjdCBvbiB5b3VyIG93biBzZXJ2ZXJdKC4uLy4uLy4uL2hvd190by9zZWxmX2hvc3RpbmcvKS5cbiAqXG4gKiAgICAgICB2YXIgcm0gPSBuZXcgRi5tYW5hZ2VyLlJ1bk1hbmFnZXIoe1xuICogICAgICAgICAgIHJ1bjoge1xuICogICAgICAgICAgICAgICBhY2NvdW50OiAnYWNtZS1zaW11bGF0aW9ucycsXG4gKiAgICAgICAgICAgICAgIHByb2plY3Q6ICdzdXBwbHktY2hhaW4tZ2FtZScsXG4gKiAgICAgICAgICAgICAgIG1vZGVsOiAnc3VwcGx5X2NoYWluX2dhbWUucHknLFxuICogICAgICAgICAgICAgICBzZXJ2ZXI6IHsgaG9zdDogJ2FwaS5mb3Jpby5jb20nIH1cbiAqICAgICAgICAgICB9XG4gKiAgICAgICB9KTtcbiAqICAgICAgIHJtLmdldFJ1bigpXG4gKiAgICAgICAgICAgLnRoZW4oZnVuY3Rpb24ocnVuKSB7XG4gKiAgICAgICAgICAgICAgIC8vIHRoZSBSdW5NYW5hZ2VyLnJ1biBjb250YWlucyB0aGUgaW5zdGFudGlhdGVkIFJ1biBTZXJ2aWNlLFxuICogICAgICAgICAgICAgICAvLyBzbyBhbnkgUnVuIFNlcnZpY2UgbWV0aG9kIGlzIHZhbGlkIGhlcmVcbiAqICAgICAgICAgICAgICAgdmFyIHJzID0gcm0ucnVuO1xuICogICAgICAgICAgICAgICBycy5kbygnc29tZU9wZXJhdGlvbicpO1xuICogICAgICAgfSlcbiAqXG4gKi9cblxuJ3VzZSBzdHJpY3QnO1xuXG52YXIgQ29uZmlnU2VydmljZSA9IHJlcXVpcmUoJy4vY29uZmlndXJhdGlvbi1zZXJ2aWNlJyk7XG52YXIgcXV0aWwgPSByZXF1aXJlKCcuLi91dGlsL3F1ZXJ5LXV0aWwnKTtcbnZhciBydXRpbCA9IHJlcXVpcmUoJy4uL3V0aWwvcnVuLXV0aWwnKTtcbnZhciBfcGljayA9IHJlcXVpcmUoJy4uL3V0aWwvb2JqZWN0LXV0aWwnKS5fcGljaztcbnZhciBUcmFuc3BvcnRGYWN0b3J5ID0gcmVxdWlyZSgnLi4vdHJhbnNwb3J0L2h0dHAtdHJhbnNwb3J0LWZhY3RvcnknKTtcbnZhciBWYXJpYWJsZXNTZXJ2aWNlID0gcmVxdWlyZSgnLi92YXJpYWJsZXMtYXBpLXNlcnZpY2UnKTtcbnZhciBJbnRyb3NwZWN0aW9uU2VydmljZSA9IHJlcXVpcmUoJy4vaW50cm9zcGVjdGlvbi1hcGktc2VydmljZScpO1xudmFyIFNlc3Npb25NYW5hZ2VyID0gcmVxdWlyZSgnLi4vc3RvcmUvc2Vzc2lvbi1tYW5hZ2VyJyk7XG5cbm1vZHVsZS5leHBvcnRzID0gZnVuY3Rpb24gKGNvbmZpZykge1xuICAgIHZhciBkZWZhdWx0cyA9IHtcbiAgICAgICAgLyoqXG4gICAgICAgICAqIEZvciBwcm9qZWN0cyB0aGF0IHJlcXVpcmUgYXV0aGVudGljYXRpb24sIHBhc3MgaW4gdGhlIHVzZXIgYWNjZXNzIHRva2VuIChkZWZhdWx0cyB0byBlbXB0eSBzdHJpbmcpLiBJZiB0aGUgdXNlciBpcyBhbHJlYWR5IGxvZ2dlZCBpbiB0byBFcGljZW50ZXIsIHRoZSB1c2VyIGFjY2VzcyB0b2tlbiBpcyBhbHJlYWR5IHNldCBpbiBhIGNvb2tpZSBhbmQgYXV0b21hdGljYWxseSBsb2FkZWQgZnJvbSB0aGVyZS4gKFNlZSBbbW9yZSBiYWNrZ3JvdW5kIG9uIGFjY2VzcyB0b2tlbnNdKC4uLy4uLy4uL3Byb2plY3RfYWNjZXNzLykpLlxuICAgICAgICAgKiBAc2VlIFtBdXRoZW50aWNhdGlvbiBBUEkgU2VydmljZV0oLi4vYXV0aC1hcGktc2VydmljZS8pIGZvciBnZXR0aW5nIHRva2Vucy5cbiAgICAgICAgICogQHR5cGUge1N0cmluZ31cbiAgICAgICAgICovXG4gICAgICAgIHRva2VuOiB1bmRlZmluZWQsXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIFRoZSBhY2NvdW50IGlkLiBJbiB0aGUgRXBpY2VudGVyIFVJLCB0aGlzIGlzIHRoZSAqKlRlYW0gSUQqKiAoZm9yIHRlYW0gcHJvamVjdHMpIG9yICoqVXNlciBJRCoqIChmb3IgcGVyc29uYWwgcHJvamVjdHMpLiBEZWZhdWx0cyB0byBlbXB0eSBzdHJpbmcuIElmIGxlZnQgdW5kZWZpbmVkLCB0YWtlbiBmcm9tIHRoZSBVUkwuXG4gICAgICAgICAqIEB0eXBlIHtTdHJpbmd9XG4gICAgICAgICAqL1xuICAgICAgICBhY2NvdW50OiB1bmRlZmluZWQsXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIFRoZSBwcm9qZWN0IGlkLiBEZWZhdWx0cyB0byBlbXB0eSBzdHJpbmcuIElmIGxlZnQgdW5kZWZpbmVkLCB0YWtlbiBmcm9tIHRoZSBVUkwuXG4gICAgICAgICAqIEB0eXBlIHtTdHJpbmd9XG4gICAgICAgICAqL1xuICAgICAgICBwcm9qZWN0OiB1bmRlZmluZWQsXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIENyaXRlcmlhIGJ5IHdoaWNoIHRvIGZpbHRlciBydW5zLiBEZWZhdWx0cyB0byBlbXB0eSBzdHJpbmcuXG4gICAgICAgICAqIEB0eXBlIHtTdHJpbmd9XG4gICAgICAgICAqL1xuICAgICAgICBmaWx0ZXI6ICcnLFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBDb252ZW5pZW5jZSBhbGlhcyBmb3IgZmlsdGVyLlxuICAgICAgICAgKiBAdHlwZSB7U3RyaW5nfVxuICAgICAgICAgKi9cbiAgICAgICAgaWQ6ICcnLFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBGbGFnIGRldGVybWluZXMgaWYgYFgtQXV0b1Jlc3RvcmU6IHRydWVgIGhlYWRlciBpcyBzZW50IHRvIEVwaWNlbnRlci4gRGVmYXVsdHMgdG8gYHRydWVgLlxuICAgICAgICAgKiBAdHlwZSB7Ym9vbGVhbn1cbiAgICAgICAgICovXG4gICAgICAgIGF1dG9SZXN0b3JlOiB0cnVlLFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBDYWxsZWQgd2hlbiB0aGUgY2FsbCBjb21wbGV0ZXMgc3VjY2Vzc2Z1bGx5LiBEZWZhdWx0cyB0byBgJC5ub29wYC5cbiAgICAgICAgICogQHR5cGUge2Z1bmN0aW9ufVxuICAgICAgICAgKi9cbiAgICAgICAgc3VjY2VzczogJC5ub29wLFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBDYWxsZWQgd2hlbiB0aGUgY2FsbCBmYWlscy4gRGVmYXVsdHMgdG8gYCQubm9vcGAuXG4gICAgICAgICAqIEB0eXBlIHtmdW5jdGlvbn1cbiAgICAgICAgICovXG4gICAgICAgIGVycm9yOiAkLm5vb3AsXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIE9wdGlvbnMgdG8gcGFzcyBvbiB0byB0aGUgdW5kZXJseWluZyB0cmFuc3BvcnQgbGF5ZXIuIEFsbCBqcXVlcnkuYWpheCBvcHRpb25zIGF0IGh0dHA6Ly9hcGkuanF1ZXJ5LmNvbS9qUXVlcnkuYWpheC8gYXJlIGF2YWlsYWJsZS4gRGVmYXVsdHMgdG8gZW1wdHkgb2JqZWN0LlxuICAgICAgICAgKiBAdHlwZSB7T2JqZWN0fVxuICAgICAgICAgKi9cbiAgICAgICAgdHJhbnNwb3J0OiB7fVxuICAgIH07XG5cbiAgICB0aGlzLnNlc3Npb25NYW5hZ2VyID0gbmV3IFNlc3Npb25NYW5hZ2VyKCk7XG4gICAgdmFyIHNlcnZpY2VPcHRpb25zID0gdGhpcy5zZXNzaW9uTWFuYWdlci5nZXRNZXJnZWRPcHRpb25zKGRlZmF1bHRzLCBjb25maWcpO1xuICAgIGlmIChzZXJ2aWNlT3B0aW9ucy5pZCkge1xuICAgICAgICBzZXJ2aWNlT3B0aW9ucy5maWx0ZXIgPSBzZXJ2aWNlT3B0aW9ucy5pZDtcbiAgICB9XG5cbiAgICB2YXIgdXJsQ29uZmlnID0gbmV3IENvbmZpZ1NlcnZpY2Uoc2VydmljZU9wdGlvbnMpLmdldCgnc2VydmVyJyk7XG4gICAgaWYgKHNlcnZpY2VPcHRpb25zLmFjY291bnQpIHtcbiAgICAgICAgdXJsQ29uZmlnLmFjY291bnRQYXRoID0gc2VydmljZU9wdGlvbnMuYWNjb3VudDtcbiAgICB9XG4gICAgaWYgKHNlcnZpY2VPcHRpb25zLnByb2plY3QpIHtcbiAgICAgICAgdXJsQ29uZmlnLnByb2plY3RQYXRoID0gc2VydmljZU9wdGlvbnMucHJvamVjdDtcbiAgICB9XG5cbiAgICB1cmxDb25maWcuZmlsdGVyID0gJzsnO1xuICAgIHVybENvbmZpZy5nZXRGaWx0ZXJVUkwgPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHZhciB1cmwgPSB1cmxDb25maWcuZ2V0QVBJUGF0aCgncnVuJyk7XG4gICAgICAgIHZhciBmaWx0ZXIgPSBxdXRpbC50b01hdHJpeEZvcm1hdChzZXJ2aWNlT3B0aW9ucy5maWx0ZXIpO1xuXG4gICAgICAgIGlmIChmaWx0ZXIpIHtcbiAgICAgICAgICAgIHVybCArPSBmaWx0ZXIgKyAnLyc7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIHVybDtcbiAgICB9O1xuXG4gICAgdXJsQ29uZmlnLmFkZEF1dG9SZXN0b3JlSGVhZGVyID0gZnVuY3Rpb24gKG9wdGlvbnMpIHtcbiAgICAgICAgdmFyIGZpbHRlciA9IHNlcnZpY2VPcHRpb25zLmZpbHRlcjtcbiAgICAgICAgLy8gVGhlIHNlbWljb2xvbiBzZXBhcmF0ZWQgZmlsdGVyIGlzIHVzZWQgd2hlbiBmaWx0ZXIgaXMgYW4gb2JqZWN0XG4gICAgICAgIHZhciBpc0ZpbHRlclJ1bklkID0gZmlsdGVyICYmICQudHlwZShmaWx0ZXIpID09PSAnc3RyaW5nJztcbiAgICAgICAgaWYgKHNlcnZpY2VPcHRpb25zLmF1dG9SZXN0b3JlICYmIGlzRmlsdGVyUnVuSWQpIHtcbiAgICAgICAgICAgIC8vIEJ5IGRlZmF1bHQgYXV0b3JlcGxheSB0aGUgcnVuIGJ5IHNlbmRpbmcgdGhpcyBoZWFkZXIgdG8gZXBpY2VudGVyXG4gICAgICAgICAgICAvLyBodHRwczovL2ZvcmlvLmNvbS9lcGljZW50ZXIvZG9jcy9wdWJsaWMvcmVzdF9hcGlzL2FnZ3JlZ2F0ZV9ydW5fYXBpLyNyZXRyaWV2aW5nXG4gICAgICAgICAgICB2YXIgYXV0b3Jlc3RvcmVPcHRzID0ge1xuICAgICAgICAgICAgICAgIGhlYWRlcnM6IHtcbiAgICAgICAgICAgICAgICAgICAgJ1gtQXV0b1Jlc3RvcmUnOiB0cnVlXG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfTtcbiAgICAgICAgICAgIHJldHVybiAkLmV4dGVuZCh0cnVlLCBhdXRvcmVzdG9yZU9wdHMsIG9wdGlvbnMpO1xuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIG9wdGlvbnM7XG4gICAgfTtcblxuICAgIHZhciBodHRwT3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LCBzZXJ2aWNlT3B0aW9ucy50cmFuc3BvcnQsIHtcbiAgICAgICAgdXJsOiB1cmxDb25maWcuZ2V0RmlsdGVyVVJMXG4gICAgfSk7XG5cbiAgICBpZiAoc2VydmljZU9wdGlvbnMudG9rZW4pIHtcbiAgICAgICAgaHR0cE9wdGlvbnMuaGVhZGVycyA9IHtcbiAgICAgICAgICAgICdBdXRob3JpemF0aW9uJzogJ0JlYXJlciAnICsgc2VydmljZU9wdGlvbnMudG9rZW5cbiAgICAgICAgfTtcbiAgICB9XG4gICAgdmFyIGh0dHAgPSBuZXcgVHJhbnNwb3J0RmFjdG9yeShodHRwT3B0aW9ucyk7XG4gICAgaHR0cC5zcGxpdEdldCA9IHJ1dGlsLnNwbGl0R2V0RmFjdG9yeShodHRwT3B0aW9ucyk7XG5cbiAgICB2YXIgc2V0RmlsdGVyT3JUaHJvd0Vycm9yID0gZnVuY3Rpb24gKG9wdGlvbnMpIHtcbiAgICAgICAgaWYgKG9wdGlvbnMuaWQpIHtcbiAgICAgICAgICAgIHNlcnZpY2VPcHRpb25zLmZpbHRlciA9IG9wdGlvbnMuaWQ7XG4gICAgICAgIH1cbiAgICAgICAgaWYgKG9wdGlvbnMuZmlsdGVyKSB7XG4gICAgICAgICAgICBzZXJ2aWNlT3B0aW9ucy5maWx0ZXIgPSBvcHRpb25zLmZpbHRlcjtcbiAgICAgICAgfVxuICAgICAgICBpZiAoIXNlcnZpY2VPcHRpb25zLmZpbHRlcikge1xuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdObyBmaWx0ZXIgc3BlY2lmaWVkIHRvIGFwcGx5IG9wZXJhdGlvbnMgYWdhaW5zdCcpO1xuICAgICAgICB9XG4gICAgfTtcblxuICAgIHZhciBwdWJsaWNBc3luY0FQSSA9IHtcbiAgICAgICAgdXJsQ29uZmlnOiB1cmxDb25maWcsXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIENyZWF0ZSBhIG5ldyBydW4uXG4gICAgICAgICAqXG4gICAgICAgICAqIE5PVEU6IFR5cGljYWxseSB0aGlzIGlzIG5vdCB1c2VkISBVc2UgYFJ1bk1hbmFnZXIuZ2V0UnVuKClgIHdpdGggYSBgc3RyYXRlZ3lgIG9mIGBhbHdheXMtbmV3YCwgb3IgdXNlIGBSdW5NYW5hZ2VyLnJlc2V0KClgLiBTZWUgW1J1biBNYW5hZ2VyXSguLi9ydW4tbWFuYWdlci8pIGZvciBtb3JlIGRldGFpbHMuXG4gICAgICAgICAqXG4gICAgICAgICAqICAqKkV4YW1wbGUqKlxuICAgICAgICAgKlxuICAgICAgICAgKiAgICAgIHJzLmNyZWF0ZSgnaGVsbG9fd29ybGQuamwnKTtcbiAgICAgICAgICpcbiAgICAgICAgICogICoqUGFyYW1ldGVycyoqXG4gICAgICAgICAqIEBwYXJhbSB7U3RyaW5nfE9iamVjdH0gYHBhcmFtc2AgSWYgYSBzdHJpbmcsIHRoZSBuYW1lIG9mIHRoZSBwcmltYXJ5IFttb2RlbCBmaWxlXSguLi8uLi8uLi93cml0aW5nX3lvdXJfbW9kZWwvKS4gVGhpcyBpcyB0aGUgb25lIGZpbGUgaW4gdGhlIHByb2plY3QgdGhhdCBleHBsaWNpdGx5IGV4cG9zZXMgdmFyaWFibGVzIGFuZCBtZXRob2RzLCBhbmQgaXQgbXVzdCBiZSBzdG9yZWQgaW4gdGhlIE1vZGVsIGZvbGRlciBvZiB5b3VyIEVwaWNlbnRlciBwcm9qZWN0LiBJZiBhbiBvYmplY3QsIG1heSBpbmNsdWRlIGBtb2RlbGAsIGBzY29wZWAsIGFuZCBgZmlsZXNgLiAoU2VlIHRoZSBbUnVuIE1hbmFnZXJdKC4uL3J1bl9tYW5hZ2VyLykgZm9yIG1vcmUgaW5mb3JtYXRpb24gb24gYHNjb3BlYCBhbmQgYGZpbGVzYC4pXG4gICAgICAgICAqIEBwYXJhbSB7T2JqZWN0fSBgb3B0aW9uc2AgKE9wdGlvbmFsKSBPdmVycmlkZXMgZm9yIGNvbmZpZ3VyYXRpb24gb3B0aW9ucy5cbiAgICAgICAgICpcbiAgICAgICAgICovXG4gICAgICAgIGNyZWF0ZTogZnVuY3Rpb24gKHBhcmFtcywgb3B0aW9ucykge1xuICAgICAgICAgICAgdmFyIGNyZWF0ZU9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSwgc2VydmljZU9wdGlvbnMsIG9wdGlvbnMsIHsgdXJsOiB1cmxDb25maWcuZ2V0QVBJUGF0aCgncnVuJykgfSk7XG4gICAgICAgICAgICB2YXIgcnVuQXBpUGFyYW1zID0gWydtb2RlbCcsICdzY29wZScsICdmaWxlcyddO1xuICAgICAgICAgICAgaWYgKHR5cGVvZiBwYXJhbXMgPT09ICdzdHJpbmcnKSB7XG4gICAgICAgICAgICAgICAgLy8gdGhpcyBpcyBqdXN0IHRoZSBtb2RlbCBuYW1lXG4gICAgICAgICAgICAgICAgcGFyYW1zID0geyBtb2RlbDogcGFyYW1zIH07XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgIC8vIHdoaXRlbGlzdCB0aGUgZmllbGRzIHRoYXQgd2UgYWN0dWFsbHkgY2FuIHNlbmQgdG8gdGhlIGFwaVxuICAgICAgICAgICAgICAgIHBhcmFtcyA9IF9waWNrKHBhcmFtcywgcnVuQXBpUGFyYW1zKTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgdmFyIG9sZFN1Y2Nlc3MgPSBjcmVhdGVPcHRpb25zLnN1Y2Nlc3M7XG4gICAgICAgICAgICBjcmVhdGVPcHRpb25zLnN1Y2Nlc3MgPSBmdW5jdGlvbiAocmVzcG9uc2UpIHtcbiAgICAgICAgICAgICAgICBzZXJ2aWNlT3B0aW9ucy5maWx0ZXIgPSByZXNwb25zZS5pZDsgLy9hbGwgZnV0dXJlIGNoYWluZWQgY2FsbHMgdG8gb3BlcmF0ZSBvbiB0aGlzIGlkXG4gICAgICAgICAgICAgICAgcmV0dXJuIG9sZFN1Y2Nlc3MuYXBwbHkodGhpcywgYXJndW1lbnRzKTtcbiAgICAgICAgICAgIH07XG5cbiAgICAgICAgICAgIHJldHVybiBodHRwLnBvc3QocGFyYW1zLCBjcmVhdGVPcHRpb25zKTtcbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgICogUmV0dXJucyBwYXJ0aWN1bGFyIHJ1bnMsIGJhc2VkIG9uIGNvbmRpdGlvbnMgc3BlY2lmaWVkIGluIHRoZSBgcXNgIG9iamVjdC5cbiAgICAgICAgICpcbiAgICAgICAgICogVGhlIGVsZW1lbnRzIG9mIHRoZSBgcXNgIG9iamVjdCBhcmUgQU5EZWQgdG9nZXRoZXIgd2l0aGluIGEgc2luZ2xlIGNhbGwgdG8gYC5xdWVyeSgpYC5cbiAgICAgICAgICpcbiAgICAgICAgICogKipFeGFtcGxlKipcbiAgICAgICAgICpcbiAgICAgICAgICogICAgICAvLyByZXR1cm5zIHJ1bnMgd2l0aCBzYXZlZCA9IHRydWUgYW5kIHZhcmlhYmxlcy5wcmljZSA+IDEsXG4gICAgICAgICAqICAgICAgLy8gd2hlcmUgdmFyaWFibGVzLnByaWNlIGhhcyBiZWVuIHBlcnNpc3RlZCAocmVjb3JkZWQpXG4gICAgICAgICAqICAgICAgLy8gaW4gdGhlIG1vZGVsLlxuICAgICAgICAgKiAgICAgcnMucXVlcnkoe1xuICAgICAgICAgKiAgICAgICAgICAnc2F2ZWQnOiAndHJ1ZScsXG4gICAgICAgICAqICAgICAgICAgICcucHJpY2UnOiAnPjEnXG4gICAgICAgICAqICAgICAgIH0sXG4gICAgICAgICAqICAgICAgIHtcbiAgICAgICAgICogICAgICAgICAgc3RhcnRyZWNvcmQ6IDIsXG4gICAgICAgICAqICAgICAgICAgIGVuZHJlY29yZDogNVxuICAgICAgICAgKiAgICAgICB9KTtcbiAgICAgICAgICpcbiAgICAgICAgICogKipQYXJhbWV0ZXJzKipcbiAgICAgICAgICogQHBhcmFtIHtPYmplY3R9IGBxc2AgUXVlcnkgb2JqZWN0LiBFYWNoIGtleSBjYW4gYmUgYSBwcm9wZXJ0eSBvZiB0aGUgcnVuIG9yIHRoZSBuYW1lIG9mIHZhcmlhYmxlIHRoYXQgaGFzIGJlZW4gc2F2ZWQgaW4gdGhlIHJ1biAocHJlZmFjZWQgYnkgYHZhcmlhYmxlcy5gKS4gRWFjaCB2YWx1ZSBjYW4gYmUgYSBsaXRlcmFsIHZhbHVlLCBvciBhIGNvbXBhcmlzb24gb3BlcmF0b3IgYW5kIHZhbHVlLiAoU2VlIFttb3JlIG9uIGZpbHRlcmluZ10oLi4vLi4vLi4vcmVzdF9hcGlzL2FnZ3JlZ2F0ZV9ydW5fYXBpLyNmaWx0ZXJzKSBhbGxvd2VkIGluIHRoZSB1bmRlcmx5aW5nIFJ1biBBUEkuKSBRdWVyeWluZyBmb3IgdmFyaWFibGVzIGlzIGF2YWlsYWJsZSBmb3IgcnVucyBbaW4gbWVtb3J5XSguLi8uLi8uLi9ydW5fcGVyc2lzdGVuY2UvI3J1bnMtaW4tbWVtb3J5KSBhbmQgZm9yIHJ1bnMgW2luIHRoZSBkYXRhYmFzZV0oLi4vLi4vLi4vcnVuX3BlcnNpc3RlbmNlLyNydW5zLWluLW1lbW9yeSkgaWYgdGhlIHZhcmlhYmxlcyBhcmUgcGVyc2lzdGVkIChlLmcuIHRoYXQgaGF2ZSBiZWVuIGByZWNvcmRgZWQgaW4geW91ciBKdWxpYSBtb2RlbCkuXG4gICAgICAgICAqIEBwYXJhbSB7T2JqZWN0fSBgb3V0cHV0TW9kaWZpZXJgIChPcHRpb25hbCkgQXZhaWxhYmxlIGZpZWxkcyBpbmNsdWRlOiBgc3RhcnRyZWNvcmRgLCBgZW5kcmVjb3JkYCwgYHNvcnRgLCBhbmQgYGRpcmVjdGlvbmAgKGBhc2NgIG9yIGBkZXNjYCkuXG4gICAgICAgICAqIEBwYXJhbSB7T2JqZWN0fSBgb3B0aW9uc2AgKE9wdGlvbmFsKSBPdmVycmlkZXMgZm9yIGNvbmZpZ3VyYXRpb24gb3B0aW9ucy5cbiAgICAgICAgICovXG4gICAgICAgIHF1ZXJ5OiBmdW5jdGlvbiAocXMsIG91dHB1dE1vZGlmaWVyLCBvcHRpb25zKSB7XG4gICAgICAgICAgICBzZXJ2aWNlT3B0aW9ucy5maWx0ZXIgPSBxczsgLy9zaG91bGRuJ3QgYmUgYWJsZSB0byBvdmVyLXJpZGVcbiAgICAgICAgICAgIHZhciBodHRwT3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LCBzZXJ2aWNlT3B0aW9ucywgb3B0aW9ucyk7XG4gICAgICAgICAgICBodHRwT3B0aW9ucyA9IHVybENvbmZpZy5hZGRBdXRvUmVzdG9yZUhlYWRlcihodHRwT3B0aW9ucyk7XG5cbiAgICAgICAgICAgIHJldHVybiBodHRwLnNwbGl0R2V0KG91dHB1dE1vZGlmaWVyLCBodHRwT3B0aW9ucyk7XG4gICAgICAgIH0sXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIFJldHVybnMgcGFydGljdWxhciBydW5zLCBiYXNlZCBvbiBjb25kaXRpb25zIHNwZWNpZmllZCBpbiB0aGUgYHFzYCBvYmplY3QuXG4gICAgICAgICAqXG4gICAgICAgICAqIFNpbWlsYXIgdG8gYC5xdWVyeSgpYC5cbiAgICAgICAgICpcbiAgICAgICAgICogKipQYXJhbWV0ZXJzKipcbiAgICAgICAgICogQHBhcmFtIHtPYmplY3R9IGBmaWx0ZXJgIEZpbHRlciBvYmplY3QuIEVhY2gga2V5IGNhbiBiZSBhIHByb3BlcnR5IG9mIHRoZSBydW4gb3IgdGhlIG5hbWUgb2YgdmFyaWFibGUgdGhhdCBoYXMgYmVlbiBzYXZlZCBpbiB0aGUgcnVuIChwcmVmYWNlZCBieSBgdmFyaWFibGVzLmApLiBFYWNoIHZhbHVlIGNhbiBiZSBhIGxpdGVyYWwgdmFsdWUsIG9yIGEgY29tcGFyaXNvbiBvcGVyYXRvciBhbmQgdmFsdWUuIChTZWUgW21vcmUgb24gZmlsdGVyaW5nXSguLi8uLi8uLi9yZXN0X2FwaXMvYWdncmVnYXRlX3J1bl9hcGkvI2ZpbHRlcnMpIGFsbG93ZWQgaW4gdGhlIHVuZGVybHlpbmcgUnVuIEFQSS4pIEZpbHRlcmluZyBmb3IgdmFyaWFibGVzIGlzIGF2YWlsYWJsZSBmb3IgcnVucyBbaW4gbWVtb3J5XSguLi8uLi8uLi9ydW5fcGVyc2lzdGVuY2UvI3J1bnMtaW4tbWVtb3J5KSBhbmQgZm9yIHJ1bnMgW2luIHRoZSBkYXRhYmFzZV0oLi4vLi4vLi4vcnVuX3BlcnNpc3RlbmNlLyNydW5zLWluLW1lbW9yeSkgaWYgdGhlIHZhcmlhYmxlcyBhcmUgcGVyc2lzdGVkIChlLmcuIHRoYXQgaGF2ZSBiZWVuIGByZWNvcmRgZWQgaW4geW91ciBKdWxpYSBtb2RlbCkuXG4gICAgICAgICAqIEBwYXJhbSB7T2JqZWN0fSBgb3V0cHV0TW9kaWZpZXJgIChPcHRpb25hbCkgQXZhaWxhYmxlIGZpZWxkcyBpbmNsdWRlOiBgc3RhcnRyZWNvcmRgLCBgZW5kcmVjb3JkYCwgYHNvcnRgLCBhbmQgYGRpcmVjdGlvbmAgKGBhc2NgIG9yIGBkZXNjYCkuXG4gICAgICAgICAqIEBwYXJhbSB7T2JqZWN0fSBgb3B0aW9uc2AgKE9wdGlvbmFsKSBPdmVycmlkZXMgZm9yIGNvbmZpZ3VyYXRpb24gb3B0aW9ucy5cbiAgICAgICAgICovXG4gICAgICAgIGZpbHRlcjogZnVuY3Rpb24gKGZpbHRlciwgb3V0cHV0TW9kaWZpZXIsIG9wdGlvbnMpIHtcbiAgICAgICAgICAgIGlmICgkLmlzUGxhaW5PYmplY3Qoc2VydmljZU9wdGlvbnMuZmlsdGVyKSkge1xuICAgICAgICAgICAgICAgICQuZXh0ZW5kKHNlcnZpY2VPcHRpb25zLmZpbHRlciwgZmlsdGVyKTtcbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgc2VydmljZU9wdGlvbnMuZmlsdGVyID0gZmlsdGVyO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgdmFyIGh0dHBPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sIHNlcnZpY2VPcHRpb25zLCBvcHRpb25zKTtcbiAgICAgICAgICAgIGh0dHBPcHRpb25zID0gdXJsQ29uZmlnLmFkZEF1dG9SZXN0b3JlSGVhZGVyKGh0dHBPcHRpb25zKTtcbiAgICAgICAgICAgIHJldHVybiBodHRwLnNwbGl0R2V0KG91dHB1dE1vZGlmaWVyLCBodHRwT3B0aW9ucyk7XG4gICAgICAgIH0sXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIEdldCBkYXRhIGZvciBhIHNwZWNpZmljIHJ1bi4gVGhpcyBpbmNsdWRlcyBzdGFuZGFyZCBydW4gZGF0YSBzdWNoIGFzIHRoZSBhY2NvdW50LCBtb2RlbCwgcHJvamVjdCwgYW5kIGNyZWF0ZWQgYW5kIGxhc3QgbW9kaWZpZWQgZGF0ZXMuIFRvIHJlcXVlc3Qgc3BlY2lmaWMgbW9kZWwgdmFyaWFibGVzLCBwYXNzIHRoZW0gYXMgcGFydCBvZiB0aGUgYGZpbHRlcnNgIHBhcmFtZXRlci5cbiAgICAgICAgICpcbiAgICAgICAgICogTm90ZSB0aGF0IGlmIHRoZSBydW4gaXMgW2luIG1lbW9yeV0oLi4vLi4vLi4vcnVuX3BlcnNpc3RlbmNlLyNydW5zLWluLW1lbW9yeSksIGFueSBtb2RlbCB2YXJpYWJsZXMgYXJlIGF2YWlsYWJsZTsgaWYgdGhlIHJ1biBpcyBbaW4gdGhlIGRhdGFiYXNlXSguLi8uLi8uLi9ydW5fcGVyc2lzdGVuY2UvI3J1bnMtaW4tZGIpLCBvbmx5IG1vZGVsIHZhcmlhYmxlcyB0aGF0IGhhdmUgYmVlbiBwZXJzaXN0ZWQgJm1kYXNoOyB0aGF0IGlzLCBgcmVjb3JkYGVkIGluIHlvdXIgSnVsaWEgbW9kZWwgJm1kYXNoOyBhcmUgYXZhaWxhYmxlLlxuICAgICAgICAgKlxuICAgICAgICAgKiAqKkV4YW1wbGUqKlxuICAgICAgICAgKlxuICAgICAgICAgKiAgICAgcnMubG9hZCgnYmI1ODk2NzctZDQ3Ni00OTcxLWE2OGUtMGM1OGQxOTFlNDUwJywgeyBpbmNsdWRlOiBbJy5wcmljZScsICcuc2FsZXMnXSB9KTtcbiAgICAgICAgICpcbiAgICAgICAgICogKipQYXJhbWV0ZXJzKipcbiAgICAgICAgICogQHBhcmFtIHtTdHJpbmd9IGBydW5JRGAgVGhlIHJ1biBpZC5cbiAgICAgICAgICogQHBhcmFtIHtPYmplY3R9IGBmaWx0ZXJzYCAoT3B0aW9uYWwpIE9iamVjdCBjb250YWluaW5nIGZpbHRlcnMgYW5kIG9wZXJhdGlvbiBtb2RpZmllcnMuIFVzZSBrZXkgYGluY2x1ZGVgIHRvIGxpc3QgbW9kZWwgdmFyaWFibGVzIHRoYXQgeW91IHdhbnQgdG8gaW5jbHVkZSBpbiB0aGUgcmVzcG9uc2UuIE90aGVyIGF2YWlsYWJsZSBmaWVsZHMgaW5jbHVkZTogYHN0YXJ0cmVjb3JkYCwgYGVuZHJlY29yZGAsIGBzb3J0YCwgYW5kIGBkaXJlY3Rpb25gIChgYXNjYCBvciBgZGVzY2ApLlxuICAgICAgICAgKiBAcGFyYW0ge09iamVjdH0gYG9wdGlvbnNgIChPcHRpb25hbCkgT3ZlcnJpZGVzIGZvciBjb25maWd1cmF0aW9uIG9wdGlvbnMuXG4gICAgICAgICAqL1xuICAgICAgICBsb2FkOiBmdW5jdGlvbiAocnVuSUQsIGZpbHRlcnMsIG9wdGlvbnMpIHtcbiAgICAgICAgICAgIGlmIChydW5JRCkge1xuICAgICAgICAgICAgICAgIHNlcnZpY2VPcHRpb25zLmZpbHRlciA9IHJ1bklEOyAvL3Nob3VsZG4ndCBiZSBhYmxlIHRvIG92ZXItcmlkZVxuICAgICAgICAgICAgfVxuICAgICAgICAgICAgdmFyIGh0dHBPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sIHNlcnZpY2VPcHRpb25zLCBvcHRpb25zKTtcbiAgICAgICAgICAgIGh0dHBPcHRpb25zID0gdXJsQ29uZmlnLmFkZEF1dG9SZXN0b3JlSGVhZGVyKGh0dHBPcHRpb25zKTtcbiAgICAgICAgICAgIHJldHVybiBodHRwLmdldChmaWx0ZXJzLCBodHRwT3B0aW9ucyk7XG4gICAgICAgIH0sXG5cblxuICAgICAgICAvKipcbiAgICAgICAgICogU2F2ZSBhdHRyaWJ1dGVzIChkYXRhLCBtb2RlbCB2YXJpYWJsZXMpIG9mIHRoZSBydW4uXG4gICAgICAgICAqXG4gICAgICAgICAqICoqRXhhbXBsZXMqKlxuICAgICAgICAgKlxuICAgICAgICAgKiAgICAgLy8gYWRkICdjb21wbGV0ZWQnIGZpZWxkIHRvIHJ1biByZWNvcmRcbiAgICAgICAgICogICAgIHJzLnNhdmUoeyBjb21wbGV0ZWQ6IHRydWUgfSk7XG4gICAgICAgICAqXG4gICAgICAgICAqICAgICAvLyB1cGRhdGUgJ3NhdmVkJyBmaWVsZCBvZiBydW4gcmVjb3JkLCBhbmQgdXBkYXRlIHZhbHVlcyBvZiBtb2RlbCB2YXJpYWJsZXMgZm9yIHRoaXMgcnVuXG4gICAgICAgICAqICAgICBycy5zYXZlKHsgc2F2ZWQ6IHRydWUsIHZhcmlhYmxlczogeyBhOiAyMywgYjogMjMgfSB9KTtcbiAgICAgICAgICpcbiAgICAgICAgICogKipQYXJhbWV0ZXJzKipcbiAgICAgICAgICogQHBhcmFtIHtPYmplY3R9IGBhdHRyaWJ1dGVzYCBUaGUgcnVuIGRhdGEgYW5kIHZhcmlhYmxlcyB0byBzYXZlLlxuICAgICAgICAgKiBAcGFyYW0ge09iamVjdH0gYGF0dHJpYnV0ZXMudmFyaWFibGVzYCBNb2RlbCB2YXJpYWJsZXMgbXVzdCBiZSBpbmNsdWRlZCBpbiBhIGB2YXJpYWJsZXNgIGZpZWxkIHdpdGhpbiB0aGUgYGF0dHJpYnV0ZXNgIG9iamVjdC4gKE90aGVyd2lzZSB0aGV5IGFyZSB0cmVhdGVkIGFzIHJ1biBkYXRhIGFuZCBhZGRlZCB0byB0aGUgcnVuIHJlY29yZCBkaXJlY3RseS4pXG4gICAgICAgICAqIEBwYXJhbSB7T2JqZWN0fSBgb3B0aW9uc2AgKE9wdGlvbmFsKSBPdmVycmlkZXMgZm9yIGNvbmZpZ3VyYXRpb24gb3B0aW9ucy5cbiAgICAgICAgICovXG4gICAgICAgIHNhdmU6IGZ1bmN0aW9uIChhdHRyaWJ1dGVzLCBvcHRpb25zKSB7XG4gICAgICAgICAgICB2YXIgaHR0cE9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSwgc2VydmljZU9wdGlvbnMsIG9wdGlvbnMpO1xuICAgICAgICAgICAgc2V0RmlsdGVyT3JUaHJvd0Vycm9yKGh0dHBPcHRpb25zKTtcbiAgICAgICAgICAgIHJldHVybiBodHRwLnBhdGNoKGF0dHJpYnV0ZXMsIGh0dHBPcHRpb25zKTtcbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgICogQ2FsbCBhIG1ldGhvZCBmcm9tIHRoZSBtb2RlbC5cbiAgICAgICAgICpcbiAgICAgICAgICogRGVwZW5kaW5nIG9uIHRoZSBsYW5ndWFnZSBpbiB3aGljaCB5b3UgaGF2ZSB3cml0dGVuIHlvdXIgbW9kZWwsIHRoZSBtZXRob2QgbWF5IG5lZWQgdG8gYmUgZXhwb3NlZCAoZS5nLiBgZXhwb3J0YCBmb3IgYSBKdWxpYSBtb2RlbCkgaW4gdGhlIG1vZGVsIGZpbGUgaW4gb3JkZXIgdG8gYmUgY2FsbGVkIHRocm91Z2ggdGhlIEFQSS4gU2VlIFtXcml0aW5nIHlvdXIgTW9kZWxdKC4uLy4uLy4uL3dyaXRpbmdfeW91cl9tb2RlbC8pKS5cbiAgICAgICAgICpcbiAgICAgICAgICogVGhlIGBwYXJhbXNgIGFyZ3VtZW50IGlzIG5vcm1hbGx5IGFuIGFycmF5IG9mIGFyZ3VtZW50cyB0byB0aGUgYG9wZXJhdGlvbmAuIEluIHRoZSBzcGVjaWFsIGNhc2Ugd2hlcmUgYG9wZXJhdGlvbmAgb25seSB0YWtlcyBvbmUgYXJndW1lbnQsIHlvdSBhcmUgbm90IHJlcXVpcmVkIHRvIHB1dCB0aGF0IGFyZ3VtZW50IGludG8gYW4gYXJyYXkuXG4gICAgICAgICAqXG4gICAgICAgICAqIE5vdGUgdGhhdCB5b3UgY2FuIGNvbWJpbmUgdGhlIGBvcGVyYXRpb25gIGFuZCBgcGFyYW1zYCBhcmd1bWVudHMgaW50byBhIHNpbmdsZSBvYmplY3QgaWYgeW91IHByZWZlciwgYXMgaW4gdGhlIGxhc3QgZXhhbXBsZS5cbiAgICAgICAgICpcbiAgICAgICAgICogKipFeGFtcGxlcyoqXG4gICAgICAgICAqXG4gICAgICAgICAqICAgICAgLy8gbWV0aG9kIFwic29sdmVcIiB0YWtlcyBubyBhcmd1bWVudHNcbiAgICAgICAgICogICAgIHJzLmRvKCdzb2x2ZScpO1xuICAgICAgICAgKiAgICAgIC8vIG1ldGhvZCBcImVjaG9cIiB0YWtlcyBvbmUgYXJndW1lbnQsIGEgc3RyaW5nXG4gICAgICAgICAqICAgICBycy5kbygnZWNobycsIFsnaGVsbG8nXSk7XG4gICAgICAgICAqICAgICAgLy8gbWV0aG9kIFwiZWNob1wiIHRha2VzIG9uZSBhcmd1bWVudCwgYSBzdHJpbmdcbiAgICAgICAgICogICAgIHJzLmRvKCdlY2hvJywgJ2hlbGxvJyk7XG4gICAgICAgICAqICAgICAgLy8gbWV0aG9kIFwic3VtQXJyYXlcIiB0YWtlcyBvbmUgYXJndW1lbnQsIGFuIGFycmF5XG4gICAgICAgICAqICAgICBycy5kbygnc3VtQXJyYXknLCBbWzQsMiwxXV0pO1xuICAgICAgICAgKiAgICAgIC8vIG1ldGhvZCBcImFkZFwiIHRha2VzIHR3byBhcmd1bWVudHMsIGJvdGggaW50ZWdlcnNcbiAgICAgICAgICogICAgIHJzLmRvKHsgbmFtZTonYWRkJywgcGFyYW1zOlsyLDRdIH0pO1xuICAgICAgICAgKlxuICAgICAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAgKiBAcGFyYW0ge1N0cmluZ30gYG9wZXJhdGlvbmAgTmFtZSBvZiBtZXRob2QuXG4gICAgICAgICAqIEBwYXJhbSB7QXJyYXl9IGBwYXJhbXNgIChPcHRpb25hbCkgQW55IHBhcmFtZXRlcnMgdGhlIG9wZXJhdGlvbiB0YWtlcywgcGFzc2VkIGFzIGFuIGFycmF5LiBJbiB0aGUgc3BlY2lhbCBjYXNlIHdoZXJlIGBvcGVyYXRpb25gIG9ubHkgdGFrZXMgb25lIGFyZ3VtZW50LCB5b3UgYXJlIG5vdCByZXF1aXJlZCB0byBwdXQgdGhhdCBhcmd1bWVudCBpbnRvIGFuIGFycmF5LCBhbmQgY2FuIGp1c3QgcGFzcyBpdCBkaXJlY3RseS5cbiAgICAgICAgICogQHBhcmFtIHtPYmplY3R9IGBvcHRpb25zYCAoT3B0aW9uYWwpIE92ZXJyaWRlcyBmb3IgY29uZmlndXJhdGlvbiBvcHRpb25zLlxuICAgICAgICAgKi9cbiAgICAgICAgZG86IGZ1bmN0aW9uIChvcGVyYXRpb24sIHBhcmFtcywgb3B0aW9ucykge1xuICAgICAgICAgICAgLy8gY29uc29sZS5sb2coJ2RvJywgb3BlcmF0aW9uLCBwYXJhbXMpO1xuICAgICAgICAgICAgdmFyIG9wc0FyZ3M7XG4gICAgICAgICAgICB2YXIgcG9zdE9wdGlvbnM7XG4gICAgICAgICAgICBpZiAob3B0aW9ucykge1xuICAgICAgICAgICAgICAgIG9wc0FyZ3MgPSBwYXJhbXM7XG4gICAgICAgICAgICAgICAgcG9zdE9wdGlvbnMgPSBvcHRpb25zO1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICBpZiAoJC5pc1BsYWluT2JqZWN0KHBhcmFtcykpIHtcbiAgICAgICAgICAgICAgICAgICAgb3BzQXJncyA9IG51bGw7XG4gICAgICAgICAgICAgICAgICAgIHBvc3RPcHRpb25zID0gcGFyYW1zO1xuICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgIG9wc0FyZ3MgPSBwYXJhbXM7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICAgICAgdmFyIHJlc3VsdCA9IHJ1dGlsLm5vcm1hbGl6ZU9wZXJhdGlvbnMob3BlcmF0aW9uLCBvcHNBcmdzKTtcbiAgICAgICAgICAgIHZhciBodHRwT3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LCBzZXJ2aWNlT3B0aW9ucywgcG9zdE9wdGlvbnMpO1xuXG4gICAgICAgICAgICBzZXRGaWx0ZXJPclRocm93RXJyb3IoaHR0cE9wdGlvbnMpO1xuXG4gICAgICAgICAgICB2YXIgcHJtcyA9IChyZXN1bHQuYXJnc1swXS5sZW5ndGggJiYgKHJlc3VsdC5hcmdzWzBdICE9PSBudWxsICYmIHJlc3VsdC5hcmdzWzBdICE9PSB1bmRlZmluZWQpKSA/IHJlc3VsdC5hcmdzWzBdIDogW107XG4gICAgICAgICAgICByZXR1cm4gaHR0cC5wb3N0KHsgYXJndW1lbnRzOiBwcm1zIH0sICQuZXh0ZW5kKHRydWUsIHt9LCBodHRwT3B0aW9ucywge1xuICAgICAgICAgICAgICAgIHVybDogdXJsQ29uZmlnLmdldEZpbHRlclVSTCgpICsgJ29wZXJhdGlvbnMvJyArIHJlc3VsdC5vcHNbMF0gKyAnLydcbiAgICAgICAgICAgIH0pKTtcbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgICogQ2FsbCBzZXZlcmFsIG1ldGhvZHMgZnJvbSB0aGUgbW9kZWwsIHNlcXVlbnRpYWxseS5cbiAgICAgICAgICpcbiAgICAgICAgICogRGVwZW5kaW5nIG9uIHRoZSBsYW5ndWFnZSBpbiB3aGljaCB5b3UgaGF2ZSB3cml0dGVuIHlvdXIgbW9kZWwsIHRoZSBtZXRob2RzIG1heSBuZWVkIHRvIGJlIGV4cG9zZWQgKGUuZy4gYGV4cG9ydGAgZm9yIGEgSnVsaWEgbW9kZWwpIGluIHRoZSBtb2RlbCBmaWxlIGluIG9yZGVyIHRvIGJlIGNhbGxlZCB0aHJvdWdoIHRoZSBBUEkuIFNlZSBbV3JpdGluZyB5b3VyIE1vZGVsXSguLi8uLi8uLi93cml0aW5nX3lvdXJfbW9kZWwvKSkuXG4gICAgICAgICAqXG4gICAgICAgICAqICoqRXhhbXBsZXMqKlxuICAgICAgICAgKlxuICAgICAgICAgKiAgICAgIC8vIG1ldGhvZHMgXCJpbml0aWFsaXplXCIgYW5kIFwic29sdmVcIiBkbyBub3QgdGFrZSBhbnkgYXJndW1lbnRzXG4gICAgICAgICAqICAgICBycy5zZXJpYWwoWydpbml0aWFsaXplJywgJ3NvbHZlJ10pO1xuICAgICAgICAgKiAgICAgIC8vIG1ldGhvZHMgXCJpbml0XCIgYW5kIFwicmVzZXRcIiB0YWtlIHR3byBhcmd1bWVudHMgZWFjaFxuICAgICAgICAgKiAgICAgcnMuc2VyaWFsKFsgIHsgbmFtZTogJ2luaXQnLCBwYXJhbXM6IFsxLDJdIH0sXG4gICAgICAgICAqICAgICAgICAgICAgICAgICAgeyBuYW1lOiAncmVzZXQnLCBwYXJhbXM6IFsyLDNdIH1dKTtcbiAgICAgICAgICogICAgICAvLyBtZXRob2QgXCJpbml0XCIgdGFrZXMgdHdvIGFyZ3VtZW50cyxcbiAgICAgICAgICogICAgICAvLyBtZXRob2QgXCJydW5tb2RlbFwiIHRha2VzIG5vbmVcbiAgICAgICAgICogICAgIHJzLnNlcmlhbChbICB7IG5hbWU6ICdpbml0JywgcGFyYW1zOiBbMSwyXSB9LFxuICAgICAgICAgKiAgICAgICAgICAgICAgICAgIHsgbmFtZTogJ3J1bm1vZGVsJywgcGFyYW1zOiBbXSB9XSk7XG4gICAgICAgICAqXG4gICAgICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICAgICAqIEBwYXJhbSB7QXJyYXl9IGBvcGVyYXRpb25zYCBJZiBub25lIG9mIHRoZSBtZXRob2RzIHRha2UgcGFyYW1ldGVycywgcGFzcyBhbiBhcnJheSBvZiB0aGUgbWV0aG9kIG5hbWVzIChzdHJpbmdzKS4gSWYgYW55IG9mIHRoZSBtZXRob2RzIGRvIHRha2UgcGFyYW1ldGVycywgcGFzcyBhbiBhcnJheSBvZiBvYmplY3RzLCBlYWNoIG9mIHdoaWNoIGNvbnRhaW5zIGEgbWV0aG9kIG5hbWUgYW5kIGl0cyBvd24gKHBvc3NpYmx5IGVtcHR5KSBhcnJheSBvZiBwYXJhbWV0ZXJzLlxuICAgICAgICAgKiBAcGFyYW0geyp9IGBwYXJhbXNgIFBhcmFtZXRlcnMgdG8gcGFzcyB0byBvcGVyYXRpb25zLlxuICAgICAgICAgKiBAcGFyYW0ge09iamVjdH0gYG9wdGlvbnNgIChPcHRpb25hbCkgT3ZlcnJpZGVzIGZvciBjb25maWd1cmF0aW9uIG9wdGlvbnMuXG4gICAgICAgICAqL1xuICAgICAgICBzZXJpYWw6IGZ1bmN0aW9uIChvcGVyYXRpb25zLCBwYXJhbXMsIG9wdGlvbnMpIHtcbiAgICAgICAgICAgIHZhciBvcFBhcmFtcyA9IHJ1dGlsLm5vcm1hbGl6ZU9wZXJhdGlvbnMob3BlcmF0aW9ucywgcGFyYW1zKTtcbiAgICAgICAgICAgIHZhciBvcHMgPSBvcFBhcmFtcy5vcHM7XG4gICAgICAgICAgICB2YXIgYXJncyA9IG9wUGFyYW1zLmFyZ3M7XG4gICAgICAgICAgICB2YXIgbWUgPSB0aGlzO1xuXG4gICAgICAgICAgICB2YXIgJGQgPSAkLkRlZmVycmVkKCk7XG4gICAgICAgICAgICB2YXIgcG9zdE9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSwgc2VydmljZU9wdGlvbnMsIG9wdGlvbnMpO1xuXG4gICAgICAgICAgICB2YXIgZG9TaW5nbGVPcCA9IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgICAgICB2YXIgb3AgPSBvcHMuc2hpZnQoKTtcbiAgICAgICAgICAgICAgICB2YXIgYXJnID0gYXJncy5zaGlmdCgpO1xuXG4gICAgICAgICAgICAgICAgbWUuZG8ob3AsIGFyZywge1xuICAgICAgICAgICAgICAgICAgICBzdWNjZXNzOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBpZiAob3BzLmxlbmd0aCkge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRvU2luZ2xlT3AoKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgJGQucmVzb2x2ZS5hcHBseSh0aGlzLCBhcmd1bWVudHMpO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBvc3RPcHRpb25zLnN1Y2Nlc3MuYXBwbHkodGhpcywgYXJndW1lbnRzKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgICAgICAgICAgZXJyb3I6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICRkLnJlamVjdC5hcHBseSh0aGlzLCBhcmd1bWVudHMpO1xuICAgICAgICAgICAgICAgICAgICAgICAgcG9zdE9wdGlvbnMuZXJyb3IuYXBwbHkodGhpcywgYXJndW1lbnRzKTtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgfTtcblxuICAgICAgICAgICAgZG9TaW5nbGVPcCgpO1xuXG4gICAgICAgICAgICByZXR1cm4gJGQucHJvbWlzZSgpO1xuICAgICAgICB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBDYWxsIHNldmVyYWwgbWV0aG9kcyBmcm9tIHRoZSBtb2RlbCwgZXhlY3V0aW5nIHRoZW0gaW4gcGFyYWxsZWwuXG4gICAgICAgICAqXG4gICAgICAgICAqIERlcGVuZGluZyBvbiB0aGUgbGFuZ3VhZ2UgaW4gd2hpY2ggeW91IGhhdmUgd3JpdHRlbiB5b3VyIG1vZGVsLCB0aGUgbWV0aG9kcyBtYXkgbmVlZCB0byBiZSBleHBvc2VkIChlLmcuIGBleHBvcnRgIGZvciBhIEp1bGlhIG1vZGVsKSBpbiB0aGUgbW9kZWwgZmlsZSBpbiBvcmRlciB0byBiZSBjYWxsZWQgdGhyb3VnaCB0aGUgQVBJLiBTZWUgW1dyaXRpbmcgeW91ciBNb2RlbF0oLi4vLi4vLi4vd3JpdGluZ195b3VyX21vZGVsLykpLlxuICAgICAgICAgKlxuICAgICAgICAgKiAqKkV4YW1wbGUqKlxuICAgICAgICAgKlxuICAgICAgICAgKiAgICAgIC8vIG1ldGhvZHMgXCJzb2x2ZVwiIGFuZCBcInJlc2V0XCIgZG8gbm90IHRha2UgYW55IGFyZ3VtZW50c1xuICAgICAgICAgKiAgICAgcnMucGFyYWxsZWwoWydzb2x2ZScsICdyZXNldCddKTtcbiAgICAgICAgICogICAgICAvLyBtZXRob2RzIFwiYWRkXCIgYW5kIFwic3VidHJhY3RcIiB0YWtlIHR3byBhcmd1bWVudHMgZWFjaFxuICAgICAgICAgKiAgICAgcnMucGFyYWxsZWwoWyB7IG5hbWU6ICdhZGQnLCBwYXJhbXM6IFsxLDJdIH0sXG4gICAgICAgICAqICAgICAgICAgICAgICAgICAgIHsgbmFtZTogJ3N1YnRyYWN0JywgcGFyYW1zOlsyLDNdIH1dKTtcbiAgICAgICAgICogICAgICAvLyBtZXRob2RzIFwiYWRkXCIgYW5kIFwic3VidHJhY3RcIiB0YWtlIHR3byBhcmd1bWVudHMgZWFjaFxuICAgICAgICAgKiAgICAgcnMucGFyYWxsZWwoeyBhZGQ6IFsxLDJdLCBzdWJ0cmFjdDogWzIsNF0gfSk7XG4gICAgICAgICAqXG4gICAgICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICAgICAqIEBwYXJhbSB7QXJyYXl8T2JqZWN0fSBgb3BlcmF0aW9uc2AgSWYgbm9uZSBvZiB0aGUgbWV0aG9kcyB0YWtlIHBhcmFtZXRlcnMsIHBhc3MgYW4gYXJyYXkgb2YgdGhlIG1ldGhvZCBuYW1lcyAoYXMgc3RyaW5ncykuIElmIGFueSBvZiB0aGUgbWV0aG9kcyBkbyB0YWtlIHBhcmFtZXRlcnMsIHlvdSBoYXZlIHR3byBvcHRpb25zLiBZb3UgY2FuIHBhc3MgYW4gYXJyYXkgb2Ygb2JqZWN0cywgZWFjaCBvZiB3aGljaCBjb250YWlucyBhIG1ldGhvZCBuYW1lIGFuZCBpdHMgb3duIChwb3NzaWJseSBlbXB0eSkgYXJyYXkgb2YgcGFyYW1ldGVycy4gQWx0ZXJuYXRpdmVseSwgeW91IGNhbiBwYXNzIGEgc2luZ2xlIG9iamVjdCB3aXRoIHRoZSBtZXRob2QgbmFtZSBhbmQgYSAocG9zc2libHkgZW1wdHkpIGFycmF5IG9mIHBhcmFtZXRlcnMuXG4gICAgICAgICAqIEBwYXJhbSB7Kn0gYHBhcmFtc2AgUGFyYW1ldGVycyB0byBwYXNzIHRvIG9wZXJhdGlvbnMuXG4gICAgICAgICAqIEBwYXJhbSB7T2JqZWN0fSBgb3B0aW9uc2AgKE9wdGlvbmFsKSBPdmVycmlkZXMgZm9yIGNvbmZpZ3VyYXRpb24gb3B0aW9ucy5cbiAgICAgICAgICovXG4gICAgICAgIHBhcmFsbGVsOiBmdW5jdGlvbiAob3BlcmF0aW9ucywgcGFyYW1zLCBvcHRpb25zKSB7XG4gICAgICAgICAgICB2YXIgJGQgPSAkLkRlZmVycmVkKCk7XG5cbiAgICAgICAgICAgIHZhciBvcFBhcmFtcyA9IHJ1dGlsLm5vcm1hbGl6ZU9wZXJhdGlvbnMob3BlcmF0aW9ucywgcGFyYW1zKTtcbiAgICAgICAgICAgIHZhciBvcHMgPSBvcFBhcmFtcy5vcHM7XG4gICAgICAgICAgICB2YXIgYXJncyA9IG9wUGFyYW1zLmFyZ3M7XG4gICAgICAgICAgICB2YXIgcG9zdE9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSwgc2VydmljZU9wdGlvbnMsIG9wdGlvbnMpO1xuXG4gICAgICAgICAgICB2YXIgcXVldWUgID0gW107XG4gICAgICAgICAgICBmb3IgKHZhciBpID0gMDsgaTwgb3BzLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgICAgICAgICAgcXVldWUucHVzaChcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5kbyhvcHNbaV0sIGFyZ3NbaV0pXG4gICAgICAgICAgICAgICAgKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgICQud2hlbi5hcHBseSh0aGlzLCBxdWV1ZSlcbiAgICAgICAgICAgICAgICAuZG9uZShmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICAgICAgICAgICRkLnJlc29sdmUuYXBwbHkodGhpcywgYXJndW1lbnRzKTtcbiAgICAgICAgICAgICAgICAgICAgcG9zdE9wdGlvbnMuc3VjY2Vzcy5hcHBseSh0aGlzLmFyZ3VtZW50cyk7XG4gICAgICAgICAgICAgICAgfSlcbiAgICAgICAgICAgICAgICAuZmFpbChmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICAgICAgICAgICRkLnJlamVjdC5hcHBseSh0aGlzLCBhcmd1bWVudHMpO1xuICAgICAgICAgICAgICAgICAgICBwb3N0T3B0aW9ucy5lcnJvci5hcHBseSh0aGlzLmFyZ3VtZW50cyk7XG4gICAgICAgICAgICAgICAgfSk7XG5cbiAgICAgICAgICAgIHJldHVybiAkZC5wcm9taXNlKCk7XG4gICAgICAgIH1cbiAgICB9O1xuXG4gICAgdmFyIHB1YmxpY1N5bmNBUEkgPSB7XG4gICAgICAgIGdldEN1cnJlbnRDb25maWc6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIHJldHVybiBzZXJ2aWNlT3B0aW9ucztcbiAgICAgICAgfSxcbiAgICAgICAgLyoqXG4gICAgICAgICAgKiBSZXR1cm5zIGEgVmFyaWFibGVzIFNlcnZpY2UgaW5zdGFuY2UuIFVzZSB0aGUgdmFyaWFibGVzIGluc3RhbmNlIHRvIGxvYWQsIHNhdmUsIGFuZCBxdWVyeSBmb3Igc3BlY2lmaWMgbW9kZWwgdmFyaWFibGVzLiBTZWUgdGhlIFtWYXJpYWJsZSBBUEkgU2VydmljZV0oLi4vdmFyaWFibGVzLWFwaS1zZXJ2aWNlLykgZm9yIG1vcmUgaW5mb3JtYXRpb24uXG4gICAgICAgICAgKlxuICAgICAgICAgICogKipFeGFtcGxlKipcbiAgICAgICAgICAqXG4gICAgICAgICAgKiAgICAgIHZhciB2cyA9IHJzLnZhcmlhYmxlcygpO1xuICAgICAgICAgICogICAgICB2cy5zYXZlKHsgc2FtcGxlX2ludDogNCB9KTtcbiAgICAgICAgICAqXG4gICAgICAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAgICogQHBhcmFtIHtPYmplY3R9IGBjb25maWdgIChPcHRpb25hbCkgT3ZlcnJpZGVzIGZvciBjb25maWd1cmF0aW9uIG9wdGlvbnMuXG4gICAgICAgICAgKi9cbiAgICAgICAgdmFyaWFibGVzOiBmdW5jdGlvbiAoY29uZmlnKSB7XG4gICAgICAgICAgICB2YXIgdnMgPSBuZXcgVmFyaWFibGVzU2VydmljZSgkLmV4dGVuZCh0cnVlLCB7fSwgc2VydmljZU9wdGlvbnMsIGNvbmZpZywge1xuICAgICAgICAgICAgICAgIHJ1blNlcnZpY2U6IHRoaXNcbiAgICAgICAgICAgIH0pKTtcbiAgICAgICAgICAgIHJldHVybiB2cztcbiAgICAgICAgfSxcblxuICAgICAgICBpbnRyb3NwZWN0aW9uOiBmdW5jdGlvbiAoY29uZmlnKSB7XG4gICAgICAgICAgICB2YXIgaW50cm9zcGVjdGlvbiA9IG5ldyBJbnRyb3NwZWN0aW9uU2VydmljZSgkLmV4dGVuZCh0cnVlLCB7fSwgc2VydmljZU9wdGlvbnMsIGNvbmZpZykpO1xuICAgICAgICAgICAgcmV0dXJuIGludHJvc3BlY3Rpb247XG4gICAgICAgIH1cbiAgICB9O1xuXG4gICAgJC5leHRlbmQodGhpcywgcHVibGljQXN5bmNBUEkpO1xuICAgICQuZXh0ZW5kKHRoaXMsIHB1YmxpY1N5bmNBUEkpO1xufTtcbiIsIid1c2Ugc3RyaWN0Jztcbi8qKlxuICogIyMgU3RhdGUgQVBJIEFkYXB0ZXJcbiAqXG4gKiBUaGUgU3RhdGUgQVBJIEFkYXB0ZXIgYWxsb3dzIHlvdSB0byByZXBsYXkgb3IgY2xvbmUgcnVucy4gSXQgYnJpbmdzIGV4aXN0aW5nLCBwZXJzaXN0ZWQgcnVuIGRhdGEgZnJvbSB0aGUgZGF0YWJhc2UgYmFjayBpbnRvIG1lbW9yeSwgdXNpbmcgdGhlIHNhbWUgcnVuIGlkIChgcmVwbGF5YCkgb3IgYSBuZXcgcnVuIGlkIChgY2xvbmVgKS4gUnVucyBtdXN0IGJlIGluIG1lbW9yeSBpbiBvcmRlciBmb3IgeW91IHRvIHVwZGF0ZSB2YXJpYWJsZXMgb3IgY2FsbCBvcGVyYXRpb25zIG9uIHRoZW0uXG4gKlxuICogU3BlY2lmaWNhbGx5LCB0aGUgU3RhdGUgQVBJIEFkYXB0ZXIgd29ya3MgYnkgXCJyZS1ydW5uaW5nXCIgdGhlIHJ1biAodXNlciBpbnRlcmFjdGlvbnMpIGZyb20gdGhlIGNyZWF0aW9uIG9mIHRoZSBydW4gdXAgdG8gdGhlIHRpbWUgaXQgd2FzIGxhc3QgcGVyc2lzdGVkIGluIHRoZSBkYXRhYmFzZS4gVGhpcyBwcm9jZXNzIHVzZXMgdGhlIGN1cnJlbnQgdmVyc2lvbiBvZiB0aGUgcnVuJ3MgbW9kZWwuIFRoZXJlZm9yZSwgaWYgdGhlIG1vZGVsIGhhcyBjaGFuZ2VkIHNpbmNlIHRoZSBvcmlnaW5hbCBydW4gd2FzIGNyZWF0ZWQsIHRoZSByZXRyaWV2ZWQgcnVuIHdpbGwgdXNlIHRoZSBuZXcgbW9kZWwg4oCUIGFuZCBtYXkgZW5kIHVwIGhhdmluZyBkaWZmZXJlbnQgdmFsdWVzIG9yIGJlaGF2aW9yIGFzIGEgcmVzdWx0LiBVc2Ugd2l0aCBjYXJlIVxuICpcbiAqIFRvIHVzZSB0aGUgU3RhdGUgQVBJIEFkYXB0ZXIsIGluc3RhbnRpYXRlIGl0IGFuZCB0aGVuIGNhbGwgaXRzIG1ldGhvZHM6XG4gKlxuICogICAgICB2YXIgc2EgPSBuZXcgRi5zZXJ2aWNlLlN0YXRlKCk7XG4gKiAgICAgIHNhLnJlcGxheSh7cnVuSWQ6ICcxODQyYmI1Yy04M2FkLTRiYTgtYTk1NS1iZDEzY2MyZmRiNGYnfSk7XG4gKlxuICogVGhlIGNvbnN0cnVjdG9yIHRha2VzIGFuIG9wdGlvbmFsIGBvcHRpb25zYCBwYXJhbWV0ZXIgaW4gd2hpY2ggeW91IGNhbiBzcGVjaWZ5IHRoZSBgYWNjb3VudGAgYW5kIGBwcm9qZWN0YCBpZiB0aGV5IGFyZSBub3QgYWxyZWFkeSBhdmFpbGFibGUgaW4gdGhlIGN1cnJlbnQgY29udGV4dC5cbiAqXG4gKi9cblxudmFyIENvbmZpZ1NlcnZpY2UgPSByZXF1aXJlKCcuL2NvbmZpZ3VyYXRpb24tc2VydmljZScpO1xudmFyIFRyYW5zcG9ydEZhY3RvcnkgPSByZXF1aXJlKCcuLi90cmFuc3BvcnQvaHR0cC10cmFuc3BvcnQtZmFjdG9yeScpO1xudmFyIF9waWNrID0gcmVxdWlyZSgnLi4vdXRpbC9vYmplY3QtdXRpbCcpLl9waWNrO1xudmFyIFNlc3Npb25NYW5hZ2VyID0gcmVxdWlyZSgnLi4vc3RvcmUvc2Vzc2lvbi1tYW5hZ2VyJyk7XG52YXIgYXBpRW5kcG9pbnQgPSAnbW9kZWwvc3RhdGUnO1xuXG5tb2R1bGUuZXhwb3J0cyA9IGZ1bmN0aW9uIChjb25maWcpIHtcblxuICAgIHZhciBkZWZhdWx0cyA9IHtcblxuICAgIH07XG5cbiAgICB0aGlzLnNlc3Npb25NYW5hZ2VyID0gbmV3IFNlc3Npb25NYW5hZ2VyKCk7XG4gICAgdmFyIHNlcnZpY2VPcHRpb25zID0gdGhpcy5zZXNzaW9uTWFuYWdlci5nZXRNZXJnZWRPcHRpb25zKGRlZmF1bHRzLCBjb25maWcpO1xuICAgIHZhciB1cmxDb25maWcgPSBuZXcgQ29uZmlnU2VydmljZShzZXJ2aWNlT3B0aW9ucykuZ2V0KCdzZXJ2ZXInKTtcblxuICAgIHZhciB0cmFuc3BvcnRPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sIHNlcnZpY2VPcHRpb25zLnRyYW5zcG9ydCwge1xuICAgICAgICB1cmw6IHVybENvbmZpZy5nZXRBUElQYXRoKGFwaUVuZHBvaW50KVxuICAgIH0pO1xuXG4gICAgaWYgKHNlcnZpY2VPcHRpb25zLnRva2VuKSB7XG4gICAgICAgIHRyYW5zcG9ydE9wdGlvbnMuaGVhZGVycyA9IHtcbiAgICAgICAgICAgICdBdXRob3JpemF0aW9uJzogJ0JlYXJlciAnICsgc2VydmljZU9wdGlvbnMudG9rZW5cbiAgICAgICAgfTtcbiAgICB9XG5cbiAgICB2YXIgaHR0cCA9IG5ldyBUcmFuc3BvcnRGYWN0b3J5KHRyYW5zcG9ydE9wdGlvbnMpO1xuICAgIHZhciBwYXJzZVJ1bklkT3JFcnJvciA9IGZ1bmN0aW9uIChwYXJhbXMpIHtcbiAgICAgICAgaWYgKCQuaXNQbGFpbk9iamVjdChwYXJhbXMpICYmIHBhcmFtcy5ydW5JZCkge1xuICAgICAgICAgICAgcmV0dXJuIHBhcmFtcy5ydW5JZDtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcignUGxlYXNlIHBhc3MgaW4gYSBydW4gaWQnKTtcbiAgICAgICAgfVxuICAgIH07XG5cbiAgICB2YXIgcHVibGljQVBJID0ge1xuICAgICAgICAvKipcbiAgICAgICAgKiBSZXBsYXkgYSBydW4uIEFmdGVyIHRoaXMgY2FsbCwgdGhlIHJ1biwgd2l0aCBpdHMgb3JpZ2luYWwgcnVuIGlkLCBpcyBub3cgYXZhaWxhYmxlIFtpbiBtZW1vcnldKC4uLy4uLy4uL3J1bl9wZXJzaXN0ZW5jZS8jcnVucy1pbi1tZW1vcnkpLiAoSXQgY29udGludWVzIHRvIGJlIHBlcnNpc3RlZCBpbnRvIHRoZSBFcGljZW50ZXIgZGF0YWJhc2UgYXQgcmVndWxhciBpbnRlcnZhbHMuKVxuICAgICAgICAqXG4gICAgICAgICogICoqRXhhbXBsZSoqXG4gICAgICAgICpcbiAgICAgICAgKiAgICAgIHZhciBzYSA9IG5ldyBGLnNlcnZpY2UuU3RhdGUoKTtcbiAgICAgICAgKiAgICAgIHNhLnJlcGxheSh7cnVuSWQ6ICcxODQyYmI1Yy04M2FkLTRiYTgtYTk1NS1iZDEzY2MyZmRiNGYnLCBzdG9wQmVmb3JlOiAnY2FsY3VsYXRlU2NvcmUnfSk7XG4gICAgICAgICpcbiAgICAgICAgKiAgKipQYXJhbWV0ZXJzKipcbiAgICAgICAgKiBAcGFyYW0ge29iamVjdH0gYHBhcmFtc2AgUGFyYW1ldGVycyBvYmplY3QuXG4gICAgICAgICogQHBhcmFtIHtzdHJpbmd9IGBwYXJhbXMucnVuSWRgIFRoZSBpZCBvZiB0aGUgcnVuIHRvIGJyaW5nIGJhY2sgdG8gbWVtb3J5LlxuICAgICAgICAqIEBwYXJhbSB7c3RyaW5nfSBgcGFyYW1zLnN0b3BCZWZvcmVgIChPcHRpb25hbCkgVGhlIHJ1biBpcyBhZHZhbmNlZCBvbmx5IHVwIHRvIHRoZSBmaXJzdCBvY2N1cnJlbmNlIG9mIHRoaXMgbWV0aG9kLlxuICAgICAgICAqIEBwYXJhbSB7YXJyYXl9IGBwYXJhbXMuZXhjbHVkZWAgKE9wdGlvbmFsKSBBcnJheSBvZiBtZXRob2RzIHRvIGV4Y2x1ZGUgd2hlbiBhZHZhbmNpbmcgdGhlIHJ1bi5cbiAgICAgICAgKiBAcGFyYW0ge29iamVjdH0gYG9wdGlvbnNgIChPcHRpb25hbCkgT3ZlcnJpZGVzIGZvciBjb25maWd1cmF0aW9uIG9wdGlvbnMuXG4gICAgICAgICovXG4gICAgICAgIHJlcGxheTogZnVuY3Rpb24gKHBhcmFtcywgb3B0aW9ucykge1xuICAgICAgICAgICAgdmFyIHJ1bklkID0gcGFyc2VSdW5JZE9yRXJyb3IocGFyYW1zKTtcblxuICAgICAgICAgICAgdmFyIHJlcGxheU9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSxcbiAgICAgICAgICAgICAgICBzZXJ2aWNlT3B0aW9ucyxcbiAgICAgICAgICAgICAgICBvcHRpb25zLFxuICAgICAgICAgICAgICAgIHsgdXJsOiB1cmxDb25maWcuZ2V0QVBJUGF0aChhcGlFbmRwb2ludCkgKyBydW5JZCB9XG4gICAgICAgICAgICApO1xuXG4gICAgICAgICAgICBwYXJhbXMgPSAkLmV4dGVuZCh0cnVlLCB7IGFjdGlvbjogJ3JlcGxheScgfSwgX3BpY2socGFyYW1zLCBbJ3N0b3BCZWZvcmUnLCAnZXhjbHVkZSddKSk7XG5cbiAgICAgICAgICAgIHJldHVybiBodHRwLnBvc3QocGFyYW1zLCByZXBsYXlPcHRpb25zKTtcbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgKiBDbG9uZSBhIGdpdmVuIHJ1biBhbmQgcmV0dXJuIGEgbmV3IHJ1biBpbiB0aGUgc2FtZSBzdGF0ZSBhcyB0aGUgZ2l2ZW4gcnVuLlxuICAgICAgICAqXG4gICAgICAgICogVGhlIG5ldyBydW4gaWQgaXMgbm93IGF2YWlsYWJsZSBbaW4gbWVtb3J5XSguLi8uLi8uLi9ydW5fcGVyc2lzdGVuY2UvI3J1bnMtaW4tbWVtb3J5KS4gVGhlIG5ldyBydW4gaW5jbHVkZXMgYSBjb3B5IG9mIGFsbCBvZiB0aGUgZGF0YSBmcm9tIHRoZSBvcmlnaW5hbCBydW4sIEVYQ0VQVDpcbiAgICAgICAgKlxuICAgICAgICAqICogVGhlIGBzYXZlZGAgZmllbGQgaW4gdGhlIG5ldyBydW4gcmVjb3JkIGlzIG5vdCBjb3BpZWQgZnJvbSB0aGUgb3JpZ2luYWwgcnVuIHJlY29yZC4gSXQgZGVmYXVsdHMgdG8gYGZhbHNlYC5cbiAgICAgICAgKiAqIFRoZSBgaW5pdGlhbGl6ZWRgIGZpZWxkIGluIHRoZSBuZXcgcnVuIHJlY29yZCBpcyBub3QgY29waWVkIGZyb20gdGhlIG9yaWdpbmFsIHJ1biByZWNvcmQuIEl0IGRlZmF1bHRzIHRvIGBmYWxzZWAgYnV0IG1heSBjaGFuZ2UgdG8gYHRydWVgIGFzIHRoZSBuZXcgcnVuIGlzIGFkdmFuY2VkLiBGb3IgZXhhbXBsZSwgaWYgdGhlcmUgaGFzIGJlZW4gYSBjYWxsIHRvIHRoZSBgc3RlcGAgZnVuY3Rpb24gKGZvciBWZW5zaW0gbW9kZWxzKSwgdGhlIGBpbml0aWFsaXplZGAgZmllbGQgaXMgc2V0IHRvIGB0cnVlYC5cbiAgICAgICAgKiAqIFRoZSBgY3JlYXRlZGAgZmllbGQgaW4gdGhlIG5ldyBydW4gcmVjb3JkIGlzIHRoZSBkYXRlIGFuZCB0aW1lIGF0IHdoaWNoIHRoZSBjbG9uZSB3YXMgY3JlYXRlZCAobm90IHRoZSB0aW1lIHRoYXQgdGhlIG9yaWdpbmFsIHJ1biB3YXMgY3JlYXRlZC4pXG4gICAgICAgICpcbiAgICAgICAgKiBUaGUgb3JpZ2luYWwgcnVuIHJlbWFpbnMgb25seSBbaW4gdGhlIGRhdGFiYXNlXSguLi8uLi8uLi9ydW5fcGVyc2lzdGVuY2UvI3J1bnMtaW4tZGIpLlxuICAgICAgICAqXG4gICAgICAgICogICoqRXhhbXBsZSoqXG4gICAgICAgICpcbiAgICAgICAgKiAgICAgIHZhciBzYSA9IG5ldyBGLnNlcnZpY2UuU3RhdGUoKTtcbiAgICAgICAgKiAgICAgIHNhLmNsb25lKHtydW5JZDogJzE4NDJiYjVjLTgzYWQtNGJhOC1hOTU1LWJkMTNjYzJmZGI0ZicsIHN0b3BCZWZvcmU6ICdjYWxjdWxhdGVTY29yZScsIGV4Y2x1ZGU6IFsnaW50ZXJpbUNhbGN1bGF0aW9uJ10gfSk7XG4gICAgICAgICpcbiAgICAgICAgKiAgKipQYXJhbWV0ZXJzKipcbiAgICAgICAgKiBAcGFyYW0ge29iamVjdH0gYHBhcmFtc2AgUGFyYW1ldGVycyBvYmplY3QuXG4gICAgICAgICogQHBhcmFtIHtzdHJpbmd9IGBwYXJhbXMucnVuSWRgIFRoZSBpZCBvZiB0aGUgcnVuIHRvIGNsb25lIGZyb20gbWVtb3J5LlxuICAgICAgICAqIEBwYXJhbSB7c3RyaW5nfSBgcGFyYW1zLnN0b3BCZWZvcmVgIChPcHRpb25hbCkgVGhlIG5ld2x5IGNsb25lZCBydW4gaXMgYWR2YW5jZWQgb25seSB1cCB0byB0aGUgZmlyc3Qgb2NjdXJyZW5jZSBvZiB0aGlzIG1ldGhvZC5cbiAgICAgICAgKiBAcGFyYW0ge2FycmF5fSBgcGFyYW1zLmV4Y2x1ZGVgIChPcHRpb25hbCkgQXJyYXkgb2YgbWV0aG9kcyB0byBleGNsdWRlIHdoZW4gYWR2YW5jaW5nIHRoZSBuZXdseSBjbG9uZWQgcnVuLlxuICAgICAgICAqIEBwYXJhbSB7b2JqZWN0fSBgb3B0aW9uc2AgKE9wdGlvbmFsKSBPdmVycmlkZXMgZm9yIGNvbmZpZ3VyYXRpb24gb3B0aW9ucy5cbiAgICAgICAgKi9cbiAgICAgICAgY2xvbmU6IGZ1bmN0aW9uIChwYXJhbXMsIG9wdGlvbnMpIHtcbiAgICAgICAgICAgIHZhciBydW5JZCA9IHBhcnNlUnVuSWRPckVycm9yKHBhcmFtcyk7XG5cbiAgICAgICAgICAgIHZhciByZXBsYXlPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sXG4gICAgICAgICAgICAgICAgc2VydmljZU9wdGlvbnMsXG4gICAgICAgICAgICAgICAgb3B0aW9ucyxcbiAgICAgICAgICAgICAgICB7IHVybDogdXJsQ29uZmlnLmdldEFQSVBhdGgoYXBpRW5kcG9pbnQpICsgcnVuSWQgfVxuICAgICAgICAgICAgKTtcblxuICAgICAgICAgICAgcGFyYW1zID0gJC5leHRlbmQodHJ1ZSwgeyBhY3Rpb246ICdjbG9uZScgfSwgX3BpY2socGFyYW1zLCBbJ3N0b3BCZWZvcmUnLCAnZXhjbHVkZSddKSk7XG5cbiAgICAgICAgICAgIHJldHVybiBodHRwLnBvc3QocGFyYW1zLCByZXBsYXlPcHRpb25zKTtcbiAgICAgICAgfVxuICAgIH07XG5cbiAgICAkLmV4dGVuZCh0aGlzLCBwdWJsaWNBUEkpO1xufTtcbiIsIid1c2Ugc3RyaWN0JztcblxudmFyIGVwaVZlcnNpb24gPSByZXF1aXJlKCcuLi9hcGktdmVyc2lvbi5qc29uJyk7XG5cbi8vVE9ETzogdXJsdXRpbHMgdG8gZ2V0IGhvc3QsIHNpbmNlIG5vIHdpbmRvdyBvbiBub2RlXG52YXIgZGVmYXVsdHMgPSB7XG4gICAgaG9zdDogd2luZG93LmxvY2F0aW9uLmhvc3QsXG4gICAgcGF0aG5hbWU6IHdpbmRvdy5sb2NhdGlvbi5wYXRobmFtZVxufTtcblxudmFyIFVybENvbmZpZ1NlcnZpY2UgPSBmdW5jdGlvbiAoY29uZmlnKSB7XG4gICAgdmFyIG9wdGlvbnMgPSAkLmV4dGVuZCh7fSwgZGVmYXVsdHMsIGNvbmZpZyk7XG4gICAgZnVuY3Rpb24gaXNMb2NhbGhvc3QoKSB7XG4gICAgICAgIHZhciBob3N0ID0gb3B0aW9ucy5ob3N0O1xuICAgICAgICB2YXIgcGF0aCA9IG9wdGlvbnMucGF0aG5hbWU7XG4gICAgICAgIC8vIFNvcnQgb2YgaGFyZGNvZGUgdGhlIGZhY3QgdGhhdCBlcGljZW50ZXIgYXBwbGljYXRpb24gc3BhY2UgaXMgcHJlZml4ZWQgYnkgL2FwcC9cbiAgICAgICAgcmV0dXJuICghaG9zdCB8fCBwYXRoLmluZGV4T2YoJy9hcHAvJykgIT09IDApO1xuICAgIH1cblxuICAgIHZhciBBUElfUFJPVE9DT0wgPSAnaHR0cHMnO1xuICAgIHZhciBIT1NUX0FQSV9NQVBQSU5HID0ge1xuICAgICAgICAnZm9yaW8uY29tJzogJ2FwaS5mb3Jpby5jb20nLFxuICAgICAgICAnZm9yaW9kZXYuY29tJzogJ2FwaS5lcGljZW50ZXIuZm9yaW9kZXYuY29tJ1xuICAgIH07XG5cbiAgICB2YXIgcHVibGljRXhwb3J0cyA9IHtcbiAgICAgICAgcHJvdG9jb2w6IEFQSV9QUk9UT0NPTCxcblxuICAgICAgICBhcGk6ICcnLFxuXG4gICAgICAgIGhvc3Q6IChmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICB2YXIgaG9zdCA9IG9wdGlvbnMuaG9zdDtcbiAgICAgICAgICAgIGlmIChpc0xvY2FsaG9zdCgpKSB7XG4gICAgICAgICAgICAgICAgaG9zdCA9ICdmb3Jpby5jb20nO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgcmV0dXJuIChIT1NUX0FQSV9NQVBQSU5HW2hvc3RdKSA/IEhPU1RfQVBJX01BUFBJTkdbaG9zdF0gOiAnYXBpLicgKyBob3N0O1xuICAgICAgICB9KCkpLFxuXG4gICAgICAgIGFwcFBhdGg6IChmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICB2YXIgcGF0aCA9IG9wdGlvbnMucGF0aG5hbWUuc3BsaXQoJ1xcLycpO1xuXG4gICAgICAgICAgICByZXR1cm4gcGF0aCAmJiBwYXRoWzFdIHx8ICcnO1xuICAgICAgICB9KCkpLFxuXG4gICAgICAgIGFjY291bnRQYXRoOiAoZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgdmFyIGFjY250ID0gJyc7XG4gICAgICAgICAgICB2YXIgcGF0aCA9IG9wdGlvbnMucGF0aG5hbWUuc3BsaXQoJ1xcLycpO1xuICAgICAgICAgICAgaWYgKHBhdGggJiYgcGF0aFsxXSA9PT0gJ2FwcCcpIHtcbiAgICAgICAgICAgICAgICBhY2NudCA9IHBhdGhbMl07XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICByZXR1cm4gYWNjbnQ7XG4gICAgICAgIH0oKSksXG5cbiAgICAgICAgcHJvamVjdFBhdGg6IChmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICB2YXIgcHJqID0gJyc7XG4gICAgICAgICAgICB2YXIgcGF0aCA9IG9wdGlvbnMucGF0aG5hbWUuc3BsaXQoJ1xcLycpO1xuICAgICAgICAgICAgaWYgKHBhdGggJiYgcGF0aFsxXSA9PT0gJ2FwcCcpIHtcbiAgICAgICAgICAgICAgICBwcmogPSBwYXRoWzNdO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgcmV0dXJuIHByajtcbiAgICAgICAgfSgpKSxcblxuICAgICAgICB2ZXJzaW9uUGF0aDogKGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIHZhciB2ZXJzaW9uID0gZXBpVmVyc2lvbi52ZXJzaW9uID8gZXBpVmVyc2lvbi52ZXJzaW9uICsgJy8nIDogJyc7XG4gICAgICAgICAgICByZXR1cm4gdmVyc2lvbjtcbiAgICAgICAgfSgpKSxcblxuICAgICAgICBpc0xvY2FsaG9zdDogaXNMb2NhbGhvc3QsXG5cbiAgICAgICAgZ2V0QVBJUGF0aDogZnVuY3Rpb24gKGFwaSkge1xuICAgICAgICAgICAgdmFyIFBST0pFQ1RfQVBJUyA9IFsncnVuJywgJ2RhdGEnLCAnZmlsZSddO1xuXG4gICAgICAgICAgICB2YXIgYXBpUGF0aCA9IHRoaXMucHJvdG9jb2wgKyAnOi8vJyArIHRoaXMuaG9zdCArICcvJyArIHRoaXMudmVyc2lvblBhdGggKyBhcGkgKyAnLyc7XG5cbiAgICAgICAgICAgIGlmICgkLmluQXJyYXkoYXBpLCBQUk9KRUNUX0FQSVMpICE9PSAtMSkge1xuICAgICAgICAgICAgICAgIGFwaVBhdGggKz0gdGhpcy5hY2NvdW50UGF0aCArICcvJyArIHRoaXMucHJvamVjdFBhdGggICsgJy8nO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgcmV0dXJuIGFwaVBhdGg7XG4gICAgICAgIH1cbiAgICB9O1xuXG4gICAgLy8gVGhpcyBkYXRhIGlzIHNldCBieSBhbiBleHRlcm5hbCBzY3JpcHQgKHN0YXJ0LWxvYWQuanMpXG4gICAgdmFyIGVudkNvbmYgPSB7XG4gICAgICAgIHByb3RvY29sOiBVcmxDb25maWdTZXJ2aWNlLnByb3RvY29sLFxuICAgICAgICBob3N0OiBVcmxDb25maWdTZXJ2aWNlLmhvc3RcbiAgICB9O1xuXG4gICAgJC5leHRlbmQocHVibGljRXhwb3J0cywgZW52Q29uZiwgY29uZmlnKTtcbiAgICByZXR1cm4gcHVibGljRXhwb3J0cztcbn07XG5cbm1vZHVsZS5leHBvcnRzID0gVXJsQ29uZmlnU2VydmljZTtcbiIsIid1c2Ugc3RyaWN0Jztcbi8qKlxuKiAjIyBVc2VyIEFQSSBBZGFwdGVyXG4qXG4qIFRoZSBVc2VyIEFQSSBBZGFwdGVyIGFsbG93cyB5b3UgdG8gcmV0cmlldmUgZGV0YWlscyBhYm91dCBlbmQgdXNlcnMgaW4geW91ciB0ZWFtIChhY2NvdW50KS4gSXQgaXMgYmFzZWQgb24gdGhlIHF1ZXJ5aW5nIGNhcGFiaWxpdGllcyBvZiB0aGUgdW5kZXJseWluZyBSRVNUZnVsIFtVc2VyIEFQSV0oLi4vLi4vLi4vcmVzdF9hcGlzL3VzZXJfbWFuYWdlbWVudC91c2VyLykuXG4qXG4qIFRvIHVzZSB0aGUgVXNlciBBUEkgQWRhcHRlciwgaW5zdGFudGlhdGUgaXQgYW5kIHRoZW4gY2FsbCBpdHMgbWV0aG9kcy5cbipcbiogICAgICAgdmFyIHVhID0gbmV3IEYuc2VydmljZS5Vc2VyKHtcbiogICAgICAgICAgIGFjY291bnQ6ICdhY21lLXNpbXVsYXRpb25zJyxcbiogICAgICAgICAgIHRva2VuOiAndXNlci1vci1wcm9qZWN0LWFjY2Vzcy10b2tlbidcbiogICAgICAgfSk7XG4qICAgICAgIHVhLmdldEJ5SWQoJzQyODM2ZDRiLTViNjEtNGZlNC04MGViLTMxMzZlOTU2ZWU1YycpO1xuKiAgICAgICB1YS5nZXQoeyB1c2VyTmFtZTogJ2pzbWl0aCcgfSk7XG4qICAgICAgIHVhLmdldCh7IGlkOiBbJzQyODM2ZDRiLTViNjEtNGZlNC04MGViLTMxMzZlOTU2ZWU1YycsXG4qICAgICAgICAgICAgICAgICAgICc0ZWE3NTYzMS00YzhkLTQ4NzItOWQ4MC1iNDYwMDE0NjQ3OGUnXSB9KTtcbipcbiogVGhlIGNvbnN0cnVjdG9yIHRha2VzIGFuIG9wdGlvbmFsIGBvcHRpb25zYCBwYXJhbWV0ZXIgaW4gd2hpY2ggeW91IGNhbiBzcGVjaWZ5IHRoZSBgYWNjb3VudGAgYW5kIGB0b2tlbmAgaWYgdGhleSBhcmUgbm90IGFscmVhZHkgYXZhaWxhYmxlIGluIHRoZSBjdXJyZW50IGNvbnRleHQuXG4qL1xuXG52YXIgQ29uZmlnU2VydmljZSA9IHJlcXVpcmUoJy4vY29uZmlndXJhdGlvbi1zZXJ2aWNlJyk7XG52YXIgVHJhbnNwb3J0RmFjdG9yeSA9IHJlcXVpcmUoJy4uL3RyYW5zcG9ydC9odHRwLXRyYW5zcG9ydC1mYWN0b3J5Jyk7XG52YXIgU2Vzc2lvbk1hbmFnZXIgPSByZXF1aXJlKCcuLi9zdG9yZS9zZXNzaW9uLW1hbmFnZXInKTtcbnZhciBxdXRpbCA9IHJlcXVpcmUoJy4uL3V0aWwvcXVlcnktdXRpbCcpO1xuXG5tb2R1bGUuZXhwb3J0cyA9IGZ1bmN0aW9uIChjb25maWcpIHtcbiAgICB2YXIgZGVmYXVsdHMgPSB7XG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIFRoZSBhY2NvdW50IGlkLiBJbiB0aGUgRXBpY2VudGVyIFVJLCB0aGlzIGlzIHRoZSAqKlRlYW0gSUQqKiAoZm9yIHRlYW0gcHJvamVjdHMpIG9yICoqVXNlciBJRCoqIChmb3IgcGVyc29uYWwgcHJvamVjdHMpLiBEZWZhdWx0cyB0byBlbXB0eSBzdHJpbmcuXG4gICAgICAgICAqIEB0eXBlIHtTdHJpbmd9XG4gICAgICAgICAqL1xuICAgICAgICBhY2NvdW50OiB1bmRlZmluZWQsXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIFRoZSBhY2Nlc3MgdG9rZW4gdG8gdXNlIHdoZW4gc2VhcmNoaW5nIGZvciBlbmQgdXNlcnMuIChTZWUgW21vcmUgYmFja2dyb3VuZCBvbiBhY2Nlc3MgdG9rZW5zXSguLi8uLi8uLi9wcm9qZWN0X2FjY2Vzcy8pKS5cbiAgICAgICAgICogQHR5cGUge1N0cmluZ31cbiAgICAgICAgICovXG4gICAgICAgIHRva2VuOiB1bmRlZmluZWQsXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIE9wdGlvbnMgdG8gcGFzcyBvbiB0byB0aGUgdW5kZXJseWluZyB0cmFuc3BvcnQgbGF5ZXIuIEFsbCBqcXVlcnkuYWpheCBvcHRpb25zIGF0IGh0dHA6Ly9hcGkuanF1ZXJ5LmNvbS9qUXVlcnkuYWpheC8gYXJlIGF2YWlsYWJsZS4gRGVmYXVsdHMgdG8gZW1wdHkgb2JqZWN0LlxuICAgICAgICAgKiBAdHlwZSB7T2JqZWN0fVxuICAgICAgICAgKi9cbiAgICAgICAgdHJhbnNwb3J0OiB7fVxuICAgIH07XG5cbiAgICB0aGlzLnNlc3Npb25NYW5hZ2VyID0gbmV3IFNlc3Npb25NYW5hZ2VyKCk7XG4gICAgdmFyIHNlcnZpY2VPcHRpb25zID0gdGhpcy5zZXNzaW9uTWFuYWdlci5nZXRNZXJnZWRPcHRpb25zKGRlZmF1bHRzLCBjb25maWcpO1xuICAgIHZhciB1cmxDb25maWcgPSBuZXcgQ29uZmlnU2VydmljZShzZXJ2aWNlT3B0aW9ucykuZ2V0KCdzZXJ2ZXInKTtcbiAgICB2YXIgdHJhbnNwb3J0T3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LCBzZXJ2aWNlT3B0aW9ucy50cmFuc3BvcnQsIHtcbiAgICAgICAgdXJsOiB1cmxDb25maWcuZ2V0QVBJUGF0aCgndXNlcicpXG4gICAgfSk7XG5cbiAgICBpZiAoc2VydmljZU9wdGlvbnMudG9rZW4pIHtcbiAgICAgICAgdHJhbnNwb3J0T3B0aW9ucy5oZWFkZXJzID0ge1xuICAgICAgICAgICAgJ0F1dGhvcml6YXRpb24nOiAnQmVhcmVyICcgKyBzZXJ2aWNlT3B0aW9ucy50b2tlblxuICAgICAgICB9O1xuICAgIH1cblxuICAgIHZhciBodHRwID0gbmV3IFRyYW5zcG9ydEZhY3RvcnkodHJhbnNwb3J0T3B0aW9ucyk7XG5cbiAgICB2YXIgcHVibGljQVBJID0ge1xuXG4gICAgICAgIC8qKlxuICAgICAgICAqIFJldHJpZXZlIGRldGFpbHMgYWJvdXQgcGFydGljdWxhciBlbmQgdXNlcnMgaW4geW91ciB0ZWFtLCBiYXNlZCBvbiB1c2VyIG5hbWUgb3IgdXNlciBpZC5cbiAgICAgICAgKlxuICAgICAgICAqICoqRXhhbXBsZSoqXG4gICAgICAgICpcbiAgICAgICAgKiAgICAgICB2YXIgdWEgPSBuZXcgRi5zZXJ2aWNlLlVzZXIoe1xuICAgICAgICAqICAgICAgICAgICBhY2NvdW50OiAnYWNtZS1zaW11bGF0aW9ucycsXG4gICAgICAgICogICAgICAgICAgIHRva2VuOiAndXNlci1vci1wcm9qZWN0LWFjY2Vzcy10b2tlbidcbiAgICAgICAgKiAgICAgICB9KTtcbiAgICAgICAgKiAgICAgICB1YS5nZXQoeyB1c2VyTmFtZTogJ2pzbWl0aCcgfSk7XG4gICAgICAgICogICAgICAgdWEuZ2V0KHsgaWQ6IFsnNDI4MzZkNGItNWI2MS00ZmU0LTgwZWItMzEzNmU5NTZlZTVjJyxcbiAgICAgICAgKiAgICAgICAgICAgICAgICAgICAnNGVhNzU2MzEtNGM4ZC00ODcyLTlkODAtYjQ2MDAxNDY0NzhlJ10gfSk7XG4gICAgICAgICpcbiAgICAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAqIEBwYXJhbSB7b2JqZWN0fSBgZmlsdGVyYCBPYmplY3Qgd2l0aCBmaWVsZCBgdXNlck5hbWVgIGFuZCB2YWx1ZSBvZiB0aGUgdXNlcm5hbWUuIEFsdGVybmF0aXZlbHksIG9iamVjdCB3aXRoIGZpZWxkIGBpZGAgYW5kIHZhbHVlIG9mIGFuIGFycmF5IG9mIHVzZXIgaWRzLlxuICAgICAgICAqIEBwYXJhbSB7b2JqZWN0fSBgb3B0aW9uc2AgKE9wdGlvbmFsKSBPdmVycmlkZXMgZm9yIGNvbmZpZ3VyYXRpb24gb3B0aW9ucy5cbiAgICAgICAgKi9cblxuICAgICAgICBnZXQ6IGZ1bmN0aW9uIChmaWx0ZXIsIG9wdGlvbnMpIHtcbiAgICAgICAgICAgIG9wdGlvbnMgPSBvcHRpb25zIHx8IHt9O1xuICAgICAgICAgICAgZmlsdGVyID0gZmlsdGVyIHx8IHt9O1xuXG4gICAgICAgICAgICB2YXIgZ2V0T3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LFxuICAgICAgICAgICAgICAgIHNlcnZpY2VPcHRpb25zLFxuICAgICAgICAgICAgICAgIG9wdGlvbnNcbiAgICAgICAgICAgICk7XG5cbiAgICAgICAgICAgIHZhciB0b1FGaWx0ZXIgPSBmdW5jdGlvbiAoZmlsdGVyKSB7XG4gICAgICAgICAgICAgICAgdmFyIHJlcyA9IHt9O1xuXG4gICAgICAgICAgICAgICAgLy8gQVBJIG9ubHkgc3VwcG9ydHMgZmlsdGVyaW5nIGJ5IHVzZXJuYW1lIGZvciBub3dcbiAgICAgICAgICAgICAgICBpZiAoZmlsdGVyLnVzZXJOYW1lKSB7XG4gICAgICAgICAgICAgICAgICAgIHJlcy5xID0gZmlsdGVyLnVzZXJOYW1lO1xuICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgIHJldHVybiByZXM7XG4gICAgICAgICAgICB9O1xuXG4gICAgICAgICAgICB2YXIgdG9JZEZpbHRlcnMgPSBmdW5jdGlvbiAoaWQpIHtcbiAgICAgICAgICAgICAgICBpZiAoIWlkKSB7XG4gICAgICAgICAgICAgICAgICAgIHJldHVybiAnJztcbiAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICBpZCA9ICQuaXNBcnJheShpZCkgPyBpZCA6IFtpZF07XG4gICAgICAgICAgICAgICAgcmV0dXJuICdpZD0nICsgaWQuam9pbignJmlkPScpO1xuICAgICAgICAgICAgfTtcblxuICAgICAgICAgICAgdmFyIGdldEZpbHRlcnMgPSBbXG4gICAgICAgICAgICAgICAgJ2FjY291bnQ9JyArIGdldE9wdGlvbnMuYWNjb3VudCxcbiAgICAgICAgICAgICAgICB0b0lkRmlsdGVycyhmaWx0ZXIuaWQpLFxuICAgICAgICAgICAgICAgIHF1dGlsLnRvUXVlcnlGb3JtYXQodG9RRmlsdGVyKGZpbHRlcikpXG4gICAgICAgICAgICBdLmpvaW4oJyYnKTtcblxuICAgICAgICAgICAgLy8gc3BlY2lhbCBjYXNlIGZvciBxdWVyaWVzIHdpdGggbGFyZ2UgbnVtYmVyIG9mIGlkc1xuICAgICAgICAgICAgLy8gbWFrZSBpdCBhcyBhIHBvc3Qgd2l0aCBHRVQgc2VtYW50aWNzXG4gICAgICAgICAgICB2YXIgdGhyZXNob2xkID0gMzA7XG4gICAgICAgICAgICBpZiAoZmlsdGVyLmlkICYmICQuaXNBcnJheShmaWx0ZXIuaWQpICYmIGZpbHRlci5pZC5sZW5ndGggPj0gdGhyZXNob2xkKSB7XG4gICAgICAgICAgICAgICAgZ2V0T3B0aW9ucy51cmwgPSB1cmxDb25maWcuZ2V0QVBJUGF0aCgndXNlcicpICsgJz9fbWV0aG9kPUdFVCc7XG4gICAgICAgICAgICAgICAgcmV0dXJuIGh0dHAucG9zdCh7IGlkOiBmaWx0ZXIuaWQgfSwgZ2V0T3B0aW9ucyk7XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgIHJldHVybiBodHRwLmdldChnZXRGaWx0ZXJzLCBnZXRPcHRpb25zKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgKiBSZXRyaWV2ZSBkZXRhaWxzIGFib3V0IGEgc2luZ2xlIGVuZCB1c2VyIGluIHlvdXIgdGVhbSwgYmFzZWQgb24gdXNlciBpZC5cbiAgICAgICAgKlxuICAgICAgICAqICoqRXhhbXBsZSoqXG4gICAgICAgICpcbiAgICAgICAgKiAgICAgICB2YXIgdWEgPSBuZXcgRi5zZXJ2aWNlLlVzZXIoe1xuICAgICAgICAqICAgICAgICAgICBhY2NvdW50OiAnYWNtZS1zaW11bGF0aW9ucycsXG4gICAgICAgICogICAgICAgICAgIHRva2VuOiAndXNlci1vci1wcm9qZWN0LWFjY2Vzcy10b2tlbidcbiAgICAgICAgKiAgICAgICB9KTtcbiAgICAgICAgKiAgICAgICB1YS5nZXRCeUlkKCc0MjgzNmQ0Yi01YjYxLTRmZTQtODBlYi0zMTM2ZTk1NmVlNWMnKTtcbiAgICAgICAgKlxuICAgICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICAgICogQHBhcmFtIHtzdHJpbmd9IGB1c2VySWRgIFRoZSB1c2VyIGlkIGZvciB0aGUgZW5kIHVzZXIgaW4geW91ciB0ZWFtLlxuICAgICAgICAqIEBwYXJhbSB7b2JqZWN0fSBgb3B0aW9uc2AgKE9wdGlvbmFsKSBPdmVycmlkZXMgZm9yIGNvbmZpZ3VyYXRpb24gb3B0aW9ucy5cbiAgICAgICAgKi9cblxuICAgICAgICBnZXRCeUlkOiBmdW5jdGlvbiAodXNlcklkLCBvcHRpb25zKSB7XG4gICAgICAgICAgICByZXR1cm4gcHVibGljQVBJLmdldCh7IGlkOiB1c2VySWQgfSwgb3B0aW9ucyk7XG4gICAgICAgIH1cbiAgICB9O1xuXG4gICAgJC5leHRlbmQodGhpcywgcHVibGljQVBJKTtcbn07XG5cblxuXG5cbiIsIi8qKlxuICpcbiAqICMjIFZhcmlhYmxlcyBBUEkgU2VydmljZVxuICpcbiAqIFVzZWQgaW4gY29uanVuY3Rpb24gd2l0aCB0aGUgW1J1biBBUEkgU2VydmljZV0oLi4vcnVuLWFwaS1zZXJ2aWNlLykgdG8gcmVhZCwgd3JpdGUsIGFuZCBzZWFyY2ggZm9yIHNwZWNpZmljIG1vZGVsIHZhcmlhYmxlcy5cbiAqXG4gKiAgICAgdmFyIHJtID0gbmV3IEYubWFuYWdlci5SdW5NYW5hZ2VyKHtcbiAqICAgICAgICAgICBydW46IHtcbiAqICAgICAgICAgICAgICAgYWNjb3VudDogJ2FjbWUtc2ltdWxhdGlvbnMnLFxuICogICAgICAgICAgICAgICBwcm9qZWN0OiAnc3VwcGx5LWNoYWluLWdhbWUnLFxuICogICAgICAgICAgICAgICBtb2RlbDogJ3N1cHBseS1jaGFpbi1tb2RlbC5qbCdcbiAqICAgICAgICAgICB9XG4gKiAgICAgIH0pO1xuICogICAgIHJtLmdldFJ1bigpXG4gKiAgICAgICAudGhlbihmdW5jdGlvbigpIHtcbiAqICAgICAgICAgIHZhciB2cyA9IHJtLnJ1bi52YXJpYWJsZXMoKTtcbiAqICAgICAgICAgIHZzLnNhdmUoe3NhbXBsZV9pbnQ6IDR9KTtcbiAqICAgICAgICB9KTtcbiAqXG4gKi9cblxuXG4gJ3VzZSBzdHJpY3QnO1xuXG4gdmFyIFRyYW5zcG9ydEZhY3RvcnkgPSByZXF1aXJlKCcuLi90cmFuc3BvcnQvaHR0cC10cmFuc3BvcnQtZmFjdG9yeScpO1xuIHZhciBydXRpbCA9IHJlcXVpcmUoJy4uL3V0aWwvcnVuLXV0aWwnKTtcblxubW9kdWxlLmV4cG9ydHMgPSBmdW5jdGlvbiAoY29uZmlnKSB7XG4gICAgdmFyIGRlZmF1bHRzID0ge1xuICAgICAgICAvKipcbiAgICAgICAgICogVGhlIHJ1bnMgb2JqZWN0IHRvIHdoaWNoIHRoZSB2YXJpYWJsZSBmaWx0ZXJzIGFwcGx5LiBEZWZhdWx0cyB0byBudWxsLlxuICAgICAgICAgKiBAdHlwZSB7cnVuU2VydmljZX1cbiAgICAgICAgICovXG4gICAgICAgIHJ1blNlcnZpY2U6IG51bGxcbiAgICB9O1xuICAgIHZhciBzZXJ2aWNlT3B0aW9ucyA9ICQuZXh0ZW5kKHt9LCBkZWZhdWx0cywgY29uZmlnKTtcblxuICAgIHZhciBnZXRVUkwgPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHJldHVybiBzZXJ2aWNlT3B0aW9ucy5ydW5TZXJ2aWNlLnVybENvbmZpZy5nZXRGaWx0ZXJVUkwoKSArICd2YXJpYWJsZXMvJztcbiAgICB9O1xuXG4gICAgdmFyIGFkZEF1dG9SZXN0b3JlSGVhZGVyID0gZnVuY3Rpb24gKG9wdGlvbnMpIHtcbiAgICAgICAgcmV0dXJuIHNlcnZpY2VPcHRpb25zLnJ1blNlcnZpY2UudXJsQ29uZmlnLmFkZEF1dG9SZXN0b3JlSGVhZGVyKG9wdGlvbnMpO1xuICAgIH07XG5cbiAgICB2YXIgaHR0cE9wdGlvbnMgPSB7XG4gICAgICAgIHVybDogZ2V0VVJMXG4gICAgfTtcbiAgICBpZiAoc2VydmljZU9wdGlvbnMudG9rZW4pIHtcbiAgICAgICAgaHR0cE9wdGlvbnMuaGVhZGVycyA9IHtcbiAgICAgICAgICAgICdBdXRob3JpemF0aW9uJzogJ0JlYXJlciAnICsgc2VydmljZU9wdGlvbnMudG9rZW5cbiAgICAgICAgfTtcbiAgICB9XG4gICAgdmFyIGh0dHAgPSBuZXcgVHJhbnNwb3J0RmFjdG9yeShodHRwT3B0aW9ucyk7XG4gICAgaHR0cC5zcGxpdEdldCA9IHJ1dGlsLnNwbGl0R2V0RmFjdG9yeShodHRwT3B0aW9ucyk7XG5cbiAgICB2YXIgcHVibGljQVBJID0ge1xuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBHZXQgdmFsdWVzIGZvciBhIHZhcmlhYmxlLlxuICAgICAgICAgKlxuICAgICAgICAgKiAqKkV4YW1wbGUqKlxuICAgICAgICAgKlxuICAgICAgICAgKiAgICAgIHZzLmxvYWQoJ3NhbXBsZV9pbnQnKVxuICAgICAgICAgKiAgICAgICAgICAudGhlbihmdW5jdGlvbih2YWwpe1xuICAgICAgICAgKiAgICAgICAgICAgICAgLy8gdmFsIGNvbnRhaW5zIHRoZSB2YWx1ZSBvZiBzYW1wbGVfaW50XG4gICAgICAgICAqICAgICAgICAgIH0pO1xuICAgICAgICAgKlxuICAgICAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAgKiBAcGFyYW0ge1N0cmluZ30gYHZhcmlhYmxlYCBOYW1lIG9mIHZhcmlhYmxlIHRvIGxvYWQuXG4gICAgICAgICAqIEBwYXJhbSB7T2JqZWN0fSBgb3V0cHV0TW9kaWZpZXJgIChPcHRpb25hbCkgQXZhaWxhYmxlIGZpZWxkcyBpbmNsdWRlOiBgc3RhcnRyZWNvcmRgLCBgZW5kcmVjb3JkYCwgYHNvcnRgLCBhbmQgYGRpcmVjdGlvbmAgKGBhc2NgIG9yIGBkZXNjYCkuXG4gICAgICAgICAqIEBwYXJhbSB7T2JqZWN0fSBgb3B0aW9uc2AgKE9wdGlvbmFsKSBPdmVycmlkZXMgZm9yIGNvbmZpZ3VyYXRpb24gb3B0aW9ucy5cbiAgICAgICAgICovXG4gICAgICAgIGxvYWQ6IGZ1bmN0aW9uICh2YXJpYWJsZSwgb3V0cHV0TW9kaWZpZXIsIG9wdGlvbnMpIHtcbiAgICAgICAgICAgIHZhciBodHRwT3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LCBzZXJ2aWNlT3B0aW9ucywgb3B0aW9ucyk7XG4gICAgICAgICAgICBodHRwT3B0aW9ucyA9IGFkZEF1dG9SZXN0b3JlSGVhZGVyKGh0dHBPcHRpb25zKTtcbiAgICAgICAgICAgIHJldHVybiBodHRwLmdldChvdXRwdXRNb2RpZmllciwgJC5leHRlbmQoe30sIGh0dHBPcHRpb25zLCB7XG4gICAgICAgICAgICAgICAgdXJsOiBnZXRVUkwoKSArIHZhcmlhYmxlICsgJy8nXG4gICAgICAgICAgICB9KSk7XG4gICAgICAgIH0sXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIFJldHVybnMgcGFydGljdWxhciB2YXJpYWJsZXMsIGJhc2VkIG9uIGNvbmRpdGlvbnMgc3BlY2lmaWVkIGluIHRoZSBgcXVlcnlgIG9iamVjdC5cbiAgICAgICAgICpcbiAgICAgICAgICogKipFeGFtcGxlKipcbiAgICAgICAgICpcbiAgICAgICAgICogICAgICB2cy5xdWVyeShbJ3ByaWNlJywgJ3NhbGVzJ10pXG4gICAgICAgICAqICAgICAgICAgIC50aGVuKGZ1bmN0aW9uKHZhbCkge1xuICAgICAgICAgKiAgICAgICAgICAgICAgLy8gdmFsIGlzIGFuIG9iamVjdCB3aXRoIHRoZSB2YWx1ZXMgb2YgdGhlIHJlcXVlc3RlZCB2YXJpYWJsZXM6IHZhbC5wcmljZSwgdmFsLnNhbGVzXG4gICAgICAgICAqICAgICAgICAgIH0pO1xuICAgICAgICAgKlxuICAgICAgICAgKiAgICAgIHZzLnF1ZXJ5KHsgaW5jbHVkZTpbJ3ByaWNlJywgJ3NhbGVzJ10gfSk7XG4gICAgICAgICAqXG4gICAgICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICAgICAqIEBwYXJhbSB7T2JqZWN0fEFycmF5fSBgcXVlcnlgIFRoZSBuYW1lcyBvZiB0aGUgdmFyaWFibGVzIHJlcXVlc3RlZC5cbiAgICAgICAgICogQHBhcmFtIHtPYmplY3R9IGBvdXRwdXRNb2RpZmllcmAgKE9wdGlvbmFsKSBBdmFpbGFibGUgZmllbGRzIGluY2x1ZGU6IGBzdGFydHJlY29yZGAsIGBlbmRyZWNvcmRgLCBgc29ydGAsIGFuZCBgZGlyZWN0aW9uYCAoYGFzY2Agb3IgYGRlc2NgKS5cbiAgICAgICAgICogQHBhcmFtIHtPYmplY3R9IGBvcHRpb25zYCAoT3B0aW9uYWwpIE92ZXJyaWRlcyBmb3IgY29uZmlndXJhdGlvbiBvcHRpb25zLlxuICAgICAgICAgKlxuICAgICAgICAgKi9cbiAgICAgICAgcXVlcnk6IGZ1bmN0aW9uIChxdWVyeSwgb3V0cHV0TW9kaWZpZXIsIG9wdGlvbnMpIHtcbiAgICAgICAgICAgIC8vUXVlcnkgYW5kIG91dHB1dE1vZGlmaWVyIGFyZSBib3RoIHF1ZXJ5c3RyaW5ncyBpbiB0aGUgdXJsOyBvbmx5IGNhbGxpbmcgdGhlbSBvdXQgc2VwYXJhdGVseSBoZXJlIHRvIGJlIGNvbnNpc3RlbnQgd2l0aCB0aGUgb3RoZXIgY2FsbHNcbiAgICAgICAgICAgIHZhciBodHRwT3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LCBzZXJ2aWNlT3B0aW9ucywgb3B0aW9ucyk7XG4gICAgICAgICAgICBodHRwT3B0aW9ucyA9IGFkZEF1dG9SZXN0b3JlSGVhZGVyKGh0dHBPcHRpb25zKTtcblxuICAgICAgICAgICAgaWYgKCQuaXNBcnJheShxdWVyeSkpIHtcbiAgICAgICAgICAgICAgICBxdWVyeSA9IHsgaW5jbHVkZTogcXVlcnkgfTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgICQuZXh0ZW5kKHF1ZXJ5LCBvdXRwdXRNb2RpZmllcik7XG4gICAgICAgICAgICByZXR1cm4gaHR0cC5zcGxpdEdldChxdWVyeSwgaHR0cE9wdGlvbnMpO1xuICAgICAgICB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBTYXZlIHZhbHVlcyB0byBtb2RlbCB2YXJpYWJsZXMuIE92ZXJ3cml0ZXMgZXhpc3RpbmcgdmFsdWVzLiBOb3RlIHRoYXQgeW91IGNhbiBvbmx5IHVwZGF0ZSBtb2RlbCB2YXJpYWJsZXMgaWYgdGhlIHJ1biBpcyBbaW4gbWVtb3J5XSguLi8uLi8uLi9ydW5fcGVyc2lzdGVuY2UvI3J1bnMtaW4tbWVtb3J5KS4gKEFuIGFsdGVybmF0ZSB3YXkgdG8gdXBkYXRlIG1vZGVsIHZhcmlhYmxlcyBpcyB0byBjYWxsIGEgbWV0aG9kIGZyb20gdGhlIG1vZGVsIGFuZCBtYWtlIHN1cmUgdGhhdCB0aGUgbWV0aG9kIHBlcnNpc3RzIHRoZSB2YXJpYWJsZXMuIFNlZSBgZG9gLCBgc2VyaWFsYCwgYW5kIGBwYXJhbGxlbGAgaW4gdGhlIFtSdW4gQVBJIFNlcnZpY2VdKC4uL3J1bi1hcGktc2VydmljZS8pIGZvciBjYWxsaW5nIG1ldGhvZHMgZnJvbSB0aGUgbW9kZWwuKVxuICAgICAgICAgKlxuICAgICAgICAgKiAqKkV4YW1wbGUqKlxuICAgICAgICAgKlxuICAgICAgICAgKiAgICAgIHZzLnNhdmUoJ3ByaWNlJywgNCk7XG4gICAgICAgICAqICAgICAgdnMuc2F2ZSh7IHByaWNlOiA0LCBxdWFudGl0eTogNSwgcHJvZHVjdHM6IFsyLDMsNF0gfSk7XG4gICAgICAgICAqXG4gICAgICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICAgICAqIEBwYXJhbSB7T2JqZWN0fFN0cmluZ30gYHZhcmlhYmxlYCBBbiBvYmplY3QgY29tcG9zZWQgb2YgdGhlIG1vZGVsIHZhcmlhYmxlcyBhbmQgdGhlIHZhbHVlcyB0byBzYXZlLiBBbHRlcm5hdGl2ZWx5LCBhIHN0cmluZyB3aXRoIHRoZSBuYW1lIG9mIHRoZSB2YXJpYWJsZS5cbiAgICAgICAgICogQHBhcmFtIHtPYmplY3R9IGB2YWxgIChPcHRpb25hbCkgSWYgcGFzc2luZyBhIHN0cmluZyBmb3IgYHZhcmlhYmxlYCwgdXNlIHRoaXMgYXJndW1lbnQgZm9yIHRoZSB2YWx1ZSB0byBzYXZlLlxuICAgICAgICAgKiBAcGFyYW0ge09iamVjdH0gYG9wdGlvbnNgIChPcHRpb25hbCkgT3ZlcnJpZGVzIGZvciBjb25maWd1cmF0aW9uIG9wdGlvbnMuXG4gICAgICAgICAqL1xuICAgICAgICBzYXZlOiBmdW5jdGlvbiAodmFyaWFibGUsIHZhbCwgb3B0aW9ucykge1xuICAgICAgICAgICAgdmFyIGF0dHJzO1xuICAgICAgICAgICAgaWYgKHR5cGVvZiB2YXJpYWJsZSA9PT0gJ29iamVjdCcpIHtcbiAgICAgICAgICAgICAgICBhdHRycyA9IHZhcmlhYmxlO1xuICAgICAgICAgICAgICAgIG9wdGlvbnMgPSB2YWw7XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgIChhdHRycyA9IHt9KVt2YXJpYWJsZV0gPSB2YWw7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICB2YXIgaHR0cE9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSwgc2VydmljZU9wdGlvbnMsIG9wdGlvbnMpO1xuXG4gICAgICAgICAgICByZXR1cm4gaHR0cC5wYXRjaC5jYWxsKHRoaXMsIGF0dHJzLCBodHRwT3B0aW9ucyk7XG4gICAgICAgIH1cblxuICAgICAgICAvLyBOb3QgQXZhaWxhYmxlIHVudGlsIHVuZGVybHlpbmcgQVBJIHN1cHBvcnRzIFBVVC4gT3RoZXJ3aXNlIHNhdmUgd291bGQgYmUgUFVUIGFuZCBtZXJnZSB3b3VsZCBiZSBQQVRDSFxuICAgICAgICAvLyAqXG4gICAgICAgIC8vICAqIFNhdmUgdmFsdWVzIHRvIHRoZSBhcGkuIE1lcmdlcyBhcnJheXMsIGJ1dCBvdGhlcndpc2Ugc2FtZSBhcyBzYXZlXG4gICAgICAgIC8vICAqIEBwYXJhbSB7T2JqZWN0fFN0cmluZ30gdmFyaWFibGUgT2JqZWN0IHdpdGggYXR0cmlidXRlcywgb3Igc3RyaW5nIGtleVxuICAgICAgICAvLyAgKiBAcGFyYW0ge09iamVjdH0gdmFsIE9wdGlvbmFsIGlmIHByZXYgcGFyYW1ldGVyIHdhcyBhIHN0cmluZywgc2V0IHZhbHVlIGhlcmVcbiAgICAgICAgLy8gICogQHBhcmFtIHtPYmplY3R9IG9wdGlvbnMgT3ZlcnJpZGVzIGZvciBjb25maWd1cmF0aW9uIG9wdGlvbnNcbiAgICAgICAgLy8gICpcbiAgICAgICAgLy8gICogQGV4YW1wbGVcbiAgICAgICAgLy8gICogICAgIHZzLm1lcmdlKHsgcHJpY2U6IDQsIHF1YW50aXR5OiA1LCBwcm9kdWN0czogWzIsMyw0XSB9KVxuICAgICAgICAvLyAgKiAgICAgdnMubWVyZ2UoJ3ByaWNlJywgNCk7XG5cbiAgICAgICAgLy8gbWVyZ2U6IGZ1bmN0aW9uICh2YXJpYWJsZSwgdmFsLCBvcHRpb25zKSB7XG4gICAgICAgIC8vICAgICB2YXIgYXR0cnM7XG4gICAgICAgIC8vICAgICBpZiAodHlwZW9mIHZhcmlhYmxlID09PSAnb2JqZWN0Jykge1xuICAgICAgICAvLyAgICAgICBhdHRycyA9IHZhcmlhYmxlO1xuICAgICAgICAvLyAgICAgICBvcHRpb25zID0gdmFsO1xuICAgICAgICAvLyAgICAgfSBlbHNlIHtcbiAgICAgICAgLy8gICAgICAgKGF0dHJzID0ge30pW3ZhcmlhYmxlXSA9IHZhbDtcbiAgICAgICAgLy8gICAgIH1cbiAgICAgICAgLy8gICAgIHZhciBodHRwT3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LCBzZXJ2aWNlT3B0aW9ucywgb3B0aW9ucyk7XG5cbiAgICAgICAgLy8gICAgIHJldHVybiBodHRwLnBhdGNoLmNhbGwodGhpcywgYXR0cnMsIGh0dHBPcHRpb25zKTtcbiAgICAgICAgLy8gfVxuICAgIH07XG4gICAgJC5leHRlbmQodGhpcywgcHVibGljQVBJKTtcbn07XG4iLCIvKipcbiAqICMjIFdvcmxkIEFQSSBBZGFwdGVyXG4gKlxuICogQSBbcnVuXSguLi8uLi8uLi9nbG9zc2FyeS8jcnVuKSBpcyBhIGNvbGxlY3Rpb24gb2YgZW5kIHVzZXIgaW50ZXJhY3Rpb25zIHdpdGggYSBwcm9qZWN0IGFuZCBpdHMgbW9kZWwgLS0gaW5jbHVkaW5nIHNldHRpbmcgdmFyaWFibGVzLCBtYWtpbmcgZGVjaXNpb25zLCBhbmQgY2FsbGluZyBvcGVyYXRpb25zLiBGb3IgYnVpbGRpbmcgbXVsdGlwbGF5ZXIgc2ltdWxhdGlvbnMgeW91IHR5cGljYWxseSB3YW50IG11bHRpcGxlIGVuZCB1c2VycyB0byBzaGFyZSB0aGUgc2FtZSBzZXQgb2YgaW50ZXJhY3Rpb25zLCBhbmQgd29yayB3aXRoaW4gYSBjb21tb24gc3RhdGUuIEVwaWNlbnRlciBhbGxvd3MgeW91IHRvIGNyZWF0ZSBcIndvcmxkc1wiIHRvIGhhbmRsZSBzdWNoIGNhc2VzLiBPbmx5IFt0ZWFtIHByb2plY3RzXSguLi8uLi8uLi9nbG9zc2FyeS8jdGVhbSkgY2FuIGJlIG11bHRpcGxheWVyLlxuICpcbiAqIFRoZSBXb3JsZCBBUEkgQWRhcHRlciBhbGxvd3MgeW91IHRvIGNyZWF0ZSwgYWNjZXNzLCBhbmQgbWFuaXB1bGF0ZSBtdWx0aXBsYXllciB3b3JsZHMgd2l0aGluIHlvdXIgRXBpY2VudGVyIHByb2plY3QuIFlvdSBjYW4gdXNlIHRoaXMgdG8gYWRkIGFuZCByZW1vdmUgZW5kIHVzZXJzIGZyb20gdGhlIHdvcmxkLCBhbmQgdG8gY3JlYXRlLCBhY2Nlc3MsIGFuZCByZW1vdmUgdGhlaXIgcnVucy4gQmVjYXVzZSBvZiB0aGlzLCB0eXBpY2FsbHkgdGhlIFdvcmxkIEFkYXB0ZXIgaXMgdXNlZCBmb3IgZmFjaWxpdGF0b3IgcGFnZXMgaW4geW91ciBwcm9qZWN0LiAoVGhlIHJlbGF0ZWQgW1dvcmxkIE1hbmFnZXJdKC4uL3dvcmxkLW1hbmFnZXIvKSBwcm92aWRlcyBhbiBlYXN5IHdheSB0byBhY2Nlc3MgcnVucyBhbmQgd29ybGRzIGZvciBwYXJ0aWN1bGFyIGVuZCB1c2Vycywgc28gaXMgdHlwaWNhbGx5IHVzZWQgaW4gcGFnZXMgdGhhdCBlbmQgdXNlcnMgd2lsbCBpbnRlcmFjdCB3aXRoLilcbiAqXG4gKiBBcyB3aXRoIGFsbCB0aGUgb3RoZXIgW0FQSSBBZGFwdGVyc10oLi4vLi4vKSwgYWxsIG1ldGhvZHMgdGFrZSBpbiBhbiBcIm9wdGlvbnNcIiBvYmplY3QgYXMgdGhlIGxhc3QgcGFyYW1ldGVyLiBUaGUgb3B0aW9ucyBjYW4gYmUgdXNlZCB0byBleHRlbmQvb3ZlcnJpZGUgdGhlIFdvcmxkIEFQSSBTZXJ2aWNlIGRlZmF1bHRzLlxuICpcbiAqIFRvIHVzZSB0aGUgV29ybGQgQWRhcHRlciwgaW5zdGFudGlhdGUgaXQgYW5kIHRoZW4gYWNjZXNzIHRoZSBtZXRob2RzIHByb3ZpZGVkLiBJbnN0YW50aWF0aW5nIHJlcXVpcmVzIHRoZSBhY2NvdW50IGlkICgqKlRlYW0gSUQqKiBpbiB0aGUgRXBpY2VudGVyIHVzZXIgaW50ZXJmYWNlKSwgcHJvamVjdCBpZCAoKipQcm9qZWN0IElEKiopLCBhbmQgZ3JvdXAgKCoqR3JvdXAgTmFtZSoqKS5cbiAqXG4gKiAgICAgICB2YXIgd2EgPSBuZXcgRi5zZXJ2aWNlLldvcmxkKHtcbiAqICAgICAgICAgIGFjY291bnQ6ICdhY21lLXNpbXVsYXRpb25zJyxcbiAqICAgICAgICAgIHByb2plY3Q6ICdzdXBwbHktY2hhaW4tZ2FtZScsXG4gKiAgICAgICAgICBncm91cDogJ3RlYW0xJyB9KTtcbiAqICAgICAgIHdhLmNyZWF0ZSgpXG4gKiAgICAgICAgICAudGhlbihmdW5jdGlvbih3b3JsZCkge1xuICogICAgICAgICAgICAgIC8vIGNhbGwgbWV0aG9kcywgZS5nLiB3YS5hZGRVc2VycygpXG4gKiAgICAgICAgICB9KTtcbiAqL1xuXG4ndXNlIHN0cmljdCc7XG5cbnZhciBDb25maWdTZXJ2aWNlID0gcmVxdWlyZSgnLi9jb25maWd1cmF0aW9uLXNlcnZpY2UnKTtcbi8vIHZhciBxdXRpbCA9IHJlcXVpcmUoJy4uL3V0aWwvcXVlcnktdXRpbCcpO1xudmFyIFRyYW5zcG9ydEZhY3RvcnkgPSByZXF1aXJlKCcuLi90cmFuc3BvcnQvaHR0cC10cmFuc3BvcnQtZmFjdG9yeScpO1xudmFyIFNlc3Npb25NYW5hZ2VyID0gcmVxdWlyZSgnLi4vc3RvcmUvc2Vzc2lvbi1tYW5hZ2VyJyk7XG52YXIgX3BpY2sgPSByZXF1aXJlKCcuLi91dGlsL29iamVjdC11dGlsJykuX3BpY2s7XG5cbnZhciBhcGlCYXNlID0gJ211bHRpcGxheWVyLyc7XG52YXIgYXNzaWdubWVudEVuZHBvaW50ID0gYXBpQmFzZSArICdhc3NpZ24nO1xudmFyIGFwaUVuZHBvaW50ID0gYXBpQmFzZSArICd3b3JsZCc7XG52YXIgcHJvamVjdEVuZHBvaW50ID0gYXBpQmFzZSArICdwcm9qZWN0JztcblxubW9kdWxlLmV4cG9ydHMgPSBmdW5jdGlvbiAoY29uZmlnKSB7XG4gICAgdmFyIGRlZmF1bHRzID0ge1xuICAgICAgICAvKipcbiAgICAgICAgICogRm9yIHByb2plY3RzIHRoYXQgcmVxdWlyZSBhdXRoZW50aWNhdGlvbiwgcGFzcyBpbiB0aGUgdXNlciBhY2Nlc3MgdG9rZW4gKGRlZmF1bHRzIHRvIGVtcHR5IHN0cmluZykuIElmIHRoZSB1c2VyIGlzIGFscmVhZHkgbG9nZ2VkIGluIHRvIEVwaWNlbnRlciwgdGhlIHVzZXIgYWNjZXNzIHRva2VuIGlzIGFscmVhZHkgc2V0IGluIGEgY29va2llIGFuZCBhdXRvbWF0aWNhbGx5IGxvYWRlZCBmcm9tIHRoZXJlLiAoU2VlIFttb3JlIGJhY2tncm91bmQgb24gYWNjZXNzIHRva2Vuc10oLi4vLi4vLi4vcHJvamVjdF9hY2Nlc3MvKSkuXG4gICAgICAgICAqIEBzZWUgW0F1dGhlbnRpY2F0aW9uIEFQSSBTZXJ2aWNlXSguLi9hdXRoLWFwaS1zZXJ2aWNlLykgZm9yIGdldHRpbmcgdG9rZW5zLlxuICAgICAgICAgKiBAdHlwZSB7U3RyaW5nfVxuICAgICAgICAgKi9cbiAgICAgICB0b2tlbjogdW5kZWZpbmVkLFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBUaGUgcHJvamVjdCBpZC4gSWYgbGVmdCB1bmRlZmluZWQsIHRha2VuIGZyb20gdGhlIFVSTC5cbiAgICAgICAgICogQHR5cGUge1N0cmluZ31cbiAgICAgICAgICovXG4gICAgICAgIHByb2plY3Q6IHVuZGVmaW5lZCxcblxuICAgICAgICAvKipcbiAgICAgICAgICogVGhlIGFjY291bnQgaWQuIEluIHRoZSBFcGljZW50ZXIgVUksIHRoaXMgaXMgdGhlICoqVGVhbSBJRCoqIChmb3IgdGVhbSBwcm9qZWN0cykuIElmIGxlZnQgdW5kZWZpbmVkLCB0YWtlbiBmcm9tIHRoZSBVUkwuXG4gICAgICAgICAqIEB0eXBlIHtTdHJpbmd9XG4gICAgICAgICAqL1xuICAgICAgICBhY2NvdW50OiB1bmRlZmluZWQsXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIFRoZSBncm91cCBuYW1lLiBEZWZhdWx0cyB0byB1bmRlZmluZWQuXG4gICAgICAgICAqIEB0eXBlIHtTdHJpbmd9XG4gICAgICAgICAqL1xuICAgICAgICBncm91cDogdW5kZWZpbmVkLFxuXG4gICAgICAgLyoqXG4gICAgICAgICAqIFRoZSBtb2RlbCBmaWxlIHRvIHVzZSB0byBjcmVhdGUgcnVucyBpbiB0aGlzIHdvcmxkLiBEZWZhdWx0cyB0byB1bmRlZmluZWQuXG4gICAgICAgICAqIEB0eXBlIHtTdHJpbmd9XG4gICAgICAgICAqL1xuICAgICAgICBtb2RlbDogdW5kZWZpbmVkLFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBDcml0ZXJpYSBieSB3aGljaCB0byBmaWx0ZXIgd29ybGQuIEN1cnJlbnRseSBvbmx5IHN1cHBvcnRzIHdvcmxkLWlkcyBhcyBmaWx0ZXJzLlxuICAgICAgICAgKiBAdHlwZSB7U3RyaW5nfVxuICAgICAgICAgKi9cbiAgICAgICAgZmlsdGVyOiAnJyxcblxuICAgICAgICAvKipcbiAgICAgICAgICogQ29udmVuaWVuY2UgYWxpYXMgZm9yIGZpbHRlclxuICAgICAgICAgKiBAdHlwZSB7U3RyaW5nfVxuICAgICAgICAgKi9cbiAgICAgICAgaWQ6ICcnLFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBPcHRpb25zIHRvIHBhc3Mgb24gdG8gdGhlIHVuZGVybHlpbmcgdHJhbnNwb3J0IGxheWVyLiBBbGwganF1ZXJ5LmFqYXggb3B0aW9ucyBhdCBodHRwOi8vYXBpLmpxdWVyeS5jb20valF1ZXJ5LmFqYXgvIGFyZSBhdmFpbGFibGUuIERlZmF1bHRzIHRvIGVtcHR5IG9iamVjdC5cbiAgICAgICAgICogQHR5cGUge09iamVjdH1cbiAgICAgICAgICovXG4gICAgICAgIHRyYW5zcG9ydDoge30sXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIENhbGxlZCB3aGVuIHRoZSBjYWxsIGNvbXBsZXRlcyBzdWNjZXNzZnVsbHkuIERlZmF1bHRzIHRvIGAkLm5vb3BgLlxuICAgICAgICAgKiBAdHlwZSB7ZnVuY3Rpb259XG4gICAgICAgICAqL1xuICAgICAgICBzdWNjZXNzOiAkLm5vb3AsXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIENhbGxlZCB3aGVuIHRoZSBjYWxsIGZhaWxzLiBEZWZhdWx0cyB0byBgJC5ub29wYC5cbiAgICAgICAgICogQHR5cGUge2Z1bmN0aW9ufVxuICAgICAgICAgKi9cbiAgICAgICAgZXJyb3I6ICQubm9vcFxuICAgIH07XG5cbiAgICB0aGlzLnNlc3Npb25NYW5hZ2VyID0gbmV3IFNlc3Npb25NYW5hZ2VyKCk7XG4gICAgdmFyIHNlcnZpY2VPcHRpb25zID0gdGhpcy5zZXNzaW9uTWFuYWdlci5nZXRNZXJnZWRPcHRpb25zKGRlZmF1bHRzLCBjb25maWcpO1xuICAgIGlmIChzZXJ2aWNlT3B0aW9ucy5pZCkge1xuICAgICAgICBzZXJ2aWNlT3B0aW9ucy5maWx0ZXIgPSBzZXJ2aWNlT3B0aW9ucy5pZDtcbiAgICB9XG5cbiAgICB2YXIgdXJsQ29uZmlnID0gbmV3IENvbmZpZ1NlcnZpY2Uoc2VydmljZU9wdGlvbnMpLmdldCgnc2VydmVyJyk7XG5cbiAgICBpZiAoIXNlcnZpY2VPcHRpb25zLmFjY291bnQpIHtcbiAgICAgICAgc2VydmljZU9wdGlvbnMuYWNjb3VudCA9IHVybENvbmZpZy5hY2NvdW50UGF0aDtcbiAgICB9XG5cbiAgICBpZiAoIXNlcnZpY2VPcHRpb25zLnByb2plY3QpIHtcbiAgICAgICAgc2VydmljZU9wdGlvbnMucHJvamVjdCA9IHVybENvbmZpZy5wcm9qZWN0UGF0aDtcbiAgICB9XG5cbiAgICB2YXIgdHJhbnNwb3J0T3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LCBzZXJ2aWNlT3B0aW9ucy50cmFuc3BvcnQsIHtcbiAgICAgICAgdXJsOiB1cmxDb25maWcuZ2V0QVBJUGF0aChhcGlFbmRwb2ludClcbiAgICB9KTtcblxuICAgIGlmIChzZXJ2aWNlT3B0aW9ucy50b2tlbikge1xuICAgICAgICB0cmFuc3BvcnRPcHRpb25zLmhlYWRlcnMgPSB7XG4gICAgICAgICAgICAnQXV0aG9yaXphdGlvbic6ICdCZWFyZXIgJyArIHNlcnZpY2VPcHRpb25zLnRva2VuXG4gICAgICAgIH07XG4gICAgfVxuXG4gICAgdmFyIGh0dHAgPSBuZXcgVHJhbnNwb3J0RmFjdG9yeSh0cmFuc3BvcnRPcHRpb25zKTtcblxuICAgIHZhciBzZXRJZEZpbHRlck9yVGhyb3dFcnJvciA9IGZ1bmN0aW9uIChvcHRpb25zKSB7XG4gICAgICAgIGlmIChvcHRpb25zLmlkKSB7XG4gICAgICAgICAgICBzZXJ2aWNlT3B0aW9ucy5maWx0ZXIgPSBvcHRpb25zLmlkO1xuICAgICAgICB9XG4gICAgICAgIGlmIChvcHRpb25zLmZpbHRlcikge1xuICAgICAgICAgICAgc2VydmljZU9wdGlvbnMuZmlsdGVyID0gb3B0aW9ucy5maWx0ZXI7XG4gICAgICAgIH1cbiAgICAgICAgaWYgKCFzZXJ2aWNlT3B0aW9ucy5maWx0ZXIpIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcignTm8gd29ybGQgaWQgc3BlY2lmaWVkIHRvIGFwcGx5IG9wZXJhdGlvbnMgYWdhaW5zdC4gVGhpcyBjb3VsZCBoYXBwZW4gaWYgdGhlIHVzZXIgaXMgbm90IGFzc2lnbmVkIHRvIGEgd29ybGQgYW5kIGlzIHRyeWluZyB0byB3b3JrIHdpdGggcnVucyBmcm9tIHRoYXQgd29ybGQuJyk7XG4gICAgICAgIH1cbiAgICB9O1xuXG4gICAgdmFyIHZhbGlkYXRlTW9kZWxPclRocm93RXJyb3IgPSBmdW5jdGlvbiAob3B0aW9ucykge1xuICAgICAgICBpZiAoIW9wdGlvbnMubW9kZWwpIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcignTm8gbW9kZWwgc3BlY2lmaWVkIHRvIGdldCB0aGUgY3VycmVudCBydW4nKTtcbiAgICAgICAgfVxuICAgIH07XG5cbiAgICB2YXIgcHVibGljQVBJID0ge1xuXG4gICAgICAgIC8qKlxuICAgICAgICAqIENyZWF0ZXMgYSBuZXcgV29ybGQuXG4gICAgICAgICpcbiAgICAgICAgKiBVc2luZyB0aGlzIG1ldGhvZCBpcyByYXJlLiBJdCBpcyBtb3JlIGNvbW1vbiB0byBjcmVhdGUgd29ybGRzIGF1dG9tYXRpY2FsbHkgd2hpbGUgeW91IGBhdXRvQXNzaWduKClgIGVuZCB1c2VycyB0byB3b3JsZHMuIChJbiB0aGlzIGNhc2UsIGNvbmZpZ3VyYXRpb24gZGF0YSBmb3IgdGhlIHdvcmxkLCBzdWNoIGFzIHRoZSByb2xlcywgYXJlIHJlYWQgZnJvbSB0aGUgcHJvamVjdC1sZXZlbCB3b3JsZCBjb25maWd1cmF0aW9uIGluZm9ybWF0aW9uLCBmb3IgZXhhbXBsZSBieSBgZ2V0UHJvamVjdFNldHRpbmdzKClgLilcbiAgICAgICAgKlxuICAgICAgICAqICAqKkV4YW1wbGUqKlxuICAgICAgICAqXG4gICAgICAgICogICAgICB2YXIgd2EgPSBuZXcgRi5zZXJ2aWNlLldvcmxkKHtcbiAgICAgICAgKiAgICAgICAgICAgYWNjb3VudDogJ2FjbWUtc2ltdWxhdGlvbnMnLFxuICAgICAgICAqICAgICAgICAgICBwcm9qZWN0OiAnc3VwcGx5LWNoYWluLWdhbWUnLFxuICAgICAgICAqICAgICAgICAgICBncm91cDogJ3RlYW0xJyB9KTtcbiAgICAgICAgKiAgICAgIHdhLmNyZWF0ZSh7XG4gICAgICAgICogICAgICAgICAgIHJvbGVzOiBbJ1ZQIE1hcmtldGluZycsICdWUCBTYWxlcycsICdWUCBFbmdpbmVlcmluZyddXG4gICAgICAgICogICAgICAgfSk7XG4gICAgICAgICpcbiAgICAgICAgKiAgKipQYXJhbWV0ZXJzKipcbiAgICAgICAgKiBAcGFyYW0ge29iamVjdH0gYHBhcmFtc2AgUGFyYW1ldGVycyB0byBjcmVhdGUgdGhlIHdvcmxkLlxuICAgICAgICAqIEBwYXJhbSB7c3RyaW5nfSBgcGFyYW1zLmdyb3VwYCAoT3B0aW9uYWwpIFRoZSAqKkdyb3VwIE5hbWUqKiB0byBjcmVhdGUgdGhpcyB3b3JsZCB1bmRlci4gT25seSBlbmQgdXNlcnMgaW4gdGhpcyBncm91cCBhcmUgZWxpZ2libGUgdG8gam9pbiB0aGUgd29ybGQuIE9wdGlvbmFsIGhlcmU7IHJlcXVpcmVkIHdoZW4gaW5zdGFudGlhdGluZyB0aGUgc2VydmljZSAoYG5ldyBGLnNlcnZpY2UuV29ybGQoKWApLlxuICAgICAgICAqIEBwYXJhbSB7b2JqZWN0fSBgcGFyYW1zLnJvbGVzYCAoT3B0aW9uYWwpIFRoZSBsaXN0IG9mIHJvbGVzIChzdHJpbmdzKSBmb3IgdGhpcyB3b3JsZC4gU29tZSB3b3JsZHMgaGF2ZSBzcGVjaWZpYyByb2xlcyB0aGF0ICoqbXVzdCoqIGJlIGZpbGxlZCBieSBlbmQgdXNlcnMuIExpc3RpbmcgdGhlIHJvbGVzIGFsbG93cyB5b3UgdG8gYXV0b2Fzc2lnbiB1c2VycyB0byB3b3JsZHMgYW5kIGVuc3VyZSB0aGF0IGFsbCByb2xlcyBhcmUgZmlsbGVkIGluIGVhY2ggd29ybGQuXG4gICAgICAgICogQHBhcmFtIHtvYmplY3R9IGBwYXJhbXMub3B0aW9uYWxSb2xlc2AgKE9wdGlvbmFsKSBUaGUgbGlzdCBvZiBvcHRpb25hbCByb2xlcyAoc3RyaW5ncykgZm9yIHRoaXMgd29ybGQuIFNvbWUgd29ybGRzIGhhdmUgc3BlY2lmaWMgcm9sZXMgdGhhdCAqKm1heSoqIGJlIGZpbGxlZCBieSBlbmQgdXNlcnMuIExpc3RpbmcgdGhlIG9wdGlvbmFsIHJvbGVzIGFzIHBhcnQgb2YgdGhlIHdvcmxkIG9iamVjdCBhbGxvd3MgeW91IHRvIGF1dG9hc3NpZ24gdXNlcnMgdG8gd29ybGRzIGFuZCBlbnN1cmUgdGhhdCBhbGwgcm9sZXMgYXJlIGZpbGxlZCBpbiBlYWNoIHdvcmxkLlxuICAgICAgICAqIEBwYXJhbSB7aW50ZWdlcn0gYHBhcmFtcy5taW5Vc2Vyc2AgKE9wdGlvbmFsKSBUaGUgbWluaW11bSBudW1iZXIgb2YgdXNlcnMgZm9yIHRoZSB3b3JsZC4gSW5jbHVkaW5nIHRoaXMgbnVtYmVyIGFsbG93cyB5b3UgdG8gYXV0b2Fzc2lnbiBlbmQgdXNlcnMgdG8gd29ybGRzIGFuZCBlbnN1cmUgdGhhdCB0aGUgY29ycmVjdCBudW1iZXIgb2YgdXNlcnMgYXJlIGluIGVhY2ggd29ybGQuXG4gICAgICAgICogQHBhcmFtIHtvYmplY3R9IGBvcHRpb25zYCAoT3B0aW9uYWwpIE9wdGlvbnMgb2JqZWN0IHRvIG92ZXJyaWRlIGdsb2JhbCBvcHRpb25zLlxuICAgICAgICAqXG4gICAgICAgICovXG4gICAgICAgIGNyZWF0ZTogZnVuY3Rpb24gKHBhcmFtcywgb3B0aW9ucykge1xuICAgICAgICAgICAgdmFyIGNyZWF0ZU9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSwgc2VydmljZU9wdGlvbnMsIG9wdGlvbnMsIHsgdXJsOiB1cmxDb25maWcuZ2V0QVBJUGF0aChhcGlFbmRwb2ludCkgfSk7XG4gICAgICAgICAgICB2YXIgd29ybGRBcGlQYXJhbXMgPSBbJ3Njb3BlJywgJ2ZpbGVzJywgJ3JvbGVzJywgJ29wdGlvbmFsUm9sZXMnLCAnbWluVXNlcnMnLCAnZ3JvdXAnLCAnbmFtZSddO1xuICAgICAgICAgICAgdmFyIHZhbGlkUGFyYW1zID0gX3BpY2soc2VydmljZU9wdGlvbnMsIFsnYWNjb3VudCcsICdwcm9qZWN0JywgJ2dyb3VwJ10pO1xuICAgICAgICAgICAgLy8gd2hpdGVsaXN0IHRoZSBmaWVsZHMgdGhhdCB3ZSBhY3R1YWxseSBjYW4gc2VuZCB0byB0aGUgYXBpXG4gICAgICAgICAgICBwYXJhbXMgPSBfcGljayhwYXJhbXMsIHdvcmxkQXBpUGFyYW1zKTtcblxuICAgICAgICAgICAgLy8gYWNjb3VudCBhbmQgcHJvamVjdCBnbyBpbiB0aGUgYm9keSwgbm90IGluIHRoZSB1cmxcbiAgICAgICAgICAgIHBhcmFtcyA9ICQuZXh0ZW5kKHt9LCB2YWxpZFBhcmFtcywgcGFyYW1zKTtcblxuICAgICAgICAgICAgdmFyIG9sZFN1Y2Nlc3MgPSBjcmVhdGVPcHRpb25zLnN1Y2Nlc3M7XG4gICAgICAgICAgICBjcmVhdGVPcHRpb25zLnN1Y2Nlc3MgPSBmdW5jdGlvbiAocmVzcG9uc2UpIHtcbiAgICAgICAgICAgICAgICBzZXJ2aWNlT3B0aW9ucy5maWx0ZXIgPSByZXNwb25zZS5pZDsgLy9hbGwgZnV0dXJlIGNoYWluZWQgY2FsbHMgdG8gb3BlcmF0ZSBvbiB0aGlzIGlkXG4gICAgICAgICAgICAgICAgcmV0dXJuIG9sZFN1Y2Nlc3MuYXBwbHkodGhpcywgYXJndW1lbnRzKTtcbiAgICAgICAgICAgIH07XG5cbiAgICAgICAgICAgIHJldHVybiBodHRwLnBvc3QocGFyYW1zLCBjcmVhdGVPcHRpb25zKTtcbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgKiBVcGRhdGVzIGEgV29ybGQsIGZvciBleGFtcGxlIHRvIHJlcGxhY2UgdGhlIHJvbGVzIGluIHRoZSB3b3JsZC5cbiAgICAgICAgKlxuICAgICAgICAqIFR5cGljYWxseSwgeW91IGNvbXBsZXRlIHdvcmxkIGNvbmZpZ3VyYXRpb24gYXQgdGhlIHByb2plY3QgbGV2ZWwsIHJhdGhlciB0aGFuIGF0IHRoZSB3b3JsZCBsZXZlbC4gRm9yIGV4YW1wbGUsIGVhY2ggd29ybGQgaW4geW91ciBwcm9qZWN0IHByb2JhYmx5IGhhcyB0aGUgc2FtZSByb2xlcyBmb3IgZW5kIHVzZXJzLiBBbmQgeW91ciBwcm9qZWN0IGlzIHByb2JhYmx5IGVpdGhlciBjb25maWd1cmVkIHNvIHRoYXQgYWxsIGVuZCB1c2VycyBzaGFyZSB0aGUgc2FtZSB3b3JsZCAoYW5kIHJ1biksIG9yIHNtYWxsZXIgc2V0cyBvZiBlbmQgdXNlcnMgc2hhcmUgd29ybGRzIOKAlCBidXQgbm90IGJvdGguIEhvd2V2ZXIsIHRoaXMgbWV0aG9kIGlzIGF2YWlsYWJsZSBpZiB5b3UgbmVlZCB0byB1cGRhdGUgdGhlIGNvbmZpZ3VyYXRpb24gb2YgYSBwYXJ0aWN1bGFyIHdvcmxkLlxuICAgICAgICAqXG4gICAgICAgICogICoqRXhhbXBsZSoqXG4gICAgICAgICpcbiAgICAgICAgKiAgICAgIHZhciB3YSA9IG5ldyBGLnNlcnZpY2UuV29ybGQoe1xuICAgICAgICAqICAgICAgICAgICBhY2NvdW50OiAnYWNtZS1zaW11bGF0aW9ucycsXG4gICAgICAgICogICAgICAgICAgIHByb2plY3Q6ICdzdXBwbHktY2hhaW4tZ2FtZScsXG4gICAgICAgICogICAgICAgICAgIGdyb3VwOiAndGVhbTEnIH0pO1xuICAgICAgICAqICAgICAgd2EuY3JlYXRlKClcbiAgICAgICAgKiAgICAgICAgICAgLnRoZW4oZnVuY3Rpb24od29ybGQpIHtcbiAgICAgICAgKiAgICAgICAgICAgICAgIHdhLnVwZGF0ZSh7IHJvbGVzOiBbJ1ZQIE1hcmtldGluZycsICdWUCBTYWxlcycsICdWUCBFbmdpbmVlcmluZyddIH0pO1xuICAgICAgICAqICAgICAgICAgICB9KTtcbiAgICAgICAgKlxuICAgICAgICAqICAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAqIEBwYXJhbSB7b2JqZWN0fSBgcGFyYW1zYCBQYXJhbWV0ZXJzIHRvIHVwZGF0ZSB0aGUgd29ybGQuXG4gICAgICAgICogQHBhcmFtIHtzdHJpbmd9IGBwYXJhbXMubmFtZWAgQSBzdHJpbmcgaWRlbnRpZmllciBmb3IgdGhlIGxpbmtlZCBlbmQgdXNlcnMsIGZvciBleGFtcGxlLCBcIm5hbWVcIjogXCJPdXIgVGVhbVwiLlxuICAgICAgICAqIEBwYXJhbSB7b2JqZWN0fSBgcGFyYW1zLnJvbGVzYCAoT3B0aW9uYWwpIFRoZSBsaXN0IG9mIHJvbGVzIChzdHJpbmdzKSBmb3IgdGhpcyB3b3JsZC4gU29tZSB3b3JsZHMgaGF2ZSBzcGVjaWZpYyByb2xlcyB0aGF0ICoqbXVzdCoqIGJlIGZpbGxlZCBieSBlbmQgdXNlcnMuIExpc3RpbmcgdGhlIHJvbGVzIGFsbG93cyB5b3UgdG8gYXV0b2Fzc2lnbiB1c2VycyB0byB3b3JsZHMgYW5kIGVuc3VyZSB0aGF0IGFsbCByb2xlcyBhcmUgZmlsbGVkIGluIGVhY2ggd29ybGQuXG4gICAgICAgICogQHBhcmFtIHtvYmplY3R9IGBwYXJhbXMub3B0aW9uYWxSb2xlc2AgKE9wdGlvbmFsKSBUaGUgbGlzdCBvZiBvcHRpb25hbCByb2xlcyAoc3RyaW5ncykgZm9yIHRoaXMgd29ybGQuIFNvbWUgd29ybGRzIGhhdmUgc3BlY2lmaWMgcm9sZXMgdGhhdCAqKm1heSoqIGJlIGZpbGxlZCBieSBlbmQgdXNlcnMuIExpc3RpbmcgdGhlIG9wdGlvbmFsIHJvbGVzIGFzIHBhcnQgb2YgdGhlIHdvcmxkIG9iamVjdCBhbGxvd3MgeW91IHRvIGF1dG9hc3NpZ24gdXNlcnMgdG8gd29ybGRzIGFuZCBlbnN1cmUgdGhhdCBhbGwgcm9sZXMgYXJlIGZpbGxlZCBpbiBlYWNoIHdvcmxkLlxuICAgICAgICAqIEBwYXJhbSB7aW50ZWdlcn0gYHBhcmFtcy5taW5Vc2Vyc2AgKE9wdGlvbmFsKSBUaGUgbWluaW11bSBudW1iZXIgb2YgdXNlcnMgZm9yIHRoZSB3b3JsZC4gSW5jbHVkaW5nIHRoaXMgbnVtYmVyIGFsbG93cyB5b3UgdG8gYXV0b2Fzc2lnbiBlbmQgdXNlcnMgdG8gd29ybGRzIGFuZCBlbnN1cmUgdGhhdCB0aGUgY29ycmVjdCBudW1iZXIgb2YgdXNlcnMgYXJlIGluIGVhY2ggd29ybGQuXG4gICAgICAgICogQHBhcmFtIHtvYmplY3R9IGBvcHRpb25zYCAoT3B0aW9uYWwpIE9wdGlvbnMgb2JqZWN0IHRvIG92ZXJyaWRlIGdsb2JhbCBvcHRpb25zLlxuICAgICAgICAqXG4gICAgICAgICovXG4gICAgICAgIHVwZGF0ZTogZnVuY3Rpb24gKHBhcmFtcywgb3B0aW9ucykge1xuICAgICAgICAgICAgdmFyIHdoaXRlbGlzdCA9IFsncm9sZXMnLCAnb3B0aW9uYWxSb2xlcycsICdtaW5Vc2VycyddO1xuICAgICAgICAgICAgb3B0aW9ucyA9IG9wdGlvbnMgfHwge307XG4gICAgICAgICAgICBzZXRJZEZpbHRlck9yVGhyb3dFcnJvcihvcHRpb25zKTtcblxuICAgICAgICAgICAgdmFyIHVwZGF0ZU9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSxcbiAgICAgICAgICAgICAgICBzZXJ2aWNlT3B0aW9ucyxcbiAgICAgICAgICAgICAgICBvcHRpb25zLFxuICAgICAgICAgICAgICAgIHsgdXJsOiB1cmxDb25maWcuZ2V0QVBJUGF0aChhcGlFbmRwb2ludCkgKyBzZXJ2aWNlT3B0aW9ucy5maWx0ZXIgfVxuICAgICAgICAgICAgKTtcblxuICAgICAgICAgICAgcGFyYW1zID0gX3BpY2socGFyYW1zIHx8IHt9LCB3aGl0ZWxpc3QpO1xuXG4gICAgICAgICAgICByZXR1cm4gaHR0cC5wYXRjaChwYXJhbXMsIHVwZGF0ZU9wdGlvbnMpO1xuICAgICAgICB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAqIERlbGV0ZXMgYW4gZXhpc3Rpbmcgd29ybGQuXG4gICAgICAgICpcbiAgICAgICAgKiBUaGlzIGZ1bmN0aW9uIG9wdGlvbmFsbHkgdGFrZXMgb25lIGFyZ3VtZW50LiBJZiB0aGUgYXJndW1lbnQgaXMgYSBzdHJpbmcsIGl0IGlzIHRoZSBpZCBvZiB0aGUgd29ybGQgdG8gZGVsZXRlLiBJZiB0aGUgYXJndW1lbnQgaXMgYW4gb2JqZWN0LCBpdCBpcyB0aGUgb3ZlcnJpZGUgZm9yIGdsb2JhbCBvcHRpb25zLlxuICAgICAgICAqXG4gICAgICAgICogICoqRXhhbXBsZSoqXG4gICAgICAgICpcbiAgICAgICAgKiAgICAgIHZhciB3YSA9IG5ldyBGLnNlcnZpY2UuV29ybGQoe1xuICAgICAgICAqICAgICAgICAgICBhY2NvdW50OiAnYWNtZS1zaW11bGF0aW9ucycsXG4gICAgICAgICogICAgICAgICAgIHByb2plY3Q6ICdzdXBwbHktY2hhaW4tZ2FtZScsXG4gICAgICAgICogICAgICAgICAgIGdyb3VwOiAndGVhbTEnIH0pO1xuICAgICAgICAqICAgICAgd2EuY3JlYXRlKClcbiAgICAgICAgKiAgICAgICAgICAgLnRoZW4oZnVuY3Rpb24od29ybGQpIHtcbiAgICAgICAgKiAgICAgICAgICAgICAgIHdhLmRlbGV0ZSgpO1xuICAgICAgICAqICAgICAgICAgICB9KTtcbiAgICAgICAgKlxuICAgICAgICAqICAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAqIEBwYXJhbSB7U3RyaW5nfE9iamVjdH0gYG9wdGlvbnNgIChPcHRpb25hbCkgVGhlIGlkIG9mIHRoZSB3b3JsZCB0byBkZWxldGUsIG9yIG9wdGlvbnMgb2JqZWN0IHRvIG92ZXJyaWRlIGdsb2JhbCBvcHRpb25zLlxuICAgICAgICAqXG4gICAgICAgICovXG4gICAgICAgIGRlbGV0ZTogZnVuY3Rpb24gKG9wdGlvbnMpIHtcbiAgICAgICAgICAgIG9wdGlvbnMgPSAob3B0aW9ucyAmJiAodHlwZW9mIG9wdGlvbnMgPT09ICdzdHJpbmcnKSkgPyB7IGZpbHRlcjogb3B0aW9ucyB9IDoge307XG4gICAgICAgICAgICBzZXRJZEZpbHRlck9yVGhyb3dFcnJvcihvcHRpb25zKTtcblxuICAgICAgICAgICAgdmFyIGRlbGV0ZU9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSxcbiAgICAgICAgICAgICAgICBzZXJ2aWNlT3B0aW9ucyxcbiAgICAgICAgICAgICAgICBvcHRpb25zLFxuICAgICAgICAgICAgICAgIHsgdXJsOiB1cmxDb25maWcuZ2V0QVBJUGF0aChhcGlFbmRwb2ludCkgKyBzZXJ2aWNlT3B0aW9ucy5maWx0ZXIgfVxuICAgICAgICAgICAgKTtcblxuICAgICAgICAgICAgcmV0dXJuIGh0dHAuZGVsZXRlKG51bGwsIGRlbGV0ZU9wdGlvbnMpO1xuICAgICAgICB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAqIFVwZGF0ZXMgdGhlIGNvbmZpZ3VyYXRpb24gZm9yIHRoZSBjdXJyZW50IGluc3RhbmNlIG9mIHRoZSBXb3JsZCBBUEkgQWRhcHRlciAoaW5jbHVkaW5nIGFsbCBzdWJzZXF1ZW50IGZ1bmN0aW9uIGNhbGxzLCB1bnRpbCB0aGUgY29uZmlndXJhdGlvbiBpcyB1cGRhdGVkIGFnYWluKS5cbiAgICAgICAgKlxuICAgICAgICAqICoqRXhhbXBsZSoqXG4gICAgICAgICpcbiAgICAgICAgKiAgICAgIHZhciB3YSA9IG5ldyBGLnNlcnZpY2UuV29ybGQoey4uLn0pLnVwZGF0ZUNvbmZpZyh7IGZpbHRlcjogJzEyMycgfSkuYWRkVXNlcih7IHVzZXJJZDogJzEyMycgfSk7XG4gICAgICAgICpcbiAgICAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAqIEBwYXJhbSB7b2JqZWN0fSBgY29uZmlnYCBUaGUgY29uZmlndXJhdGlvbiBvYmplY3QgdG8gdXNlIGluIHVwZGF0aW5nIGV4aXN0aW5nIGNvbmZpZ3VyYXRpb24uXG4gICAgICAgICovXG4gICAgICAgIHVwZGF0ZUNvbmZpZzogZnVuY3Rpb24gKGNvbmZpZykge1xuICAgICAgICAgICAgJC5leHRlbmQoc2VydmljZU9wdGlvbnMsIGNvbmZpZyk7XG5cbiAgICAgICAgICAgIHJldHVybiB0aGlzO1xuICAgICAgICB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAqIExpc3RzIGFsbCB3b3JsZHMgZm9yIGEgZ2l2ZW4gYWNjb3VudCwgcHJvamVjdCwgYW5kIGdyb3VwLiBBbGwgdGhyZWUgYXJlIHJlcXVpcmVkLCBhbmQgaWYgbm90IHNwZWNpZmllZCBhcyBwYXJhbWV0ZXJzLCBhcmUgcmVhZCBmcm9tIHRoZSBzZXJ2aWNlLlxuICAgICAgICAqXG4gICAgICAgICogICoqRXhhbXBsZSoqXG4gICAgICAgICpcbiAgICAgICAgKiAgICAgIHZhciB3YSA9IG5ldyBGLnNlcnZpY2UuV29ybGQoe1xuICAgICAgICAqICAgICAgICAgICBhY2NvdW50OiAnYWNtZS1zaW11bGF0aW9ucycsXG4gICAgICAgICogICAgICAgICAgIHByb2plY3Q6ICdzdXBwbHktY2hhaW4tZ2FtZScsXG4gICAgICAgICogICAgICAgICAgIGdyb3VwOiAndGVhbTEnIH0pO1xuICAgICAgICAqICAgICAgd2EuY3JlYXRlKClcbiAgICAgICAgKiAgICAgICAgICAgLnRoZW4oZnVuY3Rpb24od29ybGQpIHtcbiAgICAgICAgKiAgICAgICAgICAgICAgIC8vIGxpc3RzIGFsbCB3b3JsZHMgaW4gZ3JvdXAgXCJ0ZWFtMVwiXG4gICAgICAgICogICAgICAgICAgICAgICB3YS5saXN0KCk7XG4gICAgICAgICpcbiAgICAgICAgKiAgICAgICAgICAgICAgIC8vIGxpc3RzIGFsbCB3b3JsZHMgaW4gZ3JvdXAgXCJvdGhlci1ncm91cC1uYW1lXCJcbiAgICAgICAgKiAgICAgICAgICAgICAgIHdhLmxpc3QoeyBncm91cDogJ290aGVyLWdyb3VwLW5hbWUnIH0pO1xuICAgICAgICAqICAgICAgICAgICB9KTtcbiAgICAgICAgKlxuICAgICAgICAqICAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAqIEBwYXJhbSB7b2JqZWN0fSBgb3B0aW9uc2AgKE9wdGlvbmFsKSBPcHRpb25zIG9iamVjdCB0byBvdmVycmlkZSBnbG9iYWwgb3B0aW9ucy5cbiAgICAgICAgKlxuICAgICAgICAqL1xuICAgICAgICBsaXN0OiBmdW5jdGlvbiAob3B0aW9ucykge1xuICAgICAgICAgICAgb3B0aW9ucyA9IG9wdGlvbnMgfHwge307XG5cbiAgICAgICAgICAgIHZhciBnZXRPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sXG4gICAgICAgICAgICAgICAgc2VydmljZU9wdGlvbnMsXG4gICAgICAgICAgICAgICAgb3B0aW9ucyxcbiAgICAgICAgICAgICAgICB7IHVybDogdXJsQ29uZmlnLmdldEFQSVBhdGgoYXBpRW5kcG9pbnQpIH1cbiAgICAgICAgICAgICk7XG5cbiAgICAgICAgICAgIHZhciBmaWx0ZXJzID0gX3BpY2soZ2V0T3B0aW9ucywgWydhY2NvdW50JywgJ3Byb2plY3QnLCAnZ3JvdXAnXSk7XG5cbiAgICAgICAgICAgIHJldHVybiBodHRwLmdldChmaWx0ZXJzLCBnZXRPcHRpb25zKTtcbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgKiBHZXRzIGFsbCB3b3JsZHMgdGhhdCBhbiBlbmQgdXNlciBiZWxvbmdzIHRvIGZvciBhIGdpdmVuIGFjY291bnQgKHRlYW0pLCBwcm9qZWN0LCBhbmQgZ3JvdXAuXG4gICAgICAgICpcbiAgICAgICAgKiAgKipFeGFtcGxlKipcbiAgICAgICAgKlxuICAgICAgICAqICAgICAgdmFyIHdhID0gbmV3IEYuc2VydmljZS5Xb3JsZCh7XG4gICAgICAgICogICAgICAgICAgIGFjY291bnQ6ICdhY21lLXNpbXVsYXRpb25zJyxcbiAgICAgICAgKiAgICAgICAgICAgcHJvamVjdDogJ3N1cHBseS1jaGFpbi1nYW1lJyxcbiAgICAgICAgKiAgICAgICAgICAgZ3JvdXA6ICd0ZWFtMScgfSk7XG4gICAgICAgICogICAgICB3YS5jcmVhdGUoKVxuICAgICAgICAqICAgICAgICAgICAudGhlbihmdW5jdGlvbih3b3JsZCkge1xuICAgICAgICAqICAgICAgICAgICAgICAgd2EuZ2V0V29ybGRzRm9yVXNlcignYjFjMTlkZGEtMmQyZS00Nzc3LWFkNWQtMzkyOWYxN2U4NmQzJylcbiAgICAgICAgKiAgICAgICAgICAgfSk7XG4gICAgICAgICpcbiAgICAgICAgKiAqKiBQYXJhbWV0ZXJzICoqXG4gICAgICAgICogQHBhcmFtIHtzdHJpbmd9IGB1c2VySWRgIFRoZSBgdXNlcklkYCBvZiB0aGUgdXNlciB3aG9zZSB3b3JsZHMgYXJlIGJlaW5nIHJldHJpZXZlZC5cbiAgICAgICAgKiBAcGFyYW0ge29iamVjdH0gYG9wdGlvbnNgIChPcHRpb25hbCkgT3B0aW9ucyBvYmplY3QgdG8gb3ZlcnJpZGUgZ2xvYmFsIG9wdGlvbnMuXG4gICAgICAgICovXG4gICAgICAgIGdldFdvcmxkc0ZvclVzZXI6IGZ1bmN0aW9uICh1c2VySWQsIG9wdGlvbnMpIHtcbiAgICAgICAgICAgIG9wdGlvbnMgPSBvcHRpb25zIHx8IHt9O1xuXG4gICAgICAgICAgICB2YXIgZ2V0T3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LFxuICAgICAgICAgICAgICAgIHNlcnZpY2VPcHRpb25zLFxuICAgICAgICAgICAgICAgIG9wdGlvbnMsXG4gICAgICAgICAgICAgICAgeyB1cmw6IHVybENvbmZpZy5nZXRBUElQYXRoKGFwaUVuZHBvaW50KSB9XG4gICAgICAgICAgICApO1xuXG4gICAgICAgICAgICB2YXIgZmlsdGVycyA9ICQuZXh0ZW5kKFxuICAgICAgICAgICAgICAgIF9waWNrKGdldE9wdGlvbnMsIFsnYWNjb3VudCcsICdwcm9qZWN0JywgJ2dyb3VwJ10pLFxuICAgICAgICAgICAgICAgIHsgdXNlcklkOiB1c2VySWQgfVxuICAgICAgICAgICAgKTtcblxuICAgICAgICAgICAgcmV0dXJuIGh0dHAuZ2V0KGZpbHRlcnMsIGdldE9wdGlvbnMpO1xuICAgICAgICB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBMb2FkIGluZm9ybWF0aW9uIGZvciBhIHNwZWNpZmljIHdvcmxkLiBBbGwgZnVydGhlciBjYWxscyB0byB0aGUgd29ybGQgc2VydmljZSB3aWxsIHVzZSB0aGUgaWQgcHJvdmlkZWQuXG4gICAgICAgICAqXG4gICAgICAgICAqICoqUGFyYW1ldGVycyoqXG4gICAgICAgICAqIEBwYXJhbSB7U3RyaW5nfSBgd29ybGRJZGAgVGhlIGlkIG9mIHRoZSB3b3JsZCB0byBsb2FkLlxuICAgICAgICAgKiBAcGFyYW0ge09iamVjdH0gYG9wdGlvbnNgIChPcHRpb25hbCkgT3B0aW9ucyBvYmplY3QgdG8gb3ZlcnJpZGUgZ2xvYmFsIG9wdGlvbnMuXG4gICAgICAgICAqL1xuICAgICAgICBsb2FkOiBmdW5jdGlvbiAod29ybGRJZCwgb3B0aW9ucykge1xuICAgICAgICAgICAgaWYgKHdvcmxkSWQpIHtcbiAgICAgICAgICAgICAgICBzZXJ2aWNlT3B0aW9ucy5maWx0ZXIgPSB3b3JsZElkO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgaWYgKCFzZXJ2aWNlT3B0aW9ucy5maWx0ZXIpIHtcbiAgICAgICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ1BsZWFzZSBwcm92aWRlIGEgd29ybGRpZCB0byBsb2FkJyk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICB2YXIgaHR0cE9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSwgc2VydmljZU9wdGlvbnMsIG9wdGlvbnMsICB7IHVybDogdXJsQ29uZmlnLmdldEFQSVBhdGgoYXBpRW5kcG9pbnQpICsgc2VydmljZU9wdGlvbnMuZmlsdGVyICsgJy8nIH0pO1xuICAgICAgICAgICAgcmV0dXJuIGh0dHAuZ2V0KCcnLCBodHRwT3B0aW9ucyk7XG4gICAgICAgIH0sXG5cbiAgICAgICAgLyoqXG4gICAgICAgICogQWRkcyBhbiBlbmQgdXNlciBvciBsaXN0IG9mIGVuZCB1c2VycyB0byBhIGdpdmVuIHdvcmxkLiBUaGUgZW5kIHVzZXIgbXVzdCBiZSBhIG1lbWJlciBvZiB0aGUgYGdyb3VwYCB0aGF0IGlzIGFzc29jaWF0ZWQgd2l0aCB0aGlzIHdvcmxkLlxuICAgICAgICAqXG4gICAgICAgICogICoqRXhhbXBsZSoqXG4gICAgICAgICpcbiAgICAgICAgKiAgICAgIHZhciB3YSA9IG5ldyBGLnNlcnZpY2UuV29ybGQoe1xuICAgICAgICAqICAgICAgICAgICBhY2NvdW50OiAnYWNtZS1zaW11bGF0aW9ucycsXG4gICAgICAgICogICAgICAgICAgIHByb2plY3Q6ICdzdXBwbHktY2hhaW4tZ2FtZScsXG4gICAgICAgICogICAgICAgICAgIGdyb3VwOiAndGVhbTEnIH0pO1xuICAgICAgICAqICAgICAgd2EuY3JlYXRlKClcbiAgICAgICAgKiAgICAgICAgICAgLnRoZW4oZnVuY3Rpb24od29ybGQpIHtcbiAgICAgICAgKiAgICAgICAgICAgICAgIC8vIGFkZCBvbmUgdXNlclxuICAgICAgICAqICAgICAgICAgICAgICAgd2EuYWRkVXNlcnMoJ2IxYzE5ZGRhLTJkMmUtNDc3Ny1hZDVkLTM5MjlmMTdlODZkMycpO1xuICAgICAgICAqICAgICAgICAgICAgICAgd2EuYWRkVXNlcnMoWydiMWMxOWRkYS0yZDJlLTQ3NzctYWQ1ZC0zOTI5ZjE3ZTg2ZDMnXSk7XG4gICAgICAgICogICAgICAgICAgICAgICB3YS5hZGRVc2Vycyh7IHVzZXJJZDogJ2IxYzE5ZGRhLTJkMmUtNDc3Ny1hZDVkLTM5MjlmMTdlODZkMycsIHJvbGU6ICdWUCBTYWxlcycgfSk7XG4gICAgICAgICpcbiAgICAgICAgKiAgICAgICAgICAgICAgIC8vIGFkZCBzZXZlcmFsIHVzZXJzXG4gICAgICAgICogICAgICAgICAgICAgICB3YS5hZGRVc2VycyhbXG4gICAgICAgICogICAgICAgICAgICAgICAgICAgeyB1c2VySWQ6ICdhNmZlMGMxZS1mNGI4LTRmMDEtOWY1Zi0wMWNjZjRjMmVkNDQnLFxuICAgICAgICAqICAgICAgICAgICAgICAgICAgICAgcm9sZTogJ1ZQIE1hcmtldGluZycgfSxcbiAgICAgICAgKiAgICAgICAgICAgICAgICAgICB7IHVzZXJJZDogJzhmMjYwNGNmLTk2Y2QtNDQ5Zi04MmZhLWUzMzE1MzA3MzRlZScsXG4gICAgICAgICogICAgICAgICAgICAgICAgICAgICByb2xlOiAnVlAgRW5naW5lZXJpbmcnIH1cbiAgICAgICAgKiAgICAgICAgICAgICAgIF0pO1xuICAgICAgICAqXG4gICAgICAgICogICAgICAgICAgICAgICAvLyBhZGQgb25lIHVzZXIgdG8gYSBzcGVjaWZpYyB3b3JsZFxuICAgICAgICAqICAgICAgICAgICAgICAgd2EuYWRkVXNlcnMoJ2IxYzE5ZGRhLTJkMmUtNDc3Ny1hZDVkLTM5MjlmMTdlODZkMycsIHdvcmxkLmlkKTtcbiAgICAgICAgKiAgICAgICAgICAgICAgIHdhLmFkZFVzZXJzKCdiMWMxOWRkYS0yZDJlLTQ3NzctYWQ1ZC0zOTI5ZjE3ZTg2ZDMnLCB7IGZpbHRlcjogd29ybGQuaWQgfSk7XG4gICAgICAgICogICAgICAgICAgIH0pO1xuICAgICAgICAqXG4gICAgICAgICogKiogUGFyYW1ldGVycyAqKlxuICAgICAgICAqIEBwYXJhbSB7c3RyaW5nfG9iamVjdHxhcnJheX0gYHVzZXJzYCBVc2VyIGlkLCBhcnJheSBvZiB1c2VyIGlkcywgb2JqZWN0LCBvciBhcnJheSBvZiBvYmplY3RzIG9mIHRoZSB1c2VycyB0byBhZGQgdG8gdGhpcyB3b3JsZC5cbiAgICAgICAgKiBAcGFyYW0ge3N0cmluZ30gYHVzZXJzLnJvbGVgIFRoZSBgcm9sZWAgdGhlIHVzZXIgc2hvdWxkIGhhdmUgaW4gdGhlIHdvcmxkLiBJdCBpcyB1cCB0byB0aGUgY2FsbGVyIHRvIGVuc3VyZSwgaWYgbmVlZGVkLCB0aGF0IHRoZSBgcm9sZWAgcGFzc2VkIGluIGlzIG9uZSBvZiB0aGUgYHJvbGVzYCBvciBgb3B0aW9uYWxSb2xlc2Agb2YgdGhpcyB3b3JsZC5cbiAgICAgICAgKiBAcGFyYW0ge3N0cmluZ30gYHdvcmxkSWRgIFRoZSB3b3JsZCB0byB3aGljaCB0aGUgdXNlcnMgc2hvdWxkIGJlIGFkZGVkLiBJZiBub3Qgc3BlY2lmaWVkLCB0aGUgZmlsdGVyIHBhcmFtZXRlciBvZiB0aGUgYG9wdGlvbnNgIG9iamVjdCBpcyB1c2VkLlxuICAgICAgICAqIEBwYXJhbSB7b2JqZWN0fSBgb3B0aW9uc2AgKE9wdGlvbmFsKSBPcHRpb25zIG9iamVjdCB0byBvdmVycmlkZSBnbG9iYWwgb3B0aW9ucy5cbiAgICAgICAgKi9cbiAgICAgICAgYWRkVXNlcnM6IGZ1bmN0aW9uICh1c2Vycywgd29ybGRJZCwgb3B0aW9ucykge1xuXG4gICAgICAgICAgICBpZiAoIXVzZXJzKSB7XG4gICAgICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdQbGVhc2UgcHJvdmlkZSBhIGxpc3Qgb2YgdXNlcnMgdG8gYWRkIHRvIHRoZSB3b3JsZCcpO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAvLyBub3JtYWxpemUgdGhlIGxpc3Qgb2YgdXNlcnMgdG8gYW4gYXJyYXkgb2YgdXNlciBvYmplY3RzXG4gICAgICAgICAgICB1c2VycyA9ICQubWFwKFtdLmNvbmNhdCh1c2VycyksIGZ1bmN0aW9uICh1KSB7XG4gICAgICAgICAgICAgICAgdmFyIGlzT2JqZWN0ID0gJC5pc1BsYWluT2JqZWN0KHUpO1xuXG4gICAgICAgICAgICAgICAgaWYgKHR5cGVvZiB1ICE9PSAnc3RyaW5nJyAmJiAhaXNPYmplY3QpIHtcbiAgICAgICAgICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdTb21lIG9mIHRoZSB1c2VycyBpbiB0aGUgbGlzdCBhcmUgbm90IGluIHRoZSB2YWxpZCBmb3JtYXQ6ICcgKyB1KTtcbiAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICByZXR1cm4gaXNPYmplY3QgPyB1IDogeyB1c2VySWQ6IHUgfTtcbiAgICAgICAgICAgIH0pO1xuXG4gICAgICAgICAgICAvLyBjaGVjayBpZiBvcHRpb25zIHdlcmUgcGFzc2VkIGFzIHRoZSBzZWNvbmQgcGFyYW1ldGVyXG4gICAgICAgICAgICBpZiAoJC5pc1BsYWluT2JqZWN0KHdvcmxkSWQpICYmICFvcHRpb25zKSB7XG4gICAgICAgICAgICAgICAgb3B0aW9ucyA9IHdvcmxkSWQ7XG4gICAgICAgICAgICAgICAgd29ybGRJZCA9IG51bGw7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIG9wdGlvbnMgPSBvcHRpb25zIHx8IHt9O1xuXG4gICAgICAgICAgICAvLyB3ZSBtdXN0IGhhdmUgb3B0aW9ucyBieSBub3dcbiAgICAgICAgICAgIGlmICh0eXBlb2Ygd29ybGRJZCA9PT0gJ3N0cmluZycpIHtcbiAgICAgICAgICAgICAgICBvcHRpb25zLmZpbHRlciA9IHdvcmxkSWQ7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIHNldElkRmlsdGVyT3JUaHJvd0Vycm9yKG9wdGlvbnMpO1xuXG4gICAgICAgICAgICB2YXIgdXBkYXRlT3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LFxuICAgICAgICAgICAgICAgIHNlcnZpY2VPcHRpb25zLFxuICAgICAgICAgICAgICAgIG9wdGlvbnMsXG4gICAgICAgICAgICAgICAgeyB1cmw6IHVybENvbmZpZy5nZXRBUElQYXRoKGFwaUVuZHBvaW50KSArIHNlcnZpY2VPcHRpb25zLmZpbHRlciArICcvdXNlcnMnIH1cbiAgICAgICAgICAgICk7XG5cbiAgICAgICAgICAgIHJldHVybiBodHRwLnBvc3QodXNlcnMsIHVwZGF0ZU9wdGlvbnMpO1xuICAgICAgICB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAqIFVwZGF0ZXMgdGhlIHJvbGUgb2YgYW4gZW5kIHVzZXIgaW4gYSBnaXZlbiB3b3JsZC4gKFlvdSBjYW4gb25seSB1cGRhdGUgb25lIGVuZCB1c2VyIGF0IGEgdGltZS4pXG4gICAgICAgICpcbiAgICAgICAgKiAqKkV4YW1wbGUqKlxuICAgICAgICAqXG4gICAgICAgICogICAgICB2YXIgd2EgPSBuZXcgRi5zZXJ2aWNlLldvcmxkKHtcbiAgICAgICAgKiAgICAgICAgICAgYWNjb3VudDogJ2FjbWUtc2ltdWxhdGlvbnMnLFxuICAgICAgICAqICAgICAgICAgICBwcm9qZWN0OiAnc3VwcGx5LWNoYWluLWdhbWUnLFxuICAgICAgICAqICAgICAgICAgICBncm91cDogJ3RlYW0xJyB9KTtcbiAgICAgICAgKlxuICAgICAgICAqICAgICAgd2EuY3JlYXRlKCkudGhlbihmdW5jdGlvbih3b3JsZCkge1xuICAgICAgICAqICAgICAgICAgICB3YS5hZGRVc2VycygnYjFjMTlkZGEtMmQyZS00Nzc3LWFkNWQtMzkyOWYxN2U4NmQzJyk7XG4gICAgICAgICogICAgICAgICAgIHdhLnVwZGF0ZVVzZXIoeyB1c2VySWQ6ICdiMWMxOWRkYS0yZDJlLTQ3NzctYWQ1ZC0zOTI5ZjE3ZTg2ZDMnLCByb2xlOiAnbGVhZGVyJyB9KTtcbiAgICAgICAgKiAgICAgIH0pO1xuICAgICAgICAqXG4gICAgICAgICogKipQYXJhbWV0ZXJzKipcbiAgICAgICAgKiBAcGFyYW0ge29iamVjdH0gYHVzZXJgIFVzZXIgb2JqZWN0IHdpdGggYHVzZXJJZGAgYW5kIHRoZSBuZXcgYHJvbGVgLlxuICAgICAgICAqIEBwYXJhbSB7b2JqZWN0fSBgb3B0aW9uc2AgKE9wdGlvbmFsKSBPcHRpb25zIG9iamVjdCB0byBvdmVycmlkZSBnbG9iYWwgb3B0aW9ucy5cbiAgICAgICAgKlxuICAgICAgICAqL1xuICAgICAgICB1cGRhdGVVc2VyOiBmdW5jdGlvbiAodXNlciwgb3B0aW9ucykge1xuICAgICAgICAgICAgb3B0aW9ucyA9IG9wdGlvbnMgfHwge307XG5cbiAgICAgICAgICAgIGlmICghdXNlciB8fCAhdXNlci51c2VySWQpIHtcbiAgICAgICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ1lvdSBuZWVkIHRvIHBhc3MgYSB1c2VySWQgdG8gdXBkYXRlIGZyb20gdGhlIHdvcmxkJyk7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIHNldElkRmlsdGVyT3JUaHJvd0Vycm9yKG9wdGlvbnMpO1xuXG4gICAgICAgICAgICB2YXIgcGF0Y2hPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sXG4gICAgICAgICAgICAgICAgc2VydmljZU9wdGlvbnMsXG4gICAgICAgICAgICAgICAgb3B0aW9ucyxcbiAgICAgICAgICAgICAgICB7IHVybDogdXJsQ29uZmlnLmdldEFQSVBhdGgoYXBpRW5kcG9pbnQpICsgc2VydmljZU9wdGlvbnMuZmlsdGVyICsgJy91c2Vycy8nICsgdXNlci51c2VySWQgfVxuICAgICAgICAgICAgKTtcblxuICAgICAgICAgICAgcmV0dXJuIGh0dHAucGF0Y2goX3BpY2sodXNlciwgJ3JvbGUnKSwgcGF0Y2hPcHRpb25zKTtcbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgKiBSZW1vdmVzIGFuIGVuZCB1c2VyIGZyb20gYSBnaXZlbiB3b3JsZC5cbiAgICAgICAgKlxuICAgICAgICAqICAqKkV4YW1wbGUqKlxuICAgICAgICAqXG4gICAgICAgICogICAgICB2YXIgd2EgPSBuZXcgRi5zZXJ2aWNlLldvcmxkKHtcbiAgICAgICAgKiAgICAgICAgICAgYWNjb3VudDogJ2FjbWUtc2ltdWxhdGlvbnMnLFxuICAgICAgICAqICAgICAgICAgICBwcm9qZWN0OiAnc3VwcGx5LWNoYWluLWdhbWUnLFxuICAgICAgICAqICAgICAgICAgICBncm91cDogJ3RlYW0xJyB9KTtcbiAgICAgICAgKiAgICAgIHdhLmNyZWF0ZSgpXG4gICAgICAgICogICAgICAgICAgIC50aGVuKGZ1bmN0aW9uKHdvcmxkKSB7XG4gICAgICAgICogICAgICAgICAgICAgICB3YS5hZGRVc2VycyhbJ2E2ZmUwYzFlLWY0YjgtNGYwMS05ZjVmLTAxY2NmNGMyZWQ0NCcsICc4ZjI2MDRjZi05NmNkLTQ0OWYtODJmYS1lMzMxNTMwNzM0ZWUnXSk7XG4gICAgICAgICogICAgICAgICAgICAgICB3YS5yZW1vdmVVc2VyKCdhNmZlMGMxZS1mNGI4LTRmMDEtOWY1Zi0wMWNjZjRjMmVkNDQnKTtcbiAgICAgICAgKiAgICAgICAgICAgICAgIHdhLnJlbW92ZVVzZXIoeyB1c2VySWQ6ICc4ZjI2MDRjZi05NmNkLTQ0OWYtODJmYS1lMzMxNTMwNzM0ZWUnIH0pO1xuICAgICAgICAqICAgICAgICAgICB9KTtcbiAgICAgICAgKlxuICAgICAgICAqICoqIFBhcmFtZXRlcnMgKipcbiAgICAgICAgKiBAcGFyYW0ge29iamVjdHxzdHJpbmd9IGB1c2VyYCBUaGUgYHVzZXJJZGAgb2YgdGhlIHVzZXIgdG8gcmVtb3ZlIGZyb20gdGhlIHdvcmxkLCBvciBhbiBvYmplY3QgY29udGFpbmluZyB0aGUgYHVzZXJJZGAgZmllbGQuXG4gICAgICAgICogQHBhcmFtIHtvYmplY3R9IGBvcHRpb25zYCAoT3B0aW9uYWwpIE9wdGlvbnMgb2JqZWN0IHRvIG92ZXJyaWRlIGdsb2JhbCBvcHRpb25zLlxuICAgICAgICAqL1xuICAgICAgICByZW1vdmVVc2VyOiBmdW5jdGlvbiAodXNlciwgb3B0aW9ucykge1xuICAgICAgICAgICAgb3B0aW9ucyA9IG9wdGlvbnMgfHwge307XG5cbiAgICAgICAgICAgIGlmICh0eXBlb2YgdXNlciA9PT0gJ3N0cmluZycpIHtcbiAgICAgICAgICAgICAgICB1c2VyID0geyB1c2VySWQ6IHVzZXIgfTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgaWYgKCF1c2VyLnVzZXJJZCkge1xuICAgICAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcignWW91IG5lZWQgdG8gcGFzcyBhIHVzZXJJZCB0byByZW1vdmUgZnJvbSB0aGUgd29ybGQnKTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgc2V0SWRGaWx0ZXJPclRocm93RXJyb3Iob3B0aW9ucyk7XG5cbiAgICAgICAgICAgIHZhciBnZXRPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sXG4gICAgICAgICAgICAgICAgc2VydmljZU9wdGlvbnMsXG4gICAgICAgICAgICAgICAgb3B0aW9ucyxcbiAgICAgICAgICAgICAgICB7IHVybDogdXJsQ29uZmlnLmdldEFQSVBhdGgoYXBpRW5kcG9pbnQpICsgc2VydmljZU9wdGlvbnMuZmlsdGVyICsgJy91c2Vycy8nICsgdXNlci51c2VySWQgfVxuICAgICAgICAgICAgKTtcblxuICAgICAgICAgICAgcmV0dXJuIGh0dHAuZGVsZXRlKG51bGwsIGdldE9wdGlvbnMpO1xuICAgICAgICB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAqIEdldHMgdGhlIHJ1biBpZCBvZiBjdXJyZW50IHJ1biBmb3IgdGhlIGdpdmVuIHdvcmxkLiBJZiB0aGUgd29ybGQgZG9lcyBub3QgaGF2ZSBhIHJ1biwgY3JlYXRlcyBhIG5ldyBvbmUgYW5kIHJldHVybnMgdGhlIHJ1biBpZC5cbiAgICAgICAgKlxuICAgICAgICAqIFJlbWVtYmVyIHRoYXQgYSBbcnVuXSguLi8uLi9nbG9zc2FyeS8jcnVuKSBpcyBhIGNvbGxlY3Rpb24gb2YgaW50ZXJhY3Rpb25zIHdpdGggYSBwcm9qZWN0IGFuZCBpdHMgbW9kZWwuIEluIHRoZSBjYXNlIG9mIG11bHRpcGxheWVyIHByb2plY3RzLCB0aGUgcnVuIGlzIHNoYXJlZCBieSBhbGwgZW5kIHVzZXJzIGluIHRoZSB3b3JsZC5cbiAgICAgICAgKlxuICAgICAgICAqICAqKkV4YW1wbGUqKlxuICAgICAgICAqXG4gICAgICAgICogICAgICB2YXIgd2EgPSBuZXcgRi5zZXJ2aWNlLldvcmxkKHtcbiAgICAgICAgKiAgICAgICAgICAgYWNjb3VudDogJ2FjbWUtc2ltdWxhdGlvbnMnLFxuICAgICAgICAqICAgICAgICAgICBwcm9qZWN0OiAnc3VwcGx5LWNoYWluLWdhbWUnLFxuICAgICAgICAqICAgICAgICAgICBncm91cDogJ3RlYW0xJyB9KTtcbiAgICAgICAgKiAgICAgIHdhLmNyZWF0ZSgpXG4gICAgICAgICogICAgICAgICAgIC50aGVuKGZ1bmN0aW9uKHdvcmxkKSB7XG4gICAgICAgICogICAgICAgICAgICAgICB3YS5nZXRDdXJyZW50UnVuSWQoeyBtb2RlbDogJ21vZGVsLnB5JyB9KTtcbiAgICAgICAgKiAgICAgICAgICAgfSk7XG4gICAgICAgICpcbiAgICAgICAgKiAqKiBQYXJhbWV0ZXJzICoqXG4gICAgICAgICogQHBhcmFtIHtvYmplY3R9IGBvcHRpb25zYCAoT3B0aW9uYWwpIE9wdGlvbnMgb2JqZWN0IHRvIG92ZXJyaWRlIGdsb2JhbCBvcHRpb25zLlxuICAgICAgICAqIEBwYXJhbSB7b2JqZWN0fSBgb3B0aW9ucy5tb2RlbGAgVGhlIG1vZGVsIGZpbGUgdG8gdXNlIHRvIGNyZWF0ZSBhIHJ1biBpZiBuZWVkZWQuXG4gICAgICAgICovXG4gICAgICAgIGdldEN1cnJlbnRSdW5JZDogZnVuY3Rpb24gKG9wdGlvbnMpIHtcbiAgICAgICAgICAgIG9wdGlvbnMgPSBvcHRpb25zIHx8IHt9O1xuXG4gICAgICAgICAgICBzZXRJZEZpbHRlck9yVGhyb3dFcnJvcihvcHRpb25zKTtcblxuICAgICAgICAgICAgdmFyIGdldE9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSxcbiAgICAgICAgICAgICAgICBzZXJ2aWNlT3B0aW9ucyxcbiAgICAgICAgICAgICAgICBvcHRpb25zLFxuICAgICAgICAgICAgICAgIHsgdXJsOiB1cmxDb25maWcuZ2V0QVBJUGF0aChhcGlFbmRwb2ludCkgKyBzZXJ2aWNlT3B0aW9ucy5maWx0ZXIgKyAnL3J1bicgfVxuICAgICAgICAgICAgKTtcblxuICAgICAgICAgICAgdmFsaWRhdGVNb2RlbE9yVGhyb3dFcnJvcihnZXRPcHRpb25zKTtcbiAgICAgICAgICAgIHJldHVybiBodHRwLnBvc3QoX3BpY2soZ2V0T3B0aW9ucywgJ21vZGVsJyksIGdldE9wdGlvbnMpO1xuICAgICAgICB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAqIEdldHMgdGhlIGN1cnJlbnQgKG1vc3QgcmVjZW50KSB3b3JsZCBmb3IgdGhlIGdpdmVuIGVuZCB1c2VyIGluIHRoZSBnaXZlbiBncm91cC4gQnJpbmdzIHRoaXMgbW9zdCByZWNlbnQgd29ybGQgaW50byBtZW1vcnkgaWYgbmVlZGVkLlxuICAgICAgICAqXG4gICAgICAgICogICoqRXhhbXBsZSoqXG4gICAgICAgICpcbiAgICAgICAgKiAgICAgIHZhciB3YSA9IG5ldyBGLnNlcnZpY2UuV29ybGQoe1xuICAgICAgICAqICAgICAgICAgICBhY2NvdW50OiAnYWNtZS1zaW11bGF0aW9ucycsXG4gICAgICAgICogICAgICAgICAgIHByb2plY3Q6ICdzdXBwbHktY2hhaW4tZ2FtZScsXG4gICAgICAgICogICAgICAgICAgIGdyb3VwOiAndGVhbTEnIH0pO1xuICAgICAgICAqICAgICAgd2EuZ2V0Q3VycmVudFdvcmxkRm9yVXNlcignOGYyNjA0Y2YtOTZjZC00NDlmLTgyZmEtZTMzMTUzMDczNGVlJylcbiAgICAgICAgKiAgICAgICAgICAgLnRoZW4oZnVuY3Rpb24od29ybGQpIHtcbiAgICAgICAgKiAgICAgICAgICAgICAgIC8vIHVzZSBkYXRhIGZyb20gd29ybGRcbiAgICAgICAgKiAgICAgICAgICAgfSk7XG4gICAgICAgICpcbiAgICAgICAgKiAqKiBQYXJhbWV0ZXJzICoqXG4gICAgICAgICogQHBhcmFtIHtzdHJpbmd9IGB1c2VySWRgIFRoZSBgdXNlcklkYCBvZiB0aGUgdXNlciB3aG9zZSBjdXJyZW50IChtb3N0IHJlY2VudCkgd29ybGQgaXMgYmVpbmcgcmV0cmlldmVkLlxuICAgICAgICAqIEBwYXJhbSB7c3RyaW5nfSBgZ3JvdXBOYW1lYCAoT3B0aW9uYWwpIFRoZSBuYW1lIG9mIHRoZSBncm91cC4gSWYgbm90IHByb3ZpZGVkLCBkZWZhdWx0cyB0byB0aGUgZ3JvdXAgdXNlZCB0byBjcmVhdGUgdGhlIHNlcnZpY2UuXG4gICAgICAgICovXG4gICAgICAgIGdldEN1cnJlbnRXb3JsZEZvclVzZXI6IGZ1bmN0aW9uICh1c2VySWQsIGdyb3VwTmFtZSkge1xuICAgICAgICAgICAgdmFyIGR0ZCA9ICQuRGVmZXJyZWQoKTtcbiAgICAgICAgICAgIHZhciBtZSA9IHRoaXM7XG4gICAgICAgICAgICB0aGlzLmdldFdvcmxkc0ZvclVzZXIodXNlcklkLCB7IGdyb3VwOiBncm91cE5hbWUgfSlcbiAgICAgICAgICAgICAgICAudGhlbihmdW5jdGlvbiAod29ybGRzKSB7XG4gICAgICAgICAgICAgICAgICAgIC8vIGFzc3VtZSB0aGUgbW9zdCByZWNlbnQgd29ybGQgYXMgdGhlICdhY3RpdmUnIHdvcmxkXG4gICAgICAgICAgICAgICAgICAgIHdvcmxkcy5zb3J0KGZ1bmN0aW9uIChhLCBiKSB7IHJldHVybiBuZXcgRGF0ZShiLmxhc3RNb2RpZmllZCkgLSBuZXcgRGF0ZShhLmxhc3RNb2RpZmllZCk7IH0pO1xuICAgICAgICAgICAgICAgICAgICB2YXIgY3VycmVudFdvcmxkID0gd29ybGRzWzBdO1xuXG4gICAgICAgICAgICAgICAgICAgIGlmIChjdXJyZW50V29ybGQpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHNlcnZpY2VPcHRpb25zLmZpbHRlciA9ICBjdXJyZW50V29ybGQuaWQ7XG4gICAgICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgICAgICBkdGQucmVzb2x2ZShjdXJyZW50V29ybGQsIG1lKTtcbiAgICAgICAgICAgICAgICB9KVxuICAgICAgICAgICAgICAgIC5mYWlsKGR0ZC5yZWplY3QpO1xuXG4gICAgICAgICAgICByZXR1cm4gZHRkLnByb21pc2UoKTtcbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgKiBEZWxldGVzIHRoZSBjdXJyZW50IHJ1biBmcm9tIHRoZSB3b3JsZC5cbiAgICAgICAgKlxuICAgICAgICAqIChOb3RlIHRoYXQgdGhlIHdvcmxkIGlkIHJlbWFpbnMgcGFydCBvZiB0aGUgcnVuIHJlY29yZCwgaW5kaWNhdGluZyB0aGF0IHRoZSBydW4gd2FzIGZvcm1lcmx5IGFuIGFjdGl2ZSBydW4gZm9yIHRoZSB3b3JsZC4pXG4gICAgICAgICpcbiAgICAgICAgKiAgKipFeGFtcGxlKipcbiAgICAgICAgKlxuICAgICAgICAqICAgICAgdmFyIHdhID0gbmV3IEYuc2VydmljZS5Xb3JsZCh7XG4gICAgICAgICogICAgICAgICAgIGFjY291bnQ6ICdhY21lLXNpbXVsYXRpb25zJyxcbiAgICAgICAgKiAgICAgICAgICAgcHJvamVjdDogJ3N1cHBseS1jaGFpbi1nYW1lJyxcbiAgICAgICAgKiAgICAgICAgICAgZ3JvdXA6ICd0ZWFtMScgfSk7XG4gICAgICAgICpcbiAgICAgICAgKiAgICAgIHdhLmRlbGV0ZVJ1bignc2FtcGxlLXdvcmxkLWlkJyk7XG4gICAgICAgICpcbiAgICAgICAgKiAgKipQYXJhbWV0ZXJzKipcbiAgICAgICAgKiBAcGFyYW0ge3N0cmluZ30gYHdvcmxkSWRgIFRoZSBgd29ybGRJZGAgb2YgdGhlIHdvcmxkIGZyb20gd2hpY2ggdGhlIGN1cnJlbnQgcnVuIGlzIGJlaW5nIGRlbGV0ZWQuXG4gICAgICAgICogQHBhcmFtIHtvYmplY3R9IGBvcHRpb25zYCAoT3B0aW9uYWwpIE9wdGlvbnMgb2JqZWN0IHRvIG92ZXJyaWRlIGdsb2JhbCBvcHRpb25zLlxuICAgICAgICAqL1xuICAgICAgICBkZWxldGVSdW46IGZ1bmN0aW9uICh3b3JsZElkLCBvcHRpb25zKSB7XG4gICAgICAgICAgICBvcHRpb25zID0gb3B0aW9ucyB8fCB7fTtcblxuICAgICAgICAgICAgaWYgKHdvcmxkSWQpIHtcbiAgICAgICAgICAgICAgICBvcHRpb25zLmZpbHRlciA9IHdvcmxkSWQ7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIHNldElkRmlsdGVyT3JUaHJvd0Vycm9yKG9wdGlvbnMpO1xuXG4gICAgICAgICAgICB2YXIgZGVsZXRlT3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LFxuICAgICAgICAgICAgICAgIHNlcnZpY2VPcHRpb25zLFxuICAgICAgICAgICAgICAgIG9wdGlvbnMsXG4gICAgICAgICAgICAgICAgeyB1cmw6IHVybENvbmZpZy5nZXRBUElQYXRoKGFwaUVuZHBvaW50KSArIHNlcnZpY2VPcHRpb25zLmZpbHRlciArICcvcnVuJyB9XG4gICAgICAgICAgICApO1xuXG4gICAgICAgICAgICByZXR1cm4gaHR0cC5kZWxldGUobnVsbCwgZGVsZXRlT3B0aW9ucyk7XG4gICAgICAgIH0sXG5cbiAgICAgICAgLyoqXG4gICAgICAgICogQ3JlYXRlcyBhIG5ldyBydW4gZm9yIHRoZSB3b3JsZC5cbiAgICAgICAgKlxuICAgICAgICAqICAqKkV4YW1wbGUqKlxuICAgICAgICAqXG4gICAgICAgICogICAgICB2YXIgd2EgPSBuZXcgRi5zZXJ2aWNlLldvcmxkKHtcbiAgICAgICAgKiAgICAgICAgICAgYWNjb3VudDogJ2FjbWUtc2ltdWxhdGlvbnMnLFxuICAgICAgICAqICAgICAgICAgICBwcm9qZWN0OiAnc3VwcGx5LWNoYWluLWdhbWUnLFxuICAgICAgICAqICAgICAgICAgICBncm91cDogJ3RlYW0xJyB9KTtcbiAgICAgICAgKlxuICAgICAgICAqICAgICAgd2EuZ2V0Q3VycmVudFdvcmxkRm9yVXNlcignOGYyNjA0Y2YtOTZjZC00NDlmLTgyZmEtZTMzMTUzMDczNGVlJylcbiAgICAgICAgKiAgICAgICAgICAgLnRoZW4oZnVuY3Rpb24gKHdvcmxkKSB7XG4gICAgICAgICogICAgICAgICAgICAgICAgICAgd2EubmV3UnVuRm9yV29ybGQod29ybGQuaWQpO1xuICAgICAgICAqICAgICAgICAgICB9KTtcbiAgICAgICAgKlxuICAgICAgICAqICAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAqIEBwYXJhbSB7c3RyaW5nfSBgd29ybGRJZGAgd29ybGRJZCBpbiB3aGljaCB3ZSBjcmVhdGUgdGhlIG5ldyBydW4uXG4gICAgICAgICogQHBhcmFtIHtvYmplY3R9IGBvcHRpb25zYCAoT3B0aW9uYWwpIE9wdGlvbnMgb2JqZWN0IHRvIG92ZXJyaWRlIGdsb2JhbCBvcHRpb25zLlxuICAgICAgICAqIEBwYXJhbSB7b2JqZWN0fSBgb3B0aW9ucy5tb2RlbGAgVGhlIG1vZGVsIGZpbGUgdG8gdXNlIHRvIGNyZWF0ZSBhIHJ1biBpZiBuZWVkZWQuXG4gICAgICAgICovXG4gICAgICAgIG5ld1J1bkZvcldvcmxkOiBmdW5jdGlvbiAod29ybGRJZCwgb3B0aW9ucykge1xuICAgICAgICAgICAgdmFyIGN1cnJlbnRSdW5PcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sXG4gICAgICAgICAgICAgICAgb3B0aW9ucyxcbiAgICAgICAgICAgICAgICB7IGZpbHRlcjogd29ybGRJZCB8fCBzZXJ2aWNlT3B0aW9ucy5maWx0ZXIgfVxuICAgICAgICAgICAgKTtcbiAgICAgICAgICAgIHZhciBfdGhpcyA9IHRoaXM7XG5cbiAgICAgICAgICAgIHZhbGlkYXRlTW9kZWxPclRocm93RXJyb3IoY3VycmVudFJ1bk9wdGlvbnMpO1xuXG4gICAgICAgICAgICByZXR1cm4gdGhpcy5kZWxldGVSdW4od29ybGRJZCwgb3B0aW9ucylcbiAgICAgICAgICAgICAgICAudGhlbihmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICAgICAgICAgIHJldHVybiBfdGhpcy5nZXRDdXJyZW50UnVuSWQoY3VycmVudFJ1bk9wdGlvbnMpO1xuICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAqIEFzc2lnbnMgZW5kIHVzZXJzIHRvIHdvcmxkcywgY3JlYXRpbmcgbmV3IHdvcmxkcyBhcyBhcHByb3ByaWF0ZSwgYXV0b21hdGljYWxseS4gQXNzaWducyBhbGwgZW5kIHVzZXJzIGluIHRoZSBncm91cCwgYW5kIGNyZWF0ZXMgbmV3IHdvcmxkcyBhcyBuZWVkZWQgYmFzZWQgb24gdGhlIHByb2plY3QtbGV2ZWwgd29ybGQgY29uZmlndXJhdGlvbiAocm9sZXMsIG9wdGlvbmFsIHJvbGVzLCBhbmQgbWluaW11bSBlbmQgdXNlcnMgcGVyIHdvcmxkKS5cbiAgICAgICAgKlxuICAgICAgICAqICoqRXhhbXBsZSoqXG4gICAgICAgICpcbiAgICAgICAgKiAgICAgIHZhciB3YSA9IG5ldyBGLnNlcnZpY2UuV29ybGQoe1xuICAgICAgICAqICAgICAgICAgICBhY2NvdW50OiAnYWNtZS1zaW11bGF0aW9ucycsXG4gICAgICAgICogICAgICAgICAgIHByb2plY3Q6ICdzdXBwbHktY2hhaW4tZ2FtZScsXG4gICAgICAgICogICAgICAgICAgIGdyb3VwOiAndGVhbTEnIH0pO1xuICAgICAgICAqXG4gICAgICAgICogICAgICB3YS5hdXRvQXNzaWduKCk7XG4gICAgICAgICpcbiAgICAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAqIEBwYXJhbSB7b2JqZWN0fSBgb3B0aW9uc2AgKE9wdGlvbmFsKSBPcHRpb25zIG9iamVjdCB0byBvdmVycmlkZSBnbG9iYWwgb3B0aW9ucy5cbiAgICAgICAgKlxuICAgICAgICAqL1xuICAgICAgICBhdXRvQXNzaWduOiBmdW5jdGlvbiAob3B0aW9ucykge1xuICAgICAgICAgICAgb3B0aW9ucyA9IG9wdGlvbnMgfHwge307XG5cbiAgICAgICAgICAgIHZhciBvcHQgPSAkLmV4dGVuZCh0cnVlLCB7fSxcbiAgICAgICAgICAgICAgICBzZXJ2aWNlT3B0aW9ucyxcbiAgICAgICAgICAgICAgICBvcHRpb25zLFxuICAgICAgICAgICAgICAgIHsgdXJsOiB1cmxDb25maWcuZ2V0QVBJUGF0aChhc3NpZ25tZW50RW5kcG9pbnQpIH1cbiAgICAgICAgICAgICk7XG5cbiAgICAgICAgICAgIHZhciBwYXJhbXMgPSB7XG4gICAgICAgICAgICAgICAgYWNjb3VudDogb3B0LmFjY291bnQsXG4gICAgICAgICAgICAgICAgcHJvamVjdDogb3B0LnByb2plY3QsXG4gICAgICAgICAgICAgICAgZ3JvdXA6IG9wdC5ncm91cFxuICAgICAgICAgICAgfTtcblxuICAgICAgICAgICAgaWYgKG9wdC5tYXhVc2Vycykge1xuICAgICAgICAgICAgICAgIHBhcmFtcy5tYXhVc2VycyA9IG9wdC5tYXhVc2VycztcbiAgICAgICAgfVxuXG4gICAgICAgICAgICByZXR1cm4gaHR0cC5wb3N0KHBhcmFtcywgb3B0KTtcbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgKiBHZXRzIHRoZSBwcm9qZWN0J3Mgd29ybGQgY29uZmlndXJhdGlvbi5cbiAgICAgICAgKlxuICAgICAgICAqIFR5cGljYWxseSwgZXZlcnkgaW50ZXJhY3Rpb24gd2l0aCB5b3VyIHByb2plY3QgdXNlcyB0aGUgc2FtZSBjb25maWd1cmF0aW9uIG9mIGVhY2ggd29ybGQuIEZvciBleGFtcGxlLCBlYWNoIHdvcmxkIGluIHlvdXIgcHJvamVjdCBwcm9iYWJseSBoYXMgdGhlIHNhbWUgcm9sZXMgZm9yIGVuZCB1c2Vycy4gQW5kIHlvdXIgcHJvamVjdCBpcyBwcm9iYWJseSBlaXRoZXIgY29uZmlndXJlZCBzbyB0aGF0IGFsbCBlbmQgdXNlcnMgc2hhcmUgdGhlIHNhbWUgd29ybGQgKGFuZCBydW4pLCBvciBzbWFsbGVyIHNldHMgb2YgZW5kIHVzZXJzIHNoYXJlIHdvcmxkcyDigJQgYnV0IG5vdCBib3RoLlxuICAgICAgICAqXG4gICAgICAgICogKFRoZSBbTXVsdGlwbGF5ZXIgUHJvamVjdCBSRVNUIEFQSV0oLi4vLi4vLi4vcmVzdF9hcGlzL211bHRpcGxheWVyL211bHRpcGxheWVyX3Byb2plY3QvKSBhbGxvd3MgeW91IHRvIHNldCB0aGVzZSBwcm9qZWN0LWxldmVsIHdvcmxkIGNvbmZpZ3VyYXRpb25zLiBUaGUgV29ybGQgQWRhcHRlciBzaW1wbHkgcmV0cmlldmVzIHRoZW0sIGZvciBleGFtcGxlIHNvIHRoZXkgY2FuIGJlIHVzZWQgaW4gYXV0by1hc3NpZ25tZW50IG9mIGVuZCB1c2VycyB0byB3b3JsZHMuKVxuICAgICAgICAqXG4gICAgICAgICogKipFeGFtcGxlKipcbiAgICAgICAgKlxuICAgICAgICAqICAgICAgdmFyIHdhID0gbmV3IEYuc2VydmljZS5Xb3JsZCh7XG4gICAgICAgICogICAgICAgICAgIGFjY291bnQ6ICdhY21lLXNpbXVsYXRpb25zJyxcbiAgICAgICAgKiAgICAgICAgICAgcHJvamVjdDogJ3N1cHBseS1jaGFpbi1nYW1lJyxcbiAgICAgICAgKiAgICAgICAgICAgZ3JvdXA6ICd0ZWFtMScgfSk7XG4gICAgICAgICpcbiAgICAgICAgKiAgICAgIHdhLmdldFByb2plY3RTZXR0aW5ncygpXG4gICAgICAgICogICAgICAgICAgIC50aGVuKGZ1bmN0aW9uKHNldHRpbmdzKSB7XG4gICAgICAgICogICAgICAgICAgICAgICBjb25zb2xlLmxvZyhzZXR0aW5ncy5yb2xlcyk7XG4gICAgICAgICogICAgICAgICAgICAgICBjb25zb2xlLmxvZyhzZXR0aW5ncy5vcHRpb25hbFJvbGVzKTtcbiAgICAgICAgKiAgICAgICAgICAgfSk7XG4gICAgICAgICpcbiAgICAgICAgKiAqKlBhcmFtZXRlcnMqKlxuICAgICAgICAqIEBwYXJhbSB7b2JqZWN0fSBgb3B0aW9uc2AgKE9wdGlvbmFsKSBPcHRpb25zIG9iamVjdCB0byBvdmVycmlkZSBnbG9iYWwgb3B0aW9ucy5cbiAgICAgICAgKi9cbiAgICAgICAgZ2V0UHJvamVjdFNldHRpbmdzOiBmdW5jdGlvbiAob3B0aW9ucykge1xuICAgICAgICAgICAgb3B0aW9ucyA9IG9wdGlvbnMgfHwge307XG5cbiAgICAgICAgICAgIHZhciBvcHQgPSAkLmV4dGVuZCh0cnVlLCB7fSxcbiAgICAgICAgICAgICAgICBzZXJ2aWNlT3B0aW9ucyxcbiAgICAgICAgICAgICAgICBvcHRpb25zLFxuICAgICAgICAgICAgICAgIHsgdXJsOiB1cmxDb25maWcuZ2V0QVBJUGF0aChwcm9qZWN0RW5kcG9pbnQpIH1cbiAgICAgICAgICAgICk7XG5cbiAgICAgICAgICAgIG9wdC51cmwgKz0gW29wdC5hY2NvdW50LCBvcHQucHJvamVjdF0uam9pbignLycpO1xuXG4gICAgICAgICAgICByZXR1cm4gaHR0cC5nZXQobnVsbCwgb3B0KTtcbiAgICAgICAgfVxuXG4gICAgfTtcblxuICAgICQuZXh0ZW5kKHRoaXMsIHB1YmxpY0FQSSk7XG59O1xuIiwiLyoqXG4gKiBAY2xhc3MgQ29va2llIFN0b3JhZ2UgU2VydmljZVxuICpcbiAqIEBleGFtcGxlXG4gKiAgICAgIHZhciBwZW9wbGUgPSByZXF1aXJlKCdjb29raWUtc3RvcmUnKSh7IHJvb3Q6ICdwZW9wbGUnIH0pO1xuICAgICAgICBwZW9wbGVcbiAgICAgICAgICAgIC5zYXZlKHtsYXN0TmFtZTogJ3NtaXRoJyB9KVxuXG4gKi9cblxuXG4ndXNlIHN0cmljdCc7XG5cbi8vIFRoaW4gZG9jdW1lbnQuY29va2llIHdyYXBwZXIgdG8gYWxsb3cgdW5pdCB0ZXN0aW5nXG52YXIgQ29va2llID0gZnVuY3Rpb24gKCkge1xuICAgIHRoaXMuZ2V0ID0gZnVuY3Rpb24gKCkge1xuICAgICAgICByZXR1cm4gZG9jdW1lbnQuY29va2llO1xuICAgIH07XG5cbiAgICB0aGlzLnNldCA9IGZ1bmN0aW9uIChuZXdDb29raWUpIHtcbiAgICAgICAgZG9jdW1lbnQuY29va2llID0gbmV3Q29va2llO1xuICAgIH07XG59O1xuXG5tb2R1bGUuZXhwb3J0cyA9IGZ1bmN0aW9uIChjb25maWcpIHtcbiAgICB2YXIgaG9zdCA9IHdpbmRvdy5sb2NhdGlvbi5ob3N0bmFtZTtcbiAgICB2YXIgZGVmYXVsdHMgPSB7XG4gICAgICAgIC8qKlxuICAgICAgICAgKiBOYW1lIG9mIGNvbGxlY3Rpb25cbiAgICAgICAgICogQHR5cGUgeyBzdHJpbmd9XG4gICAgICAgICAqL1xuICAgICAgICByb290OiAnLycsXG5cbiAgICAgICAgZG9tYWluOiAnLicgKyBob3N0LFxuICAgICAgICBjb29raWU6IG5ldyBDb29raWUoKVxuICAgIH07XG4gICAgdGhpcy5zZXJ2aWNlT3B0aW9ucyA9ICQuZXh0ZW5kKHt9LCBkZWZhdWx0cywgY29uZmlnKTtcblxuICAgIHZhciBwdWJsaWNBUEkgPSB7XG4gICAgICAgIC8vICogVEJEXG4gICAgICAgIC8vICAqIFF1ZXJ5IGNvbGxlY3Rpb247IHVzZXMgTW9uZ29EQiBzeW50YXhcbiAgICAgICAgLy8gICogQHNlZSAgPFRCRDogRGF0YSBBUEkgVVJMPlxuICAgICAgICAvLyAgKlxuICAgICAgICAvLyAgKiBAcGFyYW0geyBzdHJpbmd9IHFzIFF1ZXJ5IEZpbHRlclxuICAgICAgICAvLyAgKiBAcGFyYW0geyBzdHJpbmd9IGxpbWl0ZXJzIEBzZWUgPFRCRDogdXJsIGZvciBsaW1pdHMsIHBhZ2luZyBldGM+XG4gICAgICAgIC8vICAqXG4gICAgICAgIC8vICAqIEBleGFtcGxlXG4gICAgICAgIC8vICAqICAgICBjcy5xdWVyeShcbiAgICAgICAgLy8gICogICAgICB7IG5hbWU6ICdKb2huJywgY2xhc3NOYW1lOiAnQ1NDMTAxJyB9LFxuICAgICAgICAvLyAgKiAgICAgIHtsaW1pdDogMTB9XG4gICAgICAgIC8vICAqICAgICApXG5cbiAgICAgICAgLy8gcXVlcnk6IGZ1bmN0aW9uIChxcywgbGltaXRlcnMpIHtcblxuICAgICAgICAvLyB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBTYXZlIGNvb2tpZSB2YWx1ZVxuICAgICAgICAgKiBAcGFyYW0gIHsgc3RyaW5nfE9iamVjdH0ga2V5ICAgSWYgZ2l2ZW4gYSBrZXkgc2F2ZSB2YWx1ZXMgdW5kZXIgaXQsIGlmIGdpdmVuIGFuIG9iamVjdCBkaXJlY3RseSwgc2F2ZSB0byB0b3AtbGV2ZWwgYXBpXG4gICAgICAgICAqIEBwYXJhbSAge09iamVjdH0gdmFsdWUgKE9wdGlvbmFsKVxuICAgICAgICAgKiBAcGFyYW0ge09iamVjdH0gb3B0aW9ucyBPdmVycmlkZXMgZm9yIHNlcnZpY2Ugb3B0aW9uc1xuICAgICAgICAgKlxuICAgICAgICAgKiBAcmV0dXJuIHsqfSBUaGUgc2F2ZWQgdmFsdWVcbiAgICAgICAgICpcbiAgICAgICAgICogQGV4YW1wbGVcbiAgICAgICAgICogICAgIGNzLnNldCgncGVyc29uJywgeyBmaXJzdE5hbWU6ICdqb2huJywgbGFzdE5hbWU6ICdzbWl0aCcgfSk7XG4gICAgICAgICAqICAgICBjcy5zZXQoeyBuYW1lOidzbWl0aCcsIGFnZTonMzInIH0pO1xuICAgICAgICAgKi9cbiAgICAgICAgc2V0OiBmdW5jdGlvbiAoa2V5LCB2YWx1ZSwgb3B0aW9ucykge1xuICAgICAgICAgICAgdmFyIHNldE9wdGlvbnMgPSAkLmV4dGVuZCh0cnVlLCB7fSwgdGhpcy5zZXJ2aWNlT3B0aW9ucywgb3B0aW9ucyk7XG5cbiAgICAgICAgICAgIHZhciBkb21haW4gPSBzZXRPcHRpb25zLmRvbWFpbjtcbiAgICAgICAgICAgIHZhciBwYXRoID0gc2V0T3B0aW9ucy5yb290O1xuICAgICAgICAgICAgdmFyIGNvb2tpZSA9IHNldE9wdGlvbnMuY29va2llO1xuXG4gICAgICAgICAgICBjb29raWUuc2V0KGVuY29kZVVSSUNvbXBvbmVudChrZXkpICsgJz0nICtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZW5jb2RlVVJJQ29tcG9uZW50KHZhbHVlKSArXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIChkb21haW4gPyAnOyBkb21haW49JyArIGRvbWFpbiA6ICcnKSArXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIChwYXRoID8gJzsgcGF0aD0nICsgcGF0aCA6ICcnKVxuICAgICAgICAgICAgKTtcblxuICAgICAgICAgICAgcmV0dXJuIHZhbHVlO1xuICAgICAgICB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBMb2FkIGNvb2tpZSB2YWx1ZVxuICAgICAgICAgKiBAcGFyYW0gIHsgc3RyaW5nfE9iamVjdH0ga2V5ICAgSWYgZ2l2ZW4gYSBrZXkgc2F2ZSB2YWx1ZXMgdW5kZXIgaXQsIGlmIGdpdmVuIGFuIG9iamVjdCBkaXJlY3RseSwgc2F2ZSB0byB0b3AtbGV2ZWwgYXBpXG4gICAgICAgICAqIEByZXR1cm4geyp9IFRoZSB2YWx1ZSBzdG9yZWRcbiAgICAgICAgICpcbiAgICAgICAgICogQGV4YW1wbGVcbiAgICAgICAgICogICAgIGNzLmdldCgncGVyc29uJyk7XG4gICAgICAgICAqL1xuICAgICAgICBnZXQ6IGZ1bmN0aW9uIChrZXkpIHtcbiAgICAgICAgICAgIHZhciBjb29raWUgPSB0aGlzLnNlcnZpY2VPcHRpb25zLmNvb2tpZTtcbiAgICAgICAgICAgIHZhciBjb29raWVSZWcgPSBuZXcgUmVnRXhwKCcoPzpefDspXFxcXHMqJyArIGVuY29kZVVSSUNvbXBvbmVudChrZXkpLnJlcGxhY2UoL1tcXC1cXC5cXCtcXCpdL2csICdcXFxcJCYnKSArICdcXFxccypcXFxcPVxcXFxzKihbXjtdKikuKiQnKTtcbiAgICAgICAgICAgIHZhciByZXMgPSBjb29raWVSZWcuZXhlYyhjb29raWUuZ2V0KCkpO1xuICAgICAgICAgICAgdmFyIHZhbCA9IHJlcyA/IGRlY29kZVVSSUNvbXBvbmVudChyZXNbMV0pIDogbnVsbDtcbiAgICAgICAgICAgIHJldHVybiB2YWw7XG4gICAgICAgIH0sXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIFJlbW92ZXMga2V5IGZyb20gY29sbGVjdGlvblxuICAgICAgICAgKiBAcGFyYW0geyBzdHJpbmd9IGtleSBrZXkgdG8gcmVtb3ZlXG4gICAgICAgICAqIEByZXR1cm4geyBzdHJpbmd9IGtleSBUaGUga2V5IHJlbW92ZWRcbiAgICAgICAgICpcbiAgICAgICAgICogQGV4YW1wbGVcbiAgICAgICAgICogICAgIGNzLnJlbW92ZSgncGVyc29uJyk7XG4gICAgICAgICAqL1xuICAgICAgICByZW1vdmU6IGZ1bmN0aW9uIChrZXksIG9wdGlvbnMpIHtcbiAgICAgICAgICAgIHZhciByZW1PcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sIHRoaXMuc2VydmljZU9wdGlvbnMsIG9wdGlvbnMpO1xuXG4gICAgICAgICAgICB2YXIgZG9tYWluID0gcmVtT3B0aW9ucy5kb21haW47XG4gICAgICAgICAgICB2YXIgcGF0aCA9IHJlbU9wdGlvbnMucm9vdDtcbiAgICAgICAgICAgIHZhciBjb29raWUgPSByZW1PcHRpb25zLmNvb2tpZTtcblxuICAgICAgICAgICAgY29va2llLnNldChlbmNvZGVVUklDb21wb25lbnQoa2V5KSArXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgJz07IGV4cGlyZXM9VGh1LCAwMSBKYW4gMTk3MCAwMDowMDowMCBHTVQnICtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAoZG9tYWluID8gJzsgZG9tYWluPScgKyBkb21haW4gOiAnJykgK1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIChwYXRoID8gJzsgcGF0aD0nICsgcGF0aCA6ICcnKVxuICAgICAgICAgICAgKTtcbiAgICAgICAgICAgIHJldHVybiBrZXk7XG4gICAgICAgIH0sXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIFJlbW92ZXMgY29sbGVjdGlvbiBiZWluZyByZWZlcmVuY2VkXG4gICAgICAgICAqIEByZXR1cm4geyBhcnJheX0ga2V5cyBBbGwgdGhlIGtleXMgcmVtb3ZlZFxuICAgICAgICAgKi9cbiAgICAgICAgZGVzdHJveTogZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgdmFyIGNvb2tpZSA9IHRoaXMuc2VydmljZU9wdGlvbnMuY29va2llO1xuICAgICAgICAgICAgdmFyIGFLZXlzID0gY29va2llLmdldCgpLnJlcGxhY2UoLygoPzpefFxccyo7KVteXFw9XSspKD89O3wkKXxeXFxzKnxcXHMqKD86XFw9W147XSopPyg/OlxcMXwkKS9nLCAnJykuc3BsaXQoL1xccyooPzpcXD1bXjtdKik/O1xccyovKTtcbiAgICAgICAgICAgIGZvciAodmFyIG5JZHggPSAwOyBuSWR4IDwgYUtleXMubGVuZ3RoOyBuSWR4KyspIHtcbiAgICAgICAgICAgICAgICB2YXIgY29va2llS2V5ID0gZGVjb2RlVVJJQ29tcG9uZW50KGFLZXlzW25JZHhdKTtcbiAgICAgICAgICAgICAgICB0aGlzLnJlbW92ZShjb29raWVLZXkpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgcmV0dXJuIGFLZXlzO1xuICAgICAgICB9XG4gICAgfTtcblxuICAgICQuZXh0ZW5kKHRoaXMsIHB1YmxpY0FQSSk7XG59O1xuIiwiJ3VzZSBzdHJpY3QnO1xuXG52YXIga2V5TmFtZXMgPSByZXF1aXJlKCcuLi9tYW5hZ2Vycy9rZXktbmFtZXMnKTtcbnZhciBTdG9yYWdlRmFjdG9yeSA9IHJlcXVpcmUoJy4vc3RvcmUtZmFjdG9yeScpO1xudmFyIG9wdGlvblV0aWxzID0gcmVxdWlyZSgnLi4vdXRpbC9vcHRpb24tdXRpbHMnKTtcblxudmFyIEVQSV9TRVNTSU9OX0tFWSA9IGtleU5hbWVzLkVQSV9TRVNTSU9OX0tFWTtcbnZhciBkZWZhdWx0cyA9IHtcbiAgICAvKipcbiAgICAgKiBXaGVyZSB0byBzdG9yZSB1c2VyIGFjY2VzcyB0b2tlbnMgZm9yIHRlbXBvcmFyeSBhY2Nlc3MuIERlZmF1bHRzIHRvIHN0b3JpbmcgaW4gYSBjb29raWUgaW4gdGhlIGJyb3dzZXIuXG4gICAgICogQHR5cGUge3N0cmluZ31cbiAgICAgKi9cbiAgICBzdG9yZTogeyBzeW5jaHJvbm91czogdHJ1ZSB9XG59O1xuXG52YXIgU2Vzc2lvbk1hbmFnZXIgPSBmdW5jdGlvbiAobWFuYWdlck9wdGlvbnMpIHtcbiAgICBtYW5hZ2VyT3B0aW9ucyA9IG1hbmFnZXJPcHRpb25zIHx8IHt9O1xuICAgIGZ1bmN0aW9uIGdldEJhc2VPcHRpb25zKG92ZXJyaWRlcykge1xuICAgICAgICBvdmVycmlkZXMgPSBvdmVycmlkZXMgfHwge307XG4gICAgICAgIHZhciBsaWJPcHRpb25zID0gb3B0aW9uVXRpbHMuZ2V0T3B0aW9ucygpO1xuICAgICAgICB2YXIgZmluYWxPcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sIGRlZmF1bHRzLCBsaWJPcHRpb25zLCBtYW5hZ2VyT3B0aW9ucywgb3ZlcnJpZGVzKTtcbiAgICAgICAgcmV0dXJuIGZpbmFsT3B0aW9ucztcbiAgICB9XG5cbiAgICBmdW5jdGlvbiBnZXRTdG9yZShvdmVycmlkZXMpIHtcbiAgICAgICAgdmFyIGJhc2VPcHRpb25zID0gZ2V0QmFzZU9wdGlvbnMob3ZlcnJpZGVzKTtcbiAgICAgICAgdmFyIHN0b3JlT3B0cyA9IGJhc2VPcHRpb25zLnN0b3JlIHx8IHt9O1xuICAgICAgICBpZiAoc3RvcmVPcHRzLnJvb3QgPT09IHVuZGVmaW5lZCAmJiBiYXNlT3B0aW9ucy5hY2NvdW50ICYmIGJhc2VPcHRpb25zLnByb2plY3QgJiYgIWJhc2VPcHRpb25zLmlzTG9jYWwpIHtcbiAgICAgICAgICAgIHN0b3JlT3B0cy5yb290ID0gJy9hcHAvJyArIGJhc2VPcHRpb25zLmFjY291bnQgKyAnLycgKyBiYXNlT3B0aW9ucy5wcm9qZWN0O1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiBuZXcgU3RvcmFnZUZhY3Rvcnkoc3RvcmVPcHRzKTtcbiAgICB9XG5cbiAgICB2YXIgcHVibGljQVBJID0ge1xuICAgICAgICBzYXZlU2Vzc2lvbjogZnVuY3Rpb24gKHVzZXJJbmZvLCBvcHRpb25zKSB7XG4gICAgICAgICAgICB2YXIgc2VyaWFsaXplZCA9IEpTT04uc3RyaW5naWZ5KHVzZXJJbmZvKTtcbiAgICAgICAgICAgIGdldFN0b3JlKG9wdGlvbnMpLnNldChFUElfU0VTU0lPTl9LRVksIHNlcmlhbGl6ZWQpO1xuICAgICAgICB9LFxuICAgICAgICBnZXRTZXNzaW9uOiBmdW5jdGlvbiAob3B0aW9ucykge1xuICAgICAgICAgICAgLy8gdmFyIHNlc3Npb24gPSBnZXRTdG9yZShvcHRpb25zKS5nZXQoRVBJX1NFU1NJT05fS0VZKSB8fCAne30nO1xuICAgICAgICAgICAgLy8gcmV0dXJuIEpTT04ucGFyc2Uoc2Vzc2lvbik7XG4gICAgICAgICAgICB2YXIgc3RvcmUgPSBnZXRTdG9yZShvcHRpb25zKTtcbiAgICAgICAgICAgIHZhciBmaW5hbE9wdHMgPSBzdG9yZS5zZXJ2aWNlT3B0aW9ucztcbiAgICAgICAgICAgIHZhciBzZXJpYWxpemVkID0gc3RvcmUuZ2V0KEVQSV9TRVNTSU9OX0tFWSkgfHwgJ3t9JztcbiAgICAgICAgICAgIHZhciBzZXNzaW9uID0gSlNPTi5wYXJzZShzZXJpYWxpemVkKTtcbiAgICAgICAgICAgIC8vIElmIHRoZSB1cmwgY29udGFpbnMgdGhlIHByb2plY3QgYW5kIGFjY291bnRcbiAgICAgICAgICAgIC8vIHZhbGlkYXRlIHRoZSBhY2NvdW50IGFuZCBwcm9qZWN0IGluIHRoZSBzZXNzaW9uXG4gICAgICAgICAgICAvLyBhbmQgb3ZlcnJpZGUgcHJvamVjdCwgZ3JvdXBOYW1lLCBncm91cElkIGFuZCBpc0ZhY1xuICAgICAgICAgICAgLy8gT3RoZXJ3aXNlIChpLmUuIGxvY2FsaG9zdCkgdXNlIHRoZSBzYXZlZCBzZXNzaW9uIHZhbHVlc1xuICAgICAgICAgICAgdmFyIGFjY291bnQgPSBmaW5hbE9wdHMuYWNjb3VudDtcbiAgICAgICAgICAgIHZhciBwcm9qZWN0ID0gZmluYWxPcHRzLnByb2plY3Q7XG4gICAgICAgICAgICBpZiAoYWNjb3VudCAmJiBzZXNzaW9uLmFjY291bnQgIT09IGFjY291bnQpIHtcbiAgICAgICAgICAgICAgICAvLyBUaGlzIG1lYW5zIHRoYXQgdGhlIHRva2VuIHdhcyBub3QgdXNlZCB0byBsb2dpbiB0byB0aGUgc2FtZSBhY2NvdW50XG4gICAgICAgICAgICAgICAgcmV0dXJuIHt9O1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgaWYgKHNlc3Npb24uZ3JvdXBzICYmIGFjY291bnQgJiYgcHJvamVjdCkge1xuICAgICAgICAgICAgICAgIHZhciBncm91cCA9IHNlc3Npb24uZ3JvdXBzW3Byb2plY3RdIHx8IHsgZ3JvdXBJZDogJycsIGdyb3VwTmFtZTogJycsIGlzRmFjOiBmYWxzZSB9O1xuICAgICAgICAgICAgICAgICQuZXh0ZW5kKHNlc3Npb24sIHsgcHJvamVjdDogcHJvamVjdCB9LCBncm91cCk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICByZXR1cm4gc2Vzc2lvbjtcbiAgICAgICAgfSxcbiAgICAgICAgcmVtb3ZlU2Vzc2lvbjogZnVuY3Rpb24gKG9wdGlvbnMpIHtcbiAgICAgICAgICAgIHJldHVybiBnZXRTdG9yZShvcHRpb25zKS5yZW1vdmUoRVBJX1NFU1NJT05fS0VZKTtcbiAgICAgICAgfSxcbiAgICAgICAgZ2V0U3RvcmU6IGZ1bmN0aW9uIChvcHRpb25zKSB7XG4gICAgICAgICAgICByZXR1cm4gZ2V0U3RvcmUob3B0aW9ucyk7XG4gICAgICAgIH0sXG5cbiAgICAgICAgZ2V0TWVyZ2VkT3B0aW9uczogZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgdmFyIGFyZ3MgPSBBcnJheS5wcm90b3R5cGUuc2xpY2UuY2FsbChhcmd1bWVudHMpO1xuICAgICAgICAgICAgdmFyIG92ZXJyaWRlcyA9ICQuZXh0ZW5kLmFwcGx5KCQsIFt0cnVlLCB7fV0uY29uY2F0KGFyZ3MpKTtcbiAgICAgICAgICAgIHZhciBiYXNlT3B0aW9ucyA9IGdldEJhc2VPcHRpb25zKG92ZXJyaWRlcyk7XG4gICAgICAgICAgICB2YXIgc2Vzc2lvbiA9IHRoaXMuZ2V0U2Vzc2lvbihvdmVycmlkZXMpO1xuXG4gICAgICAgICAgICB2YXIgc2Vzc2lvbkRlZmF1bHRzID0ge1xuICAgICAgICAgICAgICAgIC8qKlxuICAgICAgICAgICAgICAgICAqIEZvciBwcm9qZWN0cyB0aGF0IHJlcXVpcmUgYXV0aGVudGljYXRpb24sIHBhc3MgaW4gdGhlIHVzZXIgYWNjZXNzIHRva2VuIChkZWZhdWx0cyB0byBlbXB0eSBzdHJpbmcpLiBJZiB0aGUgdXNlciBpcyBhbHJlYWR5IGxvZ2dlZCBpbiB0byBFcGljZW50ZXIsIHRoZSB1c2VyIGFjY2VzcyB0b2tlbiBpcyBhbHJlYWR5IHNldCBpbiBhIGNvb2tpZSBhbmQgYXV0b21hdGljYWxseSBsb2FkZWQgZnJvbSB0aGVyZS4gKFNlZSBbbW9yZSBiYWNrZ3JvdW5kIG9uIGFjY2VzcyB0b2tlbnNdKC4uLy4uLy4uL3Byb2plY3RfYWNjZXNzLykpLlxuICAgICAgICAgICAgICAgICAqIEBzZWUgW0F1dGhlbnRpY2F0aW9uIEFQSSBTZXJ2aWNlXSguLi9hdXRoLWFwaS1zZXJ2aWNlLykgZm9yIGdldHRpbmcgdG9rZW5zLlxuICAgICAgICAgICAgICAgICAqIEB0eXBlIHtTdHJpbmd9XG4gICAgICAgICAgICAgICAgICovXG4gICAgICAgICAgICAgICAgLy9qc2hpbnQgY2FtZWxjYXNlOiBmYWxzZVxuICAgICAgICAgICAgICAgIC8vanNjczpkaXNhYmxlXG4gICAgICAgICAgICAgICAgdG9rZW46IHNlc3Npb24uYXV0aF90b2tlbixcbiAgICAgICAgICAgICAgICAvKipcbiAgICAgICAgICAgICAgICAgKiBUaGUgZ3JvdXAgbmFtZS4gSWYgbGVmdCB1bmRlZmluZWQsIHRha2VuIGZyb20gdGhlIGNvb2tpZSBzZXNzaW9uLlxuICAgICAgICAgICAgICAgICAqIEB0eXBlIHtTdHJpbmd9XG4gICAgICAgICAgICAgICAgICovXG4gICAgICAgICAgICAgICAgZ3JvdXA6IHNlc3Npb24uZ3JvdXBOYW1lLFxuICAgICAgICAgICAgICAgIC8qKlxuICAgICAgICAgICAgICAgICAqIFRoZSBncm91cCBpZC4gSWYgbGVmdCB1bmRlZmluZWQsIHRha2VuIGZyb20gdGhlIGNvb2tpZSBzZXNzaW9uLlxuICAgICAgICAgICAgICAgICAqIEB0eXBlIHtTdHJpbmd9XG4gICAgICAgICAgICAgICAgICovXG4gICAgICAgICAgICAgICAgZ3JvdXBJZDogc2Vzc2lvbi5ncm91cElkLFxuICAgICAgICAgICAgICAgIHVzZXJJZDogc2Vzc2lvbi51c2VySWRcbiAgICAgICAgICAgIH07XG4gICAgICAgICAgICByZXR1cm4gJC5leHRlbmQodHJ1ZSwgc2Vzc2lvbkRlZmF1bHRzLCBiYXNlT3B0aW9ucyk7XG4gICAgICAgIH1cbiAgICB9O1xuICAgICQuZXh0ZW5kKHRoaXMsIHB1YmxpY0FQSSk7XG59O1xuXG5tb2R1bGUuZXhwb3J0cyA9IFNlc3Npb25NYW5hZ2VyOyIsIi8qKlxuICAgIERlY2lkZXMgdHlwZSBvZiBzdG9yZSB0byBwcm92aWRlXG4qL1xuXG4ndXNlIHN0cmljdCc7XG4vLyB2YXIgaXNOb2RlID0gZmFsc2U7IEZJWE1FOiBCcm93c2VyaWZ5L21pbmlmeWlmeSBoYXMgaXNzdWVzIHdpdGggdGhlIG5leHQgbGlua1xuLy8gdmFyIHN0b3JlID0gKGlzTm9kZSkgPyByZXF1aXJlKCcuL3Nlc3Npb24tc3RvcmUnKSA6IHJlcXVpcmUoJy4vY29va2llLXN0b3JlJyk7XG52YXIgc3RvcmUgPSByZXF1aXJlKCcuL2Nvb2tpZS1zdG9yZScpO1xuXG5tb2R1bGUuZXhwb3J0cyA9IHN0b3JlO1xuIiwiJ3VzZSBzdHJpY3QnO1xuXG52YXIgcXV0aWxzID0gcmVxdWlyZSgnLi4vdXRpbC9xdWVyeS11dGlsJyk7XG5cbm1vZHVsZS5leHBvcnRzID0gZnVuY3Rpb24gKGNvbmZpZykge1xuXG4gICAgdmFyIGRlZmF1bHRzID0ge1xuICAgICAgICB1cmw6ICcnLFxuXG4gICAgICAgIGNvbnRlbnRUeXBlOiAnYXBwbGljYXRpb24vanNvbicsXG4gICAgICAgIGhlYWRlcnM6IHt9LFxuICAgICAgICBzdGF0dXNDb2RlOiB7XG4gICAgICAgICAgICA0MDQ6ICQubm9vcFxuICAgICAgICB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBPTkxZIGZvciBzdHJpbmdzIGluIHRoZSB1cmwuIEFsbCBHRVQgJiBERUxFVEUgcGFyYW1zIGFyZSBydW4gdGhyb3VnaCB0aGlzXG4gICAgICAgICAqIEB0eXBlIHtbdHlwZV0gfVxuICAgICAgICAgKi9cbiAgICAgICAgcGFyYW1ldGVyUGFyc2VyOiBxdXRpbHMudG9RdWVyeUZvcm1hdCxcblxuICAgICAgICAvLyBUbyBhbGxvdyBlcGljZW50ZXIudG9rZW4gYW5kIG90aGVyIHNlc3Npb24gY29va2llcyB0byBiZSBwYXNzZWRcbiAgICAgICAgLy8gd2l0aCB0aGUgcmVxdWVzdHNcbiAgICAgICAgeGhyRmllbGRzOiB7XG4gICAgICAgICAgICB3aXRoQ3JlZGVudGlhbHM6IHRydWVcbiAgICAgICAgfVxuICAgIH07XG5cbiAgICB2YXIgdHJhbnNwb3J0T3B0aW9ucyA9ICQuZXh0ZW5kKHt9LCBkZWZhdWx0cywgY29uZmlnKTtcblxuICAgIHZhciByZXN1bHQgPSBmdW5jdGlvbiAoZCkge1xuICAgICAgICByZXR1cm4gKCQuaXNGdW5jdGlvbihkKSkgPyBkKCkgOiBkO1xuICAgIH07XG5cbiAgICB2YXIgY29ubmVjdCA9IGZ1bmN0aW9uIChtZXRob2QsIHBhcmFtcywgY29ubmVjdE9wdGlvbnMpIHtcbiAgICAgICAgcGFyYW1zID0gcmVzdWx0KHBhcmFtcyk7XG4gICAgICAgIHBhcmFtcyA9ICgkLmlzUGxhaW5PYmplY3QocGFyYW1zKSB8fCAkLmlzQXJyYXkocGFyYW1zKSkgPyBKU09OLnN0cmluZ2lmeShwYXJhbXMpIDogcGFyYW1zO1xuXG4gICAgICAgIHZhciBvcHRpb25zID0gJC5leHRlbmQodHJ1ZSwge30sIHRyYW5zcG9ydE9wdGlvbnMsIGNvbm5lY3RPcHRpb25zLCB7XG4gICAgICAgICAgICB0eXBlOiBtZXRob2QsXG4gICAgICAgICAgICBkYXRhOiBwYXJhbXNcbiAgICAgICAgfSk7XG4gICAgICAgIHZhciBBTExPV0VEX1RPX0JFX0ZVTkNUSU9OUyA9IFsnZGF0YScsICd1cmwnXTtcbiAgICAgICAgJC5lYWNoKG9wdGlvbnMsIGZ1bmN0aW9uIChrZXksIHZhbHVlKSB7XG4gICAgICAgICAgICBpZiAoJC5pc0Z1bmN0aW9uKHZhbHVlKSAmJiAkLmluQXJyYXkoa2V5LCBBTExPV0VEX1RPX0JFX0ZVTkNUSU9OUykgIT09IC0xKSB7XG4gICAgICAgICAgICAgICAgb3B0aW9uc1trZXldID0gdmFsdWUoKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfSk7XG5cbiAgICAgICAgaWYgKG9wdGlvbnMubG9nTGV2ZWwgJiYgb3B0aW9ucy5sb2dMZXZlbCA9PT0gJ0RFQlVHJykge1xuICAgICAgICAgICAgY29uc29sZS5sb2cob3B0aW9ucy51cmwpO1xuICAgICAgICAgICAgdmFyIG9sZFN1Y2Nlc3NGbiA9IG9wdGlvbnMuc3VjY2VzcyB8fCAkLm5vb3A7XG4gICAgICAgICAgICBvcHRpb25zLnN1Y2Nlc3MgPSBmdW5jdGlvbiAocmVzcG9uc2UsIGFqYXhTdGF0dXMsIGFqYXhSZXEpIHtcbiAgICAgICAgICAgICAgICBjb25zb2xlLmxvZyhyZXNwb25zZSk7XG4gICAgICAgICAgICAgICAgb2xkU3VjY2Vzc0ZuLmFwcGx5KHRoaXMsIGFyZ3VtZW50cyk7XG4gICAgICAgICAgICB9O1xuICAgICAgICB9XG5cbiAgICAgICAgdmFyIGJlZm9yZVNlbmQgPSBvcHRpb25zLmJlZm9yZVNlbmQ7XG4gICAgICAgIG9wdGlvbnMuYmVmb3JlU2VuZCA9IGZ1bmN0aW9uICh4aHIsIHNldHRpbmdzKSB7XG4gICAgICAgICAgICB4aHIucmVxdWVzdFVybCA9IChjb25uZWN0T3B0aW9ucyB8fCB7fSkudXJsO1xuICAgICAgICAgICAgaWYgKGJlZm9yZVNlbmQpIHtcbiAgICAgICAgICAgICAgICBiZWZvcmVTZW5kLmFwcGx5KHRoaXMsIGFyZ3VtZW50cyk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH07XG5cbiAgICAgICAgcmV0dXJuICQuYWpheChvcHRpb25zKTtcbiAgICB9O1xuXG4gICAgdmFyIHB1YmxpY0FQSSA9IHtcbiAgICAgICAgZ2V0OmZ1bmN0aW9uIChwYXJhbXMsIGFqYXhPcHRpb25zKSB7XG4gICAgICAgICAgICB2YXIgb3B0aW9ucyA9ICQuZXh0ZW5kKHt9LCB0cmFuc3BvcnRPcHRpb25zLCBhamF4T3B0aW9ucyk7XG4gICAgICAgICAgICBwYXJhbXMgPSBvcHRpb25zLnBhcmFtZXRlclBhcnNlcihyZXN1bHQocGFyYW1zKSk7XG4gICAgICAgICAgICByZXR1cm4gY29ubmVjdC5jYWxsKHRoaXMsICdHRVQnLCBwYXJhbXMsIG9wdGlvbnMpO1xuICAgICAgICB9LFxuICAgICAgICBzcGxpdEdldDogZnVuY3Rpb24gKCkge1xuXG4gICAgICAgIH0sXG4gICAgICAgIHBvc3Q6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIHJldHVybiBjb25uZWN0LmFwcGx5KHRoaXMsIFsncG9zdCddLmNvbmNhdChbXS5zbGljZS5jYWxsKGFyZ3VtZW50cykpKTtcbiAgICAgICAgfSxcbiAgICAgICAgcGF0Y2g6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIHJldHVybiBjb25uZWN0LmFwcGx5KHRoaXMsIFsncGF0Y2gnXS5jb25jYXQoW10uc2xpY2UuY2FsbChhcmd1bWVudHMpKSk7XG4gICAgICAgIH0sXG4gICAgICAgIHB1dDogZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgcmV0dXJuIGNvbm5lY3QuYXBwbHkodGhpcywgWydwdXQnXS5jb25jYXQoW10uc2xpY2UuY2FsbChhcmd1bWVudHMpKSk7XG4gICAgICAgIH0sXG4gICAgICAgIGRlbGV0ZTogZnVuY3Rpb24gKHBhcmFtcywgYWpheE9wdGlvbnMpIHtcbiAgICAgICAgICAgIC8vREVMRVRFIGRvZXNuJ3Qgc3VwcG9ydCBib2R5IHBhcmFtcywgYnV0IGpRdWVyeSB0aGlua3MgaXQgZG9lcy5cbiAgICAgICAgICAgIHZhciBvcHRpb25zID0gJC5leHRlbmQoe30sIHRyYW5zcG9ydE9wdGlvbnMsIGFqYXhPcHRpb25zKTtcbiAgICAgICAgICAgIHBhcmFtcyA9IG9wdGlvbnMucGFyYW1ldGVyUGFyc2VyKHJlc3VsdChwYXJhbXMpKTtcbiAgICAgICAgICAgIGlmICgkLnRyaW0ocGFyYW1zKSkge1xuICAgICAgICAgICAgICAgIHZhciBkZWxpbWl0ZXIgPSAocmVzdWx0KG9wdGlvbnMudXJsKS5pbmRleE9mKCc/JykgPT09IC0xKSA/ICc/JyA6ICcmJztcbiAgICAgICAgICAgICAgICBvcHRpb25zLnVybCA9IHJlc3VsdChvcHRpb25zLnVybCkgKyBkZWxpbWl0ZXIgKyBwYXJhbXM7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICByZXR1cm4gY29ubmVjdC5jYWxsKHRoaXMsICdERUxFVEUnLCBudWxsLCBvcHRpb25zKTtcbiAgICAgICAgfSxcbiAgICAgICAgaGVhZDogZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgcmV0dXJuIGNvbm5lY3QuYXBwbHkodGhpcywgWydoZWFkJ10uY29uY2F0KFtdLnNsaWNlLmNhbGwoYXJndW1lbnRzKSkpO1xuICAgICAgICB9LFxuICAgICAgICBvcHRpb25zOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICByZXR1cm4gY29ubmVjdC5hcHBseSh0aGlzLCBbJ29wdGlvbnMnXS5jb25jYXQoW10uc2xpY2UuY2FsbChhcmd1bWVudHMpKSk7XG4gICAgICAgIH1cbiAgICB9O1xuXG4gICAgcmV0dXJuICQuZXh0ZW5kKHRoaXMsIHB1YmxpY0FQSSk7XG59O1xuIiwiJ3VzZSBzdHJpY3QnO1xuXG4vLyB2YXIgaXNOb2RlID0gZmFsc2U7IEZJWE1FOiBCcm93c2VyaWZ5L21pbmlmeWlmeSBoYXMgaXNzdWVzIHdpdGggdGhlIG5leHQgbGlua1xuLy8gdmFyIHRyYW5zcG9ydCA9IChpc05vZGUpID8gcmVxdWlyZSgnLi9ub2RlLWh0dHAtdHJhbnNwb3J0JykgOiByZXF1aXJlKCcuL2FqYXgtaHR0cC10cmFuc3BvcnQnKTtcbnZhciB0cmFuc3BvcnQgPSByZXF1aXJlKCcuL2FqYXgtaHR0cC10cmFuc3BvcnQnKTtcbm1vZHVsZS5leHBvcnRzID0gdHJhbnNwb3J0O1xuIiwiLyoqXG4vKiBJbmhlcml0IGZyb20gYSBjbGFzcyAodXNpbmcgcHJvdG90eXBlIGJvcnJvd2luZylcbiovXG4ndXNlIHN0cmljdCc7XG5cbmZ1bmN0aW9uIGluaGVyaXQoQywgUCkge1xuICAgIHZhciBGID0gZnVuY3Rpb24gKCkge307XG4gICAgRi5wcm90b3R5cGUgPSBQLnByb3RvdHlwZTtcbiAgICBDLnByb3RvdHlwZSA9IG5ldyBGKCk7XG4gICAgQy5fX3N1cGVyID0gUC5wcm90b3R5cGU7XG4gICAgQy5wcm90b3R5cGUuY29uc3RydWN0b3IgPSBDO1xufVxuXG4vKipcbiogU2hhbGxvdyBjb3B5IG9mIGFuIG9iamVjdFxuKi9cbnZhciBleHRlbmQgPSBmdW5jdGlvbiAoZGVzdCAvKiwgdmFyX2FyZ3MqLykge1xuICAgIHZhciBvYmogPSBBcnJheS5wcm90b3R5cGUuc2xpY2UuY2FsbChhcmd1bWVudHMsIDEpO1xuICAgIHZhciBjdXJyZW50O1xuICAgIGZvciAodmFyIGogPSAwOyBqPG9iai5sZW5ndGg7IGorKykge1xuICAgICAgICBpZiAoIShjdXJyZW50ID0gb2JqW2pdKSkge1xuICAgICAgICAgICAgY29udGludWU7XG4gICAgICAgIH1cblxuICAgICAgICAvLyBkbyBub3Qgd3JhcCBpbm5lciBpbiBkZXN0Lmhhc093blByb3BlcnR5IG9yIGJhZCB0aGluZ3Mgd2lsbCBoYXBwZW5cbiAgICAgICAgLypqc2hpbnQgLVcwODkgKi9cbiAgICAgICAgZm9yICh2YXIga2V5IGluIGN1cnJlbnQpIHtcbiAgICAgICAgICAgIGRlc3Rba2V5XSA9IGN1cnJlbnRba2V5XTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIHJldHVybiBkZXN0O1xufTtcblxubW9kdWxlLmV4cG9ydHMgPSBmdW5jdGlvbiAoYmFzZSwgcHJvcHMsIHN0YXRpY1Byb3BzKSB7XG4gICAgdmFyIHBhcmVudCA9IGJhc2U7XG4gICAgdmFyIGNoaWxkO1xuXG4gICAgY2hpbGQgPSBwcm9wcyAmJiBwcm9wcy5oYXNPd25Qcm9wZXJ0eSgnY29uc3RydWN0b3InKSA/IHByb3BzLmNvbnN0cnVjdG9yIDogZnVuY3Rpb24gKCkgeyByZXR1cm4gcGFyZW50LmFwcGx5KHRoaXMsIGFyZ3VtZW50cyk7IH07XG5cbiAgICAvLyBhZGQgc3RhdGljIHByb3BlcnRpZXMgdG8gdGhlIGNoaWxkIGNvbnN0cnVjdG9yIGZ1bmN0aW9uXG4gICAgZXh0ZW5kKGNoaWxkLCBwYXJlbnQsIHN0YXRpY1Byb3BzKTtcblxuICAgIC8vIGFzc29jaWF0ZSBwcm90b3R5cGUgY2hhaW5cbiAgICBpbmhlcml0KGNoaWxkLCBwYXJlbnQpO1xuXG4gICAgLy8gYWRkIGluc3RhbmNlIHByb3BlcnRpZXNcbiAgICBpZiAocHJvcHMpIHtcbiAgICAgICAgZXh0ZW5kKGNoaWxkLnByb3RvdHlwZSwgcHJvcHMpO1xuICAgIH1cblxuICAgIC8vIGRvbmVcbiAgICByZXR1cm4gY2hpbGQ7XG59O1xuIiwiJ3VzZSBzdHJpY3QnO1xuLypqc2hpbnQgbG9vcGZ1bmM6ZmFsc2UgKi9cblxuZnVuY3Rpb24gX3codmFsKSB7XG4gICAgaWYgKHZhbCAmJiB2YWwudGhlbikge1xuICAgICAgICByZXR1cm4gdmFsO1xuICAgIH1cbiAgICB2YXIgcCA9ICQuRGVmZXJyZWQoKTtcbiAgICBwLnJlc29sdmUodmFsKTtcblxuICAgIHJldHVybiBwLnByb21pc2UoKTtcbn1cblxuZnVuY3Rpb24gc2VxKCkge1xuICAgIHZhciBsaXN0ID0gQXJyYXkucHJvdG90eXBlLnNsaWNlLmFwcGx5KGFyZ3VtZW50cyk7XG5cbiAgICBmdW5jdGlvbiBuZXh0KHApIHtcbiAgICAgICAgdmFyIGN1ciA9IGxpc3Quc3BsaWNlKDAsMSlbMF07XG5cbiAgICAgICAgaWYgKCFjdXIpIHtcbiAgICAgICAgICAgIHJldHVybiBwO1xuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIF93KGN1cihwKSkudGhlbihuZXh0KTtcbiAgICB9XG5cbiAgICByZXR1cm4gZnVuY3Rpb24gKHNlZWQpIHtcbiAgICAgICAgcmV0dXJuIG5leHQoc2VlZCkuZmFpbChzZXEuZmFpbCk7XG4gICAgfTtcbn1cblxuZnVuY3Rpb24gTWFrZVNlcShvYmopIHtcbiAgICB2YXIgcmVzID0ge1xuICAgICAgICBfX2NhbGxzOiBbXSxcblxuICAgICAgICBvcmlnaW5hbDogb2JqLFxuXG4gICAgICAgIHRoZW46IGZ1bmN0aW9uIChmbikge1xuICAgICAgICAgICAgdGhpcy5fX2NhbGxzLnB1c2goZm4pO1xuICAgICAgICAgICAgcmV0dXJuIHRoaXM7XG4gICAgICAgIH0sXG5cbiAgICAgICAgc3RhcnQ6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIHZhciBfdGhpcyA9IHRoaXM7XG5cbiAgICAgICAgICAgIC8vIGNsZWFuIHVwXG4gICAgICAgICAgICB0aGlzLnRoZW4oZnVuY3Rpb24gKHJ1bikge1xuICAgICAgICAgICAgICAgIF90aGlzLl9fY2FsbHMubGVuZ3RoID0gMDtcbiAgICAgICAgICAgICAgICByZXR1cm4gcnVuO1xuICAgICAgICAgICAgfSk7XG5cbiAgICAgICAgICAgIHJldHVybiBzZXEuYXBwbHkobnVsbCwgdGhpcy5fX2NhbGxzKSgpO1xuICAgICAgICB9LFxuXG4gICAgICAgIGZhaWw6IGZ1bmN0aW9uIChmbikge1xuICAgICAgICAgICAgc2VxLmZhaWwgPSBmbjtcbiAgICAgICAgICAgIHJldHVybiB0aGlzO1xuICAgICAgICB9XG4gICAgfTtcblxuICAgIHZhciBmdW5jTWFrZXIgPSBmdW5jdGlvbiAocCwgb2JqKSB7XG4gICAgICAgIHZhciBmbiA9IG9ialtwXS5iaW5kKG9iaik7XG4gICAgICAgIHJldHVybiBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICB2YXIgYXJncyA9IEFycmF5LnByb3RvdHlwZS5zbGljZS5hcHBseShhcmd1bWVudHMpO1xuICAgICAgICAgICAgdGhpcy5fX2NhbGxzLnB1c2goRnVuY3Rpb24uYmluZC5hcHBseShmbiwgW251bGxdLmNvbmNhdChhcmdzKSkpO1xuICAgICAgICAgICAgcmV0dXJuIHRoaXM7XG4gICAgICAgIH07XG4gICAgfTtcblxuICAgIGZvciAodmFyIHByb3AgaW4gb2JqKSB7XG4gICAgICAgIGlmICh0eXBlb2Ygb2JqW3Byb3BdID09PSAnZnVuY3Rpb24nKSB7XG4gICAgICAgICAgICByZXNbcHJvcF0gPSBmdW5jTWFrZXIocHJvcCwgb2JqKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIHJlc1twcm9wXSA9IG9ialtwcm9wXTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIHJldHVybiByZXM7XG59XG5cbm1vZHVsZS5leHBvcnRzID0gTWFrZVNlcTtcbiIsIid1c2Ugc3RyaWN0JztcblxubW9kdWxlLmV4cG9ydHMgPSB7XG4gICAgX3BpY2s6IGZ1bmN0aW9uIChvYmosIHByb3BzKSB7XG4gICAgICAgIHZhciByZXMgPSB7fTtcbiAgICAgICAgZm9yICh2YXIgcCBpbiBvYmopIHtcbiAgICAgICAgICAgIGlmIChwcm9wcy5pbmRleE9mKHApICE9PSAtMSkge1xuICAgICAgICAgICAgICAgIHJlc1twXSA9IG9ialtwXTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuXG4gICAgICAgIHJldHVybiByZXM7XG4gICAgfVxufTtcbiIsIid1c2Ugc3RyaWN0JztcblxudmFyIENvbmZpZ1NlcnZpY2UgPSByZXF1aXJlKCcuLi9zZXJ2aWNlL2NvbmZpZ3VyYXRpb24tc2VydmljZScpO1xuXG52YXIgdXJsQ29uZmlnID0gbmV3IENvbmZpZ1NlcnZpY2UoKS5nZXQoJ3NlcnZlcicpO1xudmFyIGN1c3RvbURlZmF1bHRzID0ge307XG52YXIgbGliRGVmYXVsdHMgPSB7XG4gICAgLyoqXG4gICAgICogVGhlIGFjY291bnQgaWQuIEluIHRoZSBFcGljZW50ZXIgVUksIHRoaXMgaXMgdGhlICoqVGVhbSBJRCoqIChmb3IgdGVhbSBwcm9qZWN0cykgb3IgKipVc2VyIElEKiogKGZvciBwZXJzb25hbCBwcm9qZWN0cykuIERlZmF1bHRzIHRvIGVtcHR5IHN0cmluZy4gSWYgbGVmdCB1bmRlZmluZWQsIHRha2VuIGZyb20gdGhlIFVSTC5cbiAgICAgKiBAdHlwZSB7U3RyaW5nfVxuICAgICAqL1xuICAgIGFjY291bnQ6IHVybENvbmZpZy5hY2NvdW50UGF0aCxcbiAgICAvKipcbiAgICAgKiBUaGUgYWNjb3VudCBpZC4gSW4gdGhlIEVwaWNlbnRlciBVSSwgdGhpcyBpcyB0aGUgKipUZWFtIElEKiogKGZvciB0ZWFtIHByb2plY3RzKSBvciAqKlVzZXIgSUQqKiAoZm9yIHBlcnNvbmFsIHByb2plY3RzKS4gRGVmYXVsdHMgdG8gZW1wdHkgc3RyaW5nLiBJZiBsZWZ0IHVuZGVmaW5lZCwgdGFrZW4gZnJvbSB0aGUgVVJMLlxuICAgICAqIEB0eXBlIHtTdHJpbmd9XG4gICAgICovXG4gICAgcHJvamVjdDogdXJsQ29uZmlnLnByb2plY3RQYXRoLFxuICAgIGlzTG9jYWw6IHVybENvbmZpZy5pc0xvY2FsaG9zdCgpLFxuICAgIHN0b3JlOiB7fVxufTtcblxudmFyIG9wdGlvblV0aWxzID0ge1xuICAgIC8qKlxuICAgICAqIEdldHMgdGhlIGZpbmFsIG9wdGlvbnMgYnkgb3ZlcnJpZGluZyB0aGUgZ2xvYmFsIG9wdGlvbnMgc2V0IHdpdGhcbiAgICAgKiBvcHRpb25VdGlscyNzZXREZWZhdWx0cygpIGFuZCB0aGUgbGliIGRlZmF1bHRzLlxuICAgICAqIEBwYXJhbSB7b2JqZWN0fSBgb3B0aW9uc2AgVGhlIGZpbmFsIG9wdGlvbnMgb2JqZWN0LlxuICAgICAqL1xuICAgIGdldE9wdGlvbnM6IGZ1bmN0aW9uIChvcHRpb25zKSB7XG4gICAgICAgIHJldHVybiAkLmV4dGVuZCh0cnVlLCB7fSwgbGliRGVmYXVsdHMsIGN1c3RvbURlZmF1bHRzLCBvcHRpb25zKTtcbiAgICB9LFxuICAgIC8qKlxuICAgICAqIFNldHMgdGhlIGdsb2JhbCBkZWZhdWx0cyBmb3IgdGhlIG9wdGlvblV0aWxzI2dldE9wdGlvbnMoKSBtZXRob2QuXG4gICAgICogQHBhcmFtIHtvYmplY3R9IGBkZWZhdWx0c2AgVGhlIGRlZmF1bHRzIG9iamVjdC5cbiAgICAgKi9cbiAgICBzZXREZWZhdWx0czogZnVuY3Rpb24gKGRlZmF1bHRzKSB7XG4gICAgICAgIGN1c3RvbURlZmF1bHRzID0gZGVmYXVsdHM7XG4gICAgfVxufTtcbm1vZHVsZS5leHBvcnRzID0gb3B0aW9uVXRpbHM7XG4iLCIvKipcbiAqIFV0aWxpdGllcyBmb3Igd29ya2luZyB3aXRoIHF1ZXJ5IHN0cmluZ3NcbiovXG4ndXNlIHN0cmljdCc7XG5cbm1vZHVsZS5leHBvcnRzID0gKGZ1bmN0aW9uICgpIHtcblxuICAgIHJldHVybiB7XG4gICAgICAgIC8qKlxuICAgICAgICAgKiBDb252ZXJ0cyB0byBtYXRyaXggZm9ybWF0XG4gICAgICAgICAqIEBwYXJhbSAge09iamVjdH0gcXMgT2JqZWN0IHRvIGNvbnZlcnQgdG8gcXVlcnkgc3RyaW5nXG4gICAgICAgICAqIEByZXR1cm4geyBzdHJpbmd9ICAgIE1hdHJpeC1mb3JtYXQgcXVlcnkgcGFyYW1ldGVyc1xuICAgICAgICAgKi9cbiAgICAgICAgdG9NYXRyaXhGb3JtYXQ6IGZ1bmN0aW9uIChxcykge1xuICAgICAgICAgICAgaWYgKHFzID09PSBudWxsIHx8IHFzID09PSB1bmRlZmluZWQgfHwgcXMgPT09ICcnKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuICc7JztcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGlmICh0eXBlb2YgcXMgPT09ICdzdHJpbmcnIHx8IHFzIGluc3RhbmNlb2YgU3RyaW5nKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIHFzO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICB2YXIgcmV0dXJuQXJyYXkgPSBbXTtcbiAgICAgICAgICAgIHZhciBPUEVSQVRPUlMgPSBbJzwnLCAnPicsICchJ107XG4gICAgICAgICAgICAkLmVhY2gocXMsIGZ1bmN0aW9uIChrZXksIHZhbHVlKSB7XG4gICAgICAgICAgICAgICAgaWYgKHR5cGVvZiB2YWx1ZSAhPT0gJ3N0cmluZycgfHwgJC5pbkFycmF5KCQudHJpbSh2YWx1ZSkuY2hhckF0KDApLCBPUEVSQVRPUlMpID09PSAtMSkge1xuICAgICAgICAgICAgICAgICAgICB2YWx1ZSA9ICc9JyArIHZhbHVlO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICByZXR1cm5BcnJheS5wdXNoKGtleSArIHZhbHVlKTtcbiAgICAgICAgICAgIH0pO1xuXG4gICAgICAgICAgICB2YXIgbXRyeCA9ICc7JyArIHJldHVybkFycmF5LmpvaW4oJzsnKTtcbiAgICAgICAgICAgIHJldHVybiBtdHJ4O1xuICAgICAgICB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBDb252ZXJ0cyBzdHJpbmdzL2FycmF5cy9vYmplY3RzIHRvIHR5cGUgJ2E9YiZiPWMnXG4gICAgICAgICAqIEBwYXJhbSAgeyBzdHJpbmd8QXJyYXl8T2JqZWN0fSBxc1xuICAgICAgICAgKiBAcmV0dXJuIHsgc3RyaW5nfVxuICAgICAgICAgKi9cbiAgICAgICAgdG9RdWVyeUZvcm1hdDogZnVuY3Rpb24gKHFzKSB7XG4gICAgICAgICAgICBpZiAocXMgPT09IG51bGwgfHwgcXMgPT09IHVuZGVmaW5lZCkge1xuICAgICAgICAgICAgICAgIHJldHVybiAnJztcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGlmICh0eXBlb2YgcXMgPT09ICdzdHJpbmcnIHx8IHFzIGluc3RhbmNlb2YgU3RyaW5nKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIHFzO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICB2YXIgcmV0dXJuQXJyYXkgPSBbXTtcbiAgICAgICAgICAgICQuZWFjaChxcywgZnVuY3Rpb24gKGtleSwgdmFsdWUpIHtcbiAgICAgICAgICAgICAgICBpZiAoJC5pc0FycmF5KHZhbHVlKSkge1xuICAgICAgICAgICAgICAgICAgICB2YWx1ZSA9IHZhbHVlLmpvaW4oJywnKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgaWYgKCQuaXNQbGFpbk9iamVjdCh2YWx1ZSkpIHtcbiAgICAgICAgICAgICAgICAgICAgLy9Nb3N0bHkgZm9yIGRhdGEgYXBpXG4gICAgICAgICAgICAgICAgICAgIHZhbHVlID0gSlNPTi5zdHJpbmdpZnkodmFsdWUpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICByZXR1cm5BcnJheS5wdXNoKGtleSArICc9JyArIHZhbHVlKTtcbiAgICAgICAgICAgIH0pO1xuXG4gICAgICAgICAgICB2YXIgcmVzdWx0ID0gcmV0dXJuQXJyYXkuam9pbignJicpO1xuICAgICAgICAgICAgcmV0dXJuIHJlc3VsdDtcbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgICogQ29udmVydHMgc3RyaW5ncyBvZiB0eXBlICdhPWImYj1jJyB0byB7IGE6YiwgYjpjfVxuICAgICAgICAgKiBAcGFyYW0gIHsgc3RyaW5nfSBxc1xuICAgICAgICAgKiBAcmV0dXJuIHtvYmplY3R9XG4gICAgICAgICAqL1xuICAgICAgICBxc1RvT2JqZWN0OiBmdW5jdGlvbiAocXMpIHtcbiAgICAgICAgICAgIGlmIChxcyA9PT0gbnVsbCB8fCBxcyA9PT0gdW5kZWZpbmVkIHx8IHFzID09PSAnJykge1xuICAgICAgICAgICAgICAgIHJldHVybiB7fTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgdmFyIHFzQXJyYXkgPSBxcy5zcGxpdCgnJicpO1xuICAgICAgICAgICAgdmFyIHJldHVybk9iaiA9IHt9O1xuICAgICAgICAgICAgJC5lYWNoKHFzQXJyYXksIGZ1bmN0aW9uIChpbmRleCwgdmFsdWUpIHtcbiAgICAgICAgICAgICAgICB2YXIgcUtleSA9IHZhbHVlLnNwbGl0KCc9JylbMF07XG4gICAgICAgICAgICAgICAgdmFyIHFWYWwgPSB2YWx1ZS5zcGxpdCgnPScpWzFdO1xuXG4gICAgICAgICAgICAgICAgaWYgKHFWYWwuaW5kZXhPZignLCcpICE9PSAtMSkge1xuICAgICAgICAgICAgICAgICAgICBxVmFsID0gcVZhbC5zcGxpdCgnLCcpO1xuICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgIHJldHVybk9ialtxS2V5XSA9IHFWYWw7XG4gICAgICAgICAgICB9KTtcblxuICAgICAgICAgICAgcmV0dXJuIHJldHVybk9iajtcbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgICogTm9ybWFsaXplcyBhbmQgbWVyZ2VzIHN0cmluZ3Mgb2YgdHlwZSAnYT1iJywgeyBiOmN9IHRvIHsgYTpiLCBiOmN9XG4gICAgICAgICAqIEBwYXJhbSAgeyBzdHJpbmd8QXJyYXl8T2JqZWN0fSBxczFcbiAgICAgICAgICogQHBhcmFtICB7IHN0cmluZ3xBcnJheXxPYmplY3R9IHFzMlxuICAgICAgICAgKiBAcmV0dXJuIHtPYmplY3R9XG4gICAgICAgICAqL1xuICAgICAgICBtZXJnZVFTOiBmdW5jdGlvbiAocXMxLCBxczIpIHtcbiAgICAgICAgICAgIHZhciBvYmoxID0gdGhpcy5xc1RvT2JqZWN0KHRoaXMudG9RdWVyeUZvcm1hdChxczEpKTtcbiAgICAgICAgICAgIHZhciBvYmoyID0gdGhpcy5xc1RvT2JqZWN0KHRoaXMudG9RdWVyeUZvcm1hdChxczIpKTtcbiAgICAgICAgICAgIHJldHVybiAkLmV4dGVuZCh0cnVlLCB7fSwgb2JqMSwgb2JqMik7XG4gICAgICAgIH0sXG5cbiAgICAgICAgYWRkVHJhaWxpbmdTbGFzaDogZnVuY3Rpb24gKHVybCkge1xuICAgICAgICAgICAgaWYgKCF1cmwpIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gJyc7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICByZXR1cm4gKHVybC5jaGFyQXQodXJsLmxlbmd0aCAtIDEpID09PSAnLycpID8gdXJsIDogKHVybCArICcvJyk7XG4gICAgICAgIH1cbiAgICB9O1xufSgpKTtcblxuXG5cbiIsIi8qKlxuICogVXRpbGl0aWVzIGZvciB3b3JraW5nIHdpdGggdGhlIHJ1biBzZXJ2aWNlXG4qL1xuJ3VzZSBzdHJpY3QnO1xudmFyIHF1dGlsID0gcmVxdWlyZSgnLi9xdWVyeS11dGlsJyk7XG52YXIgTUFYX1VSTF9MRU5HVEggPSAyMDQ4O1xuXG5tb2R1bGUuZXhwb3J0cyA9IChmdW5jdGlvbiAoKSB7XG4gICAgcmV0dXJuIHtcbiAgICAgICAgLyoqXG4gICAgICAgICAqIHJldHVybnMgb3BlcmF0aW9ucyBvZiB0aGUgZm9ybSBgW1tvcDEsb3AyXSwgW2FyZzEsIGFyZzJdXWBcbiAgICAgICAgICogQHBhcmFtICB7T2JqZWN0fEFycmF5fFN0cmluZ30gYG9wZXJhdGlvbnNgIG9wZXJhdGlvbnMgdG8gcGVyZm9ybVxuICAgICAgICAgKiBAcGFyYW0gIHtBcnJheX0gYGFyZ3NgIGFyZ3VtZW50cyBmb3Igb3BlcmF0aW9uXG4gICAgICAgICAqIEByZXR1cm4ge1N0cmluZ30gICAgTWF0cml4LWZvcm1hdCBxdWVyeSBwYXJhbWV0ZXJzXG4gICAgICAgICAqL1xuICAgICAgICBub3JtYWxpemVPcGVyYXRpb25zOiBmdW5jdGlvbiAob3BlcmF0aW9ucywgYXJncykge1xuICAgICAgICAgICAgaWYgKCFhcmdzKSB7XG4gICAgICAgICAgICAgICAgYXJncyA9IFtdO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgdmFyIHJldHVybkxpc3QgPSB7XG4gICAgICAgICAgICAgICAgb3BzOiBbXSxcbiAgICAgICAgICAgICAgICBhcmdzOiBbXVxuICAgICAgICAgICAgfTtcblxuICAgICAgICAgICAgdmFyIF9jb25jYXQgPSBmdW5jdGlvbiAoYXJyKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIChhcnIgIT09IG51bGwgJiYgYXJyICE9PSB1bmRlZmluZWQpID8gW10uY29uY2F0KGFycikgOiBbXTtcbiAgICAgICAgICAgIH07XG5cbiAgICAgICAgICAgIC8veyBhZGQ6IFsxLDJdLCBzdWJ0cmFjdDogWzIsNF0gfVxuICAgICAgICAgICAgdmFyIF9ub3JtYWxpemVQbGFpbk9iamVjdHMgPSBmdW5jdGlvbiAob3BlcmF0aW9ucywgcmV0dXJuTGlzdCkge1xuICAgICAgICAgICAgICAgIGlmICghcmV0dXJuTGlzdCkge1xuICAgICAgICAgICAgICAgICAgICByZXR1cm5MaXN0ID0geyBvcHM6IFtdLCBhcmdzOiBbXSB9O1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAkLmVhY2gob3BlcmF0aW9ucywgZnVuY3Rpb24gKG9wbiwgYXJnKSB7XG4gICAgICAgICAgICAgICAgICAgIHJldHVybkxpc3Qub3BzLnB1c2gob3BuKTtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuTGlzdC5hcmdzLnB1c2goX2NvbmNhdChhcmcpKTtcbiAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgICByZXR1cm4gcmV0dXJuTGlzdDtcbiAgICAgICAgICAgIH07XG4gICAgICAgICAgICAvL3sgbmFtZTogJ2FkZCcsIHBhcmFtczogWzFdIH1cbiAgICAgICAgICAgIHZhciBfbm9ybWFsaXplU3RydWN0dXJlZE9iamVjdHMgPSBmdW5jdGlvbiAob3BlcmF0aW9uLCByZXR1cm5MaXN0KSB7XG4gICAgICAgICAgICAgICAgaWYgKCFyZXR1cm5MaXN0KSB7XG4gICAgICAgICAgICAgICAgICAgIHJldHVybkxpc3QgPSB7IG9wczogW10sIGFyZ3M6IFtdIH07XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIHJldHVybkxpc3Qub3BzLnB1c2gob3BlcmF0aW9uLm5hbWUpO1xuICAgICAgICAgICAgICAgIHJldHVybkxpc3QuYXJncy5wdXNoKF9jb25jYXQob3BlcmF0aW9uLnBhcmFtcykpO1xuICAgICAgICAgICAgICAgIHJldHVybiByZXR1cm5MaXN0O1xuICAgICAgICAgICAgfTtcblxuICAgICAgICAgICAgdmFyIF9ub3JtYWxpemVPYmplY3QgPSBmdW5jdGlvbiAob3BlcmF0aW9uLCByZXR1cm5MaXN0KSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuICgob3BlcmF0aW9uLm5hbWUpID8gX25vcm1hbGl6ZVN0cnVjdHVyZWRPYmplY3RzIDogX25vcm1hbGl6ZVBsYWluT2JqZWN0cykob3BlcmF0aW9uLCByZXR1cm5MaXN0KTtcbiAgICAgICAgICAgIH07XG5cbiAgICAgICAgICAgIHZhciBfbm9ybWFsaXplTGl0ZXJhbHMgPSBmdW5jdGlvbiAob3BlcmF0aW9uLCBhcmdzLCByZXR1cm5MaXN0KSB7XG4gICAgICAgICAgICAgICAgaWYgKCFyZXR1cm5MaXN0KSB7XG4gICAgICAgICAgICAgICAgICAgIHJldHVybkxpc3QgPSB7IG9wczogW10sIGFyZ3M6IFtdIH07XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIHJldHVybkxpc3Qub3BzLnB1c2gob3BlcmF0aW9uKTtcbiAgICAgICAgICAgICAgICByZXR1cm5MaXN0LmFyZ3MucHVzaChfY29uY2F0KGFyZ3MpKTtcbiAgICAgICAgICAgICAgICByZXR1cm4gcmV0dXJuTGlzdDtcbiAgICAgICAgICAgIH07XG5cblxuICAgICAgICAgICAgdmFyIF9ub3JtYWxpemVBcnJheXMgPSBmdW5jdGlvbiAob3BlcmF0aW9ucywgYXJnLCByZXR1cm5MaXN0KSB7XG4gICAgICAgICAgICAgICAgaWYgKCFyZXR1cm5MaXN0KSB7XG4gICAgICAgICAgICAgICAgICAgIHJldHVybkxpc3QgPSB7IG9wczogW10sIGFyZ3M6IFtdIH07XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICQuZWFjaChvcGVyYXRpb25zLCBmdW5jdGlvbiAoaW5kZXgsIG9wbikge1xuICAgICAgICAgICAgICAgICAgICBpZiAoJC5pc1BsYWluT2JqZWN0KG9wbikpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIF9ub3JtYWxpemVPYmplY3Qob3BuLCByZXR1cm5MaXN0KTtcbiAgICAgICAgICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIF9ub3JtYWxpemVMaXRlcmFscyhvcG4sIGFyZ3NbaW5kZXhdLCByZXR1cm5MaXN0KTtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICAgIHJldHVybiByZXR1cm5MaXN0O1xuICAgICAgICAgICAgfTtcblxuICAgICAgICAgICAgaWYgKCQuaXNQbGFpbk9iamVjdChvcGVyYXRpb25zKSkge1xuICAgICAgICAgICAgICAgIF9ub3JtYWxpemVPYmplY3Qob3BlcmF0aW9ucywgcmV0dXJuTGlzdCk7XG4gICAgICAgICAgICB9IGVsc2UgaWYgKCQuaXNBcnJheShvcGVyYXRpb25zKSkge1xuICAgICAgICAgICAgICAgIF9ub3JtYWxpemVBcnJheXMob3BlcmF0aW9ucywgYXJncywgcmV0dXJuTGlzdCk7XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgIF9ub3JtYWxpemVMaXRlcmFscyhvcGVyYXRpb25zLCBhcmdzLCByZXR1cm5MaXN0KTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgcmV0dXJuIHJldHVybkxpc3Q7XG4gICAgICAgIH0sXG5cbiAgICAgICAgc3BsaXRHZXRGYWN0b3J5OiBmdW5jdGlvbiAoaHR0cE9wdGlvbnMpIHtcbiAgICAgICAgICAgIHJldHVybiBmdW5jdGlvbiAocGFyYW1zLCBvcHRpb25zKSB7XG4gICAgICAgICAgICAgICAgdmFyIGh0dHAgPSB0aGlzO1xuICAgICAgICAgICAgICAgIHZhciBnZXRWYWx1ZSA9IGZ1bmN0aW9uIChuYW1lKSB7XG4gICAgICAgICAgICAgICAgICAgIHZhciB2YWx1ZSA9IG9wdGlvbnNbbmFtZV0gfHwgaHR0cE9wdGlvbnNbbmFtZV07XG4gICAgICAgICAgICAgICAgICAgIGlmICh0eXBlb2YgdmFsdWUgPT09ICdmdW5jdGlvbicpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHZhbHVlID0gdmFsdWUoKTtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICByZXR1cm4gdmFsdWU7XG4gICAgICAgICAgICAgICAgfTtcbiAgICAgICAgICAgICAgICB2YXIgZ2V0RmluYWxVcmwgPSBmdW5jdGlvbiAocGFyYW1zKSB7XG4gICAgICAgICAgICAgICAgICAgIHZhciB1cmwgPSBnZXRWYWx1ZSgndXJsJywgb3B0aW9ucyk7XG4gICAgICAgICAgICAgICAgICAgIHZhciBkYXRhID0gcGFyYW1zO1xuICAgICAgICAgICAgICAgICAgICAvLyBUaGVyZSBpcyBlYXN5IChvciBrbm93bikgd2F5IHRvIGdldCB0aGUgZmluYWwgVVJMIGpxdWVyeSBpcyBnb2luZyB0byBzZW5kIHNvXG4gICAgICAgICAgICAgICAgICAgIC8vIHdlJ3JlIHJlcGxpY2F0aW5nIGl0LiBUaGUgcHJvY2VzcyBtaWdodCBjaGFuZ2UgYXQgc29tZSBwb2ludCBidXQgaXQgcHJvYmFibHkgd2lsbCBub3QuXG4gICAgICAgICAgICAgICAgICAgIC8vIDEuIFJlbW92ZSBoYXNoXG4gICAgICAgICAgICAgICAgICAgIHVybCA9IHVybC5yZXBsYWNlKC8jLiokLywgJycpO1xuICAgICAgICAgICAgICAgICAgICAvLyAxLiBBcHBlbmQgcXVlcnkgc3RyaW5nXG4gICAgICAgICAgICAgICAgICAgIHZhciBxdWVyeVBhcmFtcyA9IHF1dGlsLnRvUXVlcnlGb3JtYXQoZGF0YSk7XG4gICAgICAgICAgICAgICAgICAgIHZhciBxdWVzdGlvbklkeCA9IHVybC5pbmRleE9mKCc/Jyk7XG4gICAgICAgICAgICAgICAgICAgIGlmIChxdWVyeVBhcmFtcyAmJiBxdWVzdGlvbklkeCA+IC0xKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICByZXR1cm4gdXJsICsgJyYnICsgcXVlcnlQYXJhbXM7XG4gICAgICAgICAgICAgICAgICAgIH0gZWxzZSBpZiAocXVlcnlQYXJhbXMpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybiB1cmwgKyAnPycgKyBxdWVyeVBhcmFtcztcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICByZXR1cm4gdXJsO1xuICAgICAgICAgICAgICAgIH07XG4gICAgICAgICAgICAgICAgdmFyIHVybCA9IGdldEZpbmFsVXJsKHBhcmFtcyk7XG4gICAgICAgICAgICAgICAgLy8gV2UgbXVzdCBzcGxpdCB0aGUgR0VUIGluIG11bHRpcGxlIHNob3J0IFVSTCdzXG4gICAgICAgICAgICAgICAgLy8gVGhlIG9ubHkgcHJvcGVydHkgYWxsb3dlZCB0byBiZSBzcGxpdCBpcyBcImluY2x1ZGVcIlxuICAgICAgICAgICAgICAgIGlmIChwYXJhbXMgJiYgcGFyYW1zLmluY2x1ZGUgJiYgZW5jb2RlVVJJKHVybCkubGVuZ3RoID4gTUFYX1VSTF9MRU5HVEgpIHtcbiAgICAgICAgICAgICAgICAgICAgdmFyIGR0ZCA9ICQuRGVmZXJyZWQoKTtcbiAgICAgICAgICAgICAgICAgICAgdmFyIHBhcmFtc0NvcHkgPSAkLmV4dGVuZCh0cnVlLCB7fSwgcGFyYW1zKTtcbiAgICAgICAgICAgICAgICAgICAgZGVsZXRlIHBhcmFtc0NvcHkuaW5jbHVkZTtcbiAgICAgICAgICAgICAgICAgICAgdmFyIHVybE5vSW5jbHVkZXMgPSBnZXRGaW5hbFVybChwYXJhbXNDb3B5KTtcbiAgICAgICAgICAgICAgICAgICAgdmFyIGRpZmYgPSBNQVhfVVJMX0xFTkdUSCAtIHVybE5vSW5jbHVkZXMubGVuZ3RoO1xuICAgICAgICAgICAgICAgICAgICB2YXIgb2xkU3VjY2VzcyA9IG9wdGlvbnMuc3VjY2VzcyB8fCBodHRwT3B0aW9ucy5zdWNjZXNzIHx8ICQubm9vcDtcbiAgICAgICAgICAgICAgICAgICAgdmFyIG9sZEVycm9yID0gb3B0aW9ucy5lcnJvciB8fCBodHRwT3B0aW9ucy5lcnJvciB8fCAkLm5vb3A7XG4gICAgICAgICAgICAgICAgICAgIC8vIHJlbW92ZSB0aGUgb3JpZ2luYWwgc3VjY2VzcyBhbmQgZXJyb3IgY2FsbGJhY2tzXG4gICAgICAgICAgICAgICAgICAgIG9wdGlvbnMuc3VjY2VzcyA9ICQubm9vcDtcbiAgICAgICAgICAgICAgICAgICAgb3B0aW9ucy5lcnJvciA9ICQubm9vcDtcblxuICAgICAgICAgICAgICAgICAgICB2YXIgaW5jbHVkZSA9IHBhcmFtcy5pbmNsdWRlO1xuICAgICAgICAgICAgICAgICAgICB2YXIgY3VyckluY2x1ZGVzID0gW107XG4gICAgICAgICAgICAgICAgICAgIHZhciBpbmNsdWRlT3B0cyA9IFtjdXJySW5jbHVkZXNdO1xuICAgICAgICAgICAgICAgICAgICB2YXIgY3Vyckxlbmd0aCA9IGVuY29kZVVSSUNvbXBvbmVudCgnP2luY2x1ZGU9JykubGVuZ3RoO1xuICAgICAgICAgICAgICAgICAgICB2YXIgdmFyaWFibGUgPSBpbmNsdWRlLnBvcCgpO1xuICAgICAgICAgICAgICAgICAgICB3aGlsZSAodmFyaWFibGUpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHZhciB2YXJMZW5naHQgPSBlbmNvZGVVUklDb21wb25lbnQodmFyaWFibGUpLmxlbmd0aDtcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIFVzZSBhIGdyZWVkeSBhcHByb2FjaCBmb3Igbm93LCBjYW4gYmUgb3B0aW1pemVkIHRvIGJlIHNvbHZlZCBpbiBhIG1vcmVcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIGVmZmljaWVudCB3YXlcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vICsgMSBpcyB0aGUgY29tbWFcbiAgICAgICAgICAgICAgICAgICAgICAgIGlmIChjdXJyTGVuZ3RoICsgdmFyTGVuZ2h0ICsgMSA8IGRpZmYpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBjdXJySW5jbHVkZXMucHVzaCh2YXJpYWJsZSk7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgY3Vyckxlbmd0aCArPSB2YXJMZW5naHQgKyAxO1xuICAgICAgICAgICAgICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBjdXJySW5jbHVkZXMgPSBbdmFyaWFibGVdO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGluY2x1ZGVPcHRzLnB1c2goY3VyckluY2x1ZGVzKTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBjdXJyTGVuZ3RoID0gJz9pbmNsdWRlPScubGVuZ3RoICsgdmFyTGVuZ2h0O1xuICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICAgICAgdmFyaWFibGUgPSBpbmNsdWRlLnBvcCgpO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgIHZhciByZXFzID0gJC5tYXAoaW5jbHVkZU9wdHMsIGZ1bmN0aW9uIChpbmNsdWRlKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICB2YXIgcmVxUGFyYW1zID0gJC5leHRlbmQoe30sIHBhcmFtcywgeyBpbmNsdWRlOiBpbmNsdWRlIH0pO1xuICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIGh0dHAuZ2V0KHJlcVBhcmFtcywgb3B0aW9ucyk7XG4gICAgICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICAgICAgICAkLndoZW4uYXBwbHkoJCwgcmVxcykudGhlbihmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAvLyBFYWNoIGFyZ3VtZW50IGFyZSBhcnJheXMgb2YgdGhlIGFyZ3VtZW50cyBvZiBlYWNoIGRvbmUgcmVxdWVzdFxuICAgICAgICAgICAgICAgICAgICAgICAgLy8gU28gdGhlIGZpcnN0IGFyZ3VtZW50IG9mIHRoZSBmaXJzdCBhcnJheSBvZiBhcmd1bWVudHMgaXMgdGhlIGRhdGFcbiAgICAgICAgICAgICAgICAgICAgICAgIHZhciBpc1ZhbGlkID0gYXJndW1lbnRzWzBdICYmIGFyZ3VtZW50c1swXVswXTtcbiAgICAgICAgICAgICAgICAgICAgICAgIGlmICghaXNWYWxpZCkge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIFNob3VsZCBuZXZlciBoYXBwZW4uLi5cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBvbGRFcnJvcigpO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybiBkdGQucmVqZWN0KCk7XG4gICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgICAgICB2YXIgZmlyc3RSZXNwb25zZSA9IGFyZ3VtZW50c1swXVswXTtcbiAgICAgICAgICAgICAgICAgICAgICAgIHZhciBpc09iamVjdCA9ICQuaXNQbGFpbk9iamVjdChmaXJzdFJlc3BvbnNlKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIHZhciBpc1J1bkFQSSA9IChpc09iamVjdCAmJiAkLmlzUGxhaW5PYmplY3QoZmlyc3RSZXNwb25zZS52YXJpYWJsZXMpKSB8fCAhaXNPYmplY3Q7XG4gICAgICAgICAgICAgICAgICAgICAgICBpZiAoaXNSdW5BUEkpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZiAoaXNPYmplY3QpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gYWdncmVnYXRlIHRoZSB2YXJpYWJsZXMgcHJvcGVydHkgb25seVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB2YXIgYWdncmVnYXRlUnVuID0gYXJndW1lbnRzWzBdWzBdO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAkLmVhY2goYXJndW1lbnRzLCBmdW5jdGlvbiAoaWR4LCBhcmdzKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB2YXIgcnVuID0gYXJnc1swXTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICQuZXh0ZW5kKHRydWUsIGFnZ3JlZ2F0ZVJ1bi52YXJpYWJsZXMsIHJ1bi52YXJpYWJsZXMpO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgb2xkU3VjY2VzcyhhZ2dyZWdhdGVSdW4sIGFyZ3VtZW50c1swXVsxXSwgYXJndW1lbnRzWzBdWzJdKTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZHRkLnJlc29sdmUoYWdncmVnYXRlUnVuLCBhcmd1bWVudHNbMF1bMV0sIGFyZ3VtZW50c1swXVsyXSk7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gYXJyYXkgb2YgcnVuc1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBBZ3JlZ2F0ZSB2YXJpYWJsZXMgaW4gZWFjaCBydW5cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdmFyIGFnZ3JlZ2F0ZWRSdW5zID0ge307XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICQuZWFjaChhcmd1bWVudHMsIGZ1bmN0aW9uIChpZHgsIGFyZ3MpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHZhciBydW5zID0gYXJnc1swXTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmICghJC5pc0FycmF5KHJ1bnMpKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJC5lYWNoKHJ1bnMsIGZ1bmN0aW9uIChpZHhSdW4sIHJ1bikge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmIChydW4uaWQgJiYgIWFnZ3JlZ2F0ZWRSdW5zW3J1bi5pZF0pIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcnVuLnZhcmlhYmxlcyA9IHJ1bi52YXJpYWJsZXMgfHwge307XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFnZ3JlZ2F0ZWRSdW5zW3J1bi5pZF0gPSBydW47XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfSBlbHNlIGlmIChydW4uaWQpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJC5leHRlbmQodHJ1ZSwgYWdncmVnYXRlZFJ1bnNbcnVuLmlkXS52YXJpYWJsZXMsIHJ1bi52YXJpYWJsZXMpO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gdHVybiBpdCBpbnRvIGFuIGFycmF5XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFnZ3JlZ2F0ZWRSdW5zID0gJC5tYXAoYWdncmVnYXRlZFJ1bnMsIGZ1bmN0aW9uIChydW4pIHsgcmV0dXJuIHJ1bjsgfSk7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG9sZFN1Y2Nlc3MoYWdncmVnYXRlZFJ1bnMsIGFyZ3VtZW50c1swXVsxXSwgYXJndW1lbnRzWzBdWzJdKTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZHRkLnJlc29sdmUoYWdncmVnYXRlZFJ1bnMsIGFyZ3VtZW50c1swXVsxXSwgYXJndW1lbnRzWzBdWzJdKTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIGlzIHZhcmlhYmxlcyBBUElcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBhZ2dyZWdhdGUgdGhlIHJlc3BvbnNlXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgdmFyIGFnZ3JlZ2F0ZWRWYXJpYWJsZXMgPSB7fTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAkLmVhY2goYXJndW1lbnRzLCBmdW5jdGlvbiAoaWR4LCBhcmdzKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHZhciB2YXJzID0gYXJnc1swXTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJC5leHRlbmQodHJ1ZSwgYWdncmVnYXRlZFZhcmlhYmxlcywgdmFycyk7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgb2xkU3VjY2VzcyhhZ2dyZWdhdGVkVmFyaWFibGVzLCBhcmd1bWVudHNbMF1bMV0sIGFyZ3VtZW50c1swXVsyXSk7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgZHRkLnJlc29sdmUoYWdncmVnYXRlZFZhcmlhYmxlcywgYXJndW1lbnRzWzBdWzFdLCBhcmd1bWVudHNbMF1bMl0pO1xuICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICB9LCBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBvbGRFcnJvci5hcHBseShodHRwLCBhcmd1bWVudHMpO1xuICAgICAgICAgICAgICAgICAgICAgICAgZHRkLnJlamVjdC5hcHBseShkdGQsIGFyZ3VtZW50cyk7XG4gICAgICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICAgICAgICByZXR1cm4gZHRkLnByb21pc2UoKTtcbiAgICAgICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICByZXR1cm4gaHR0cC5nZXQocGFyYW1zLCBvcHRpb25zKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9O1xuICAgICAgICB9XG4gICAgfTtcbn0oKSk7XG4iXX0= +>>>>>>> dms3-version diff --git a/dist/epicenter.min.js b/dist/epicenter.min.js index 0c706e75..18f5d5a3 100644 --- a/dist/epicenter.min.js +++ b/dist/epicenter.min.js @@ -10,103 +10,99 @@ exports.read=function(buffer,offset,isLE,mLen,nBytes){var e,m;var eLen=8*nBytes- },{}],4:[function(require,module,exports){ var toString={}.toString;module.exports=Array.isArray||function(arr){return"[object Array]"==toString.call(arr)}; },{}],5:[function(require,module,exports){ -"use strict";function toObject(val){if(null===val||void 0===val)throw new TypeError("Object.assign cannot be called with null or undefined");return Object(val)}function shouldUseNative(){try{if(!Object.assign)return!1;var test1=new String("abc");if(test1[5]="de","5"===Object.getOwnPropertyNames(test1)[0])return!1;var test2={};for(var i=0;i<10;i++)test2["_"+String.fromCharCode(i)]=i;var order2=Object.getOwnPropertyNames(test2).map(function(n){return test2[n]});if("0123456789"!==order2.join(""))return!1;var test3={};return"abcdefghijklmnopqrst".split("").forEach(function(letter){test3[letter]=letter}),"abcdefghijklmnopqrst"===Object.keys(Object.assign({},test3)).join("")}catch(e){return!1}}var hasOwnProperty=Object.prototype.hasOwnProperty;var propIsEnumerable=Object.prototype.propertyIsEnumerable;module.exports=shouldUseNative()?Object.assign:function(target,source){var from;var to=toObject(target);var symbols;for(var s=1;s1&&groupId){var filteredGroups=$.grep(groupList,function(resGroup){return resGroup.groupId===groupId});group=1===filteredGroups.length?filteredGroups[0]:null}if(group){var isFac=!!isTeamMember||"facilitator"===_findUserInGroup(group.members,userInfo.user_id).role;var groupData={groupId:group.groupId,groupName:group.name,isFac:isFac};var sessionInfoWithGroup=objectAssign({},sessionInfo,groupData);sessionInfo.groups[project]=groupData,_this.sessionManager.saveSession(sessionInfoWithGroup,adapterOptions),outSuccess.apply(this,[data]),$d.resolve(data)}else handleGroupError("This user is associated with more than one group. Please specify a group id to log into and try again",403,data)};if(isTeamMember){var opts=objectAssign({},userGroupOpts,{token:token});var groupService=new GroupService(opts);groupService.getGroups({account:adapterOptions.account,project:project}).then(function(groups){groups.forEach(function(group){group.groupId=group.id}),handleGroupList(groups)},$d.reject)}else _this.getUserGroups({userId:userInfo.user_id,token:token},userGroupOpts).then(handleGroupList,$d.reject)};return adapterOptions.success=handleSuccess,adapterOptions.error=function(response){return adapterOptions.account?(adapterOptions.account=null,adapterOptions.error=function(){outError.apply(this,arguments),$d.reject(response)},void _this.authAdapter.login(adapterOptions)):(outError.apply(this,arguments),void $d.reject(response))},this.authAdapter.login(adapterOptions),$d.promise()},logout:function(options){var _this=this;var adapterOptions=this.sessionManager.getMergedOptions(options);var removeCookieFn=function(response){_this.sessionManager.removeSession()};return this.authAdapter.logout(adapterOptions).done(removeCookieFn)},getToken:function(options){var httpOptions=this.sessionManager.getMergedOptions(options);var session=this.sessionManager.getSession();var $d=$.Deferred();return session.auth_token?$d.resolve(session.auth_token):this.login(httpOptions).then($d.resolve),$d.promise()},getUserGroups:function(params,options){var adapterOptions=this.sessionManager.getMergedOptions({success:$.noop},options);var $d=$.Deferred();var outSuccess=adapterOptions.success;adapterOptions.success=function(memberInfo){adapterOptions.project&&(memberInfo=$.grep(memberInfo,function(group){return group.project===adapterOptions.project})),outSuccess.apply(this,[memberInfo]),$d.resolve(memberInfo)};var memberAdapter=new MemberAdapter({token:params.token});return memberAdapter.getGroupsForUser(params,adapterOptions).fail($d.reject),$d.promise()},getCurrentUserSessionInfo:function(options){return this.sessionManager.getSession(options)},addGroups:function(groups){var session=this.getCurrentUserSessionInfo();var isArray=Array.isArray(groups);return groups=isArray?groups:[groups],$.each(groups,function(index,group){var extendedGroup=$.extend({},{isFac:!1},group);var project=extendedGroup.project;var validProps=["groupName","groupId","isFac"];if(!project||!extendedGroup.groupName)throw new Error("No project or groupName specified.");extendedGroup=_pick(extendedGroup,validProps),session.groups[project]=extendedGroup}),this.sessionManager.saveSession(session),session}}),module.exports=AuthManager; -},{"../service/auth-api-service":28,"../service/group-api-service":32,"../service/member-api-adapter":33,"../store/session-manager":42,"../util/object-util":48,"buffer":2,"object-assign":5}],10:[function(require,module,exports){ +},{"./service/url-config-service":35}],8:[function(require,module,exports){ +"use strict";function AuthManager(options){options=$.extend(!0,{},defaults,options),this.sessionManager=new SessionManager(options),this.options=this.sessionManager.getMergedOptions(),this.isLocal=this.options.isLocal,this.authAdapter=new AuthAdapter(this.options)}var AuthAdapter=require("../service/auth-api-service");var MemberAdapter=require("../service/member-api-adapter");var SessionManager=require("../store/session-manager");var Buffer=require("buffer").Buffer;var _pick=require("../util/object-util")._pick;var defaults={requiresGroup:!0};var _findUserInGroup=function(members,id){for(var j=0;j1&&groupId){var filteredGroups=$.grep(memberInfo,function(resGroup){return resGroup.groupId===groupId});group=1===filteredGroups.length?filteredGroups[0]:null}if(group){var groupData={groupId:group.groupId,groupName:group.name,isFac:"facilitator"===_findUserInGroup(group.members,userInfo.user_id).role};var sessionInfoWithGroup=$.extend({},sessionInfo,groupData);sessionInfo.groups[project]=groupData,_this.sessionManager.saveSession(sessionInfoWithGroup,adapterOptions),outSuccess.apply(this,[data]),$d.resolve(data)}else handleGroupError("This user is associated with more than one group. Please specify a group id to log into and try again",403,data)}).fail($d.reject):(sessionManager.saveSession(sessionInfo),outSuccess.apply(this,[data]),void $d.resolve(data))};return adapterOptions.success=handleSuccess,adapterOptions.error=function(response){return adapterOptions.account?(adapterOptions.account=null,adapterOptions.error=function(){outError.apply(this,arguments),$d.reject(response)},void _this.authAdapter.login(adapterOptions)):(outError.apply(this,arguments),void $d.reject(response))},this.authAdapter.login(adapterOptions),$d.promise()},logout:function(options){var _this=this;var adapterOptions=this.sessionManager.getMergedOptions(options);var removeCookieFn=function(response){_this.sessionManager.removeSession()};return this.authAdapter.logout(adapterOptions).done(removeCookieFn)},getToken:function(options){var httpOptions=this.sessionManager.getMergedOptions(options);var session=this.sessionManager.getSession();var $d=$.Deferred();return session.auth_token?$d.resolve(session.auth_token):this.login(httpOptions).then($d.resolve),$d.promise()},getUserGroups:function(params,options){var adapterOptions=this.sessionManager.getMergedOptions({success:$.noop},options);var $d=$.Deferred();var outSuccess=adapterOptions.success;adapterOptions.success=function(memberInfo){adapterOptions.project&&(memberInfo=$.grep(memberInfo,function(group){return group.project===adapterOptions.project})),outSuccess.apply(this,[memberInfo]),$d.resolve(memberInfo)};var memberAdapter=new MemberAdapter({token:params.token});return memberAdapter.getGroupsForUser(params,adapterOptions).fail($d.reject),$d.promise()},getCurrentUserSessionInfo:function(options){return this.sessionManager.getSession(options)},addGroups:function(groups){var session=this.getCurrentUserSessionInfo();var isArray=Array.isArray(groups);return groups=isArray?groups:[groups],$.each(groups,function(index,group){var extendedGroup=$.extend({},{isFac:!1},group);var project=extendedGroup.project;var validProps=["groupName","groupId","isFac"];if(!project||!extendedGroup.groupName)throw new Error("No project or groupName specified.");extendedGroup=_pick(extendedGroup,validProps),session.groups[project]=extendedGroup}),this.sessionManager.saveSession(session),session}}),module.exports=AuthManager; +},{"../service/auth-api-service":27,"../service/member-api-adapter":32,"../store/session-manager":40,"../util/object-util":46,"buffer":2}],9:[function(require,module,exports){ "use strict";var Channel=require("../service/channel-service");var SessionManager=require("../store/session-manager");var ChannelManager=function(options){if(!$.cometd)throw new Error("Cometd library not found. Please include epicenter-multiplayer-dependencies.js");if(!options||!options.url)throw new Error("Please provide an url for the cometd server");var defaults={url:"",logLevel:"info",websocketEnabled:!1,shareConnection:!1,channel:{},handshake:void 0};this.sessionManager=new SessionManager;var defaultCometOptions=this.sessionManager.getMergedOptions(defaults,options);if(this.currentSubscriptions=[],this.options=defaultCometOptions,defaultCometOptions.shareConnection&&ChannelManager.prototype._cometd)return this.cometd=ChannelManager.prototype._cometd,this;var cometd=new $.Cometd;ChannelManager.prototype._cometd=cometd,cometd.websocketEnabled=defaultCometOptions.websocketEnabled,this.isConnected=!1;var connectionBroken=function(message){$(this).trigger("disconnect",message)};var connectionSucceeded=function(message){$(this).trigger("connect",message)};var me=this;cometd.configure(defaultCometOptions),cometd.addListener("/meta/connect",function(message){var wasConnected=this.isConnected;this.isConnected=message.successful===!0,!wasConnected&&this.isConnected?connectionSucceeded.call(this,message):wasConnected&&!this.isConnected&&connectionBroken.call(this,message)}.bind(this)),cometd.addListener("/meta/disconnect",connectionBroken),cometd.addListener("/meta/handshake",function(message){message.successful&&cometd.batch(function(){$(me.currentSubscriptions).each(function(index,subs){cometd.resubscribe(subs)})})}),cometd.addListener("/meta/subscribe",function(message){$(me).trigger("subscribe",message)}),cometd.addListener("/meta/unsubscribe",function(message){$(me).trigger("unsubscribe",message)}),cometd.addListener("/meta/publish",function(message){$(me).trigger("publish",message)}),cometd.addListener("/meta/unsuccessful",function(message){$(me).trigger("error",message)}),cometd.handshake(defaultCometOptions.handshake),this.cometd=cometd};ChannelManager.prototype=$.extend(ChannelManager.prototype,{getChannel:function(options){options&&!$.isPlainObject(options)&&(options={base:options});var defaults={transport:this.cometd};var channel=new Channel($.extend(!0,{},this.options.channel,defaults,options));var subs=channel.subscribe;channel.subscribe=function(){var subid=subs.apply(channel,arguments);return this.currentSubscriptions=this.currentSubscriptions.concat(subid),subid}.bind(this);var unsubs=channel.unsubscribe;return channel.unsubscribe=function(){var removed=unsubs.apply(channel,arguments);for(var i=0;i=threshold?(getOptions.url=urlConfig.getAPIPath("user")+"?_method=GET",http.post({id:filter.id},getOptions)):http.get(getFilters,getOptions)},getById:function(userId,options){return publicAPI.get({id:userId},options)}};$.extend(this,publicAPI)}; -},{"../store/session-manager":42,"../transport/http-transport-factory":45,"../util/query-util":50,"./configuration-service":30}],39:[function(require,module,exports){ +},{"../store/session-manager":40,"../transport/http-transport-factory":43,"../util/query-util":48,"./configuration-service":29}],37:[function(require,module,exports){ "use strict";var TransportFactory=require("../transport/http-transport-factory");var rutil=require("../util/run-util");module.exports=function(config){var defaults={runService:null};var serviceOptions=$.extend({},defaults,config);var getURL=function(){return serviceOptions.runService.urlConfig.getFilterURL()+"variables/"};var addAutoRestoreHeader=function(options){return serviceOptions.runService.urlConfig.addAutoRestoreHeader(options)};var httpOptions={url:getURL};serviceOptions.token&&(httpOptions.headers={Authorization:"Bearer "+serviceOptions.token});var http=new TransportFactory(httpOptions);http.splitGet=rutil.splitGetFactory(httpOptions);var publicAPI={load:function(variable,outputModifier,options){var httpOptions=$.extend(!0,{},serviceOptions,options);return httpOptions=addAutoRestoreHeader(httpOptions),http.get(outputModifier,$.extend({},httpOptions,{url:getURL()+variable+"/"}))},query:function(query,outputModifier,options){var httpOptions=$.extend(!0,{},serviceOptions,options);return httpOptions=addAutoRestoreHeader(httpOptions),$.isArray(query)&&(query={include:query}),$.extend(query,outputModifier),http.splitGet(query,httpOptions)},save:function(variable,val,options){var attrs;"object"==typeof variable?(attrs=variable,options=val):(attrs={})[variable]=val;var httpOptions=$.extend(!0,{},serviceOptions,options);return http.patch.call(this,attrs,httpOptions)}};$.extend(this,publicAPI)}; -},{"../transport/http-transport-factory":45,"../util/run-util":51}],40:[function(require,module,exports){ -"use strict";var ConfigService=require("./configuration-service");var TransportFactory=require("../transport/http-transport-factory");var SessionManager=require("../store/session-manager");var _pick=require("../util/object-util")._pick;var apiBase="multiplayer/";var assignmentEndpoint=apiBase+"assign";var apiEndpoint=apiBase+"world";var projectEndpoint=apiBase+"project";module.exports=function(config){var defaults={token:void 0,project:void 0,account:void 0,group:void 0,model:void 0,filter:"",id:"",transport:{},success:$.noop,error:$.noop};this.sessionManager=new SessionManager;var serviceOptions=this.sessionManager.getMergedOptions(defaults,config);serviceOptions.id&&(serviceOptions.filter=serviceOptions.id);var urlConfig=new ConfigService(serviceOptions).get("server");serviceOptions.account||(serviceOptions.account=urlConfig.accountPath),serviceOptions.project||(serviceOptions.project=urlConfig.projectPath);var transportOptions=$.extend(!0,{},serviceOptions.transport,{url:urlConfig.getAPIPath(apiEndpoint)});serviceOptions.token&&(transportOptions.headers={Authorization:"Bearer "+serviceOptions.token});var http=new TransportFactory(transportOptions);var setIdFilterOrThrowError=function(options){if(options.id&&(serviceOptions.filter=options.id),options.filter&&(serviceOptions.filter=options.filter),!serviceOptions.filter)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.")};var validateModelOrThrowError=function(options){if(!options.model)throw new Error("No model specified to get the current run")};var publicAPI={create:function(params,options){var createOptions=$.extend(!0,{},serviceOptions,options,{url:urlConfig.getAPIPath(apiEndpoint)});var worldApiParams=["scope","files","roles","optionalRoles","minUsers","group","name"];var validParams=_pick(serviceOptions,["account","project","group"]);params=_pick(params,worldApiParams),params=$.extend({},validParams,params);var oldSuccess=createOptions.success;return createOptions.success=function(response){return serviceOptions.filter=response.id,oldSuccess.apply(this,arguments)},http.post(params,createOptions)},update:function(params,options){var whitelist=["roles","optionalRoles","minUsers"];options=options||{},setIdFilterOrThrowError(options);var updateOptions=$.extend(!0,{},serviceOptions,options,{url:urlConfig.getAPIPath(apiEndpoint)+serviceOptions.filter});return params=_pick(params||{},whitelist),http.patch(params,updateOptions)},delete:function(options){options=options&&"string"==typeof options?{filter:options}:{},setIdFilterOrThrowError(options);var deleteOptions=$.extend(!0,{},serviceOptions,options,{url:urlConfig.getAPIPath(apiEndpoint)+serviceOptions.filter});return http.delete(null,deleteOptions)},updateConfig:function(config){return $.extend(serviceOptions,config),this},list:function(options){options=options||{};var getOptions=$.extend(!0,{},serviceOptions,options,{url:urlConfig.getAPIPath(apiEndpoint)});var filters=_pick(getOptions,["account","project","group"]);return http.get(filters,getOptions)},getWorldsForUser:function(userId,options){options=options||{};var getOptions=$.extend(!0,{},serviceOptions,options,{url:urlConfig.getAPIPath(apiEndpoint)});var filters=$.extend(_pick(getOptions,["account","project","group"]),{userId:userId});return http.get(filters,getOptions)},load:function(worldId,options){if(worldId&&(serviceOptions.filter=worldId),!serviceOptions.filter)throw new Error("Please provide a worldid to load");var httpOptions=$.extend(!0,{},serviceOptions,options,{url:urlConfig.getAPIPath(apiEndpoint)+serviceOptions.filter+"/"});return http.get("",httpOptions)},addUsers:function(users,worldId,options){if(!users)throw new Error("Please provide a list of users to add to the world");users=$.map([].concat(users),function(u){var isObject=$.isPlainObject(u);if("string"!=typeof u&&!isObject)throw new Error("Some of the users in the list are not in the valid format: "+u);return isObject?u:{userId:u}}),$.isPlainObject(worldId)&&!options&&(options=worldId,worldId=null),options=options||{},"string"==typeof worldId&&(options.filter=worldId),setIdFilterOrThrowError(options);var updateOptions=$.extend(!0,{},serviceOptions,options,{url:urlConfig.getAPIPath(apiEndpoint)+serviceOptions.filter+"/users"});return http.post(users,updateOptions)},updateUser:function(user,options){if(options=options||{},!user||!user.userId)throw new Error("You need to pass a userId to update from the world");setIdFilterOrThrowError(options);var patchOptions=$.extend(!0,{},serviceOptions,options,{url:urlConfig.getAPIPath(apiEndpoint)+serviceOptions.filter+"/users/"+user.userId});return http.patch(_pick(user,"role"),patchOptions)},removeUser:function(user,options){if(options=options||{},"string"==typeof user&&(user={userId:user}),!user.userId)throw new Error("You need to pass a userId to remove from the world");setIdFilterOrThrowError(options);var getOptions=$.extend(!0,{},serviceOptions,options,{url:urlConfig.getAPIPath(apiEndpoint)+serviceOptions.filter+"/users/"+user.userId});return http.delete(null,getOptions)},getCurrentRunId:function(options){options=options||{},setIdFilterOrThrowError(options);var getOptions=$.extend(!0,{},serviceOptions,options,{url:urlConfig.getAPIPath(apiEndpoint)+serviceOptions.filter+"/run"});return validateModelOrThrowError(getOptions),http.post(_pick(getOptions,"model"),getOptions)},getCurrentWorldForUser:function(userId,groupName){var dtd=$.Deferred();var me=this;return this.getWorldsForUser(userId,{group:groupName}).then(function(worlds){worlds.sort(function(a,b){return new Date(b.lastModified)-new Date(a.lastModified)});var currentWorld=worlds[0];currentWorld&&(serviceOptions.filter=currentWorld.id),dtd.resolve(currentWorld,me)}).fail(dtd.reject),dtd.promise()},deleteRun:function(worldId,options){options=options||{},worldId&&(options.filter=worldId),setIdFilterOrThrowError(options);var deleteOptions=$.extend(!0,{},serviceOptions,options,{url:urlConfig.getAPIPath(apiEndpoint)+serviceOptions.filter+"/run"});return http.delete(null,deleteOptions)},newRunForWorld:function(worldId,options){var currentRunOptions=$.extend(!0,{},options,{filter:worldId||serviceOptions.filter});var _this=this;return validateModelOrThrowError(currentRunOptions),this.deleteRun(worldId,options).then(function(){return _this.getCurrentRunId(currentRunOptions)})},autoAssign:function(options){options=options||{};var opt=$.extend(!0,{},serviceOptions,options,{url:urlConfig.getAPIPath(assignmentEndpoint)});var params={account:opt.account,project:opt.project,group:opt.group};return opt.maxUsers&&(params.maxUsers=opt.maxUsers),http.post(params,opt)},getProjectSettings:function(options){options=options||{};var opt=$.extend(!0,{},serviceOptions,options,{url:urlConfig.getAPIPath(projectEndpoint)});return opt.url+=[opt.account,opt.project].join("/"),http.get(null,opt)}};$.extend(this,publicAPI)}; -},{"../store/session-manager":42,"../transport/http-transport-factory":45,"../util/object-util":48,"./configuration-service":30}],41:[function(require,module,exports){ -"use strict";var Cookie=function(){this.get=function(){return document.cookie},this.set=function(newCookie){document.cookie=newCookie}};module.exports=function(config){var host=window.location.hostname;var validHost=host.split(".").length>1;var domain=validHost?"."+host:null;var defaults={root:"/",domain:domain,cookie:new Cookie};this.serviceOptions=$.extend({},defaults,config);var publicAPI={set:function(key,value,options){var setOptions=$.extend(!0,{},this.serviceOptions,options);var domain=setOptions.domain;var path=setOptions.root;var cookie=setOptions.cookie;return cookie.set(encodeURIComponent(key)+"="+encodeURIComponent(value)+(domain?"; domain="+domain:"")+(path?"; path="+path:"")),value},get:function(key){var cookie=this.serviceOptions.cookie;var cookieReg=new RegExp("(?:^|;)\\s*"+encodeURIComponent(key).replace(/[\-\.\+\*]/g,"\\$&")+"\\s*\\=\\s*([^;]*).*$");var res=cookieReg.exec(cookie.get());var val=res?decodeURIComponent(res[1]):null;return val},remove:function(key,options){var remOptions=$.extend(!0,{},this.serviceOptions,options);var domain=remOptions.domain;var path=remOptions.root;var cookie=remOptions.cookie;return cookie.set(encodeURIComponent(key)+"=; expires=Thu, 01 Jan 1970 00:00:00 GMT"+(domain?"; domain="+domain:"")+(path?"; path="+path:"")),key},destroy:function(){var cookie=this.serviceOptions.cookie;var aKeys=cookie.get().replace(/((?:^|\s*;)[^\=]+)(?=;|$)|^\s*|\s*(?:\=[^;]*)?(?:\1|$)/g,"").split(/\s*(?:\=[^;]*)?;\s*/);for(var nIdx=0;nIdx","!"];$.each(qs,function(key,value){"string"==typeof value&&$.inArray($.trim(value).charAt(0),OPERATORS)!==-1||(value="="+value),returnArray.push(key+value)});var mtrx=";"+returnArray.join(";");return mtrx},toQueryFormat:function(qs){if(null===qs||void 0===qs)return"";if("string"==typeof qs||qs instanceof String)return qs;var returnArray=[];$.each(qs,function(key,value){$.isArray(value)&&(value=value.join(",")),$.isPlainObject(value)&&(value=JSON.stringify(value)),returnArray.push(key+"="+value)});var result=returnArray.join("&");return result},qsToObject:function(qs){if(null===qs||void 0===qs||""===qs)return{};var qsArray=qs.split("&");var returnObj={};return $.each(qsArray,function(index,value){var qKey=value.split("=")[0];var qVal=value.split("=")[1];qVal.indexOf(",")!==-1&&(qVal=qVal.split(",")),returnObj[qKey]=qVal}),returnObj},mergeQS:function(qs1,qs2){var obj1=this.qsToObject(this.toQueryFormat(qs1));var obj2=this.qsToObject(this.toQueryFormat(qs2));return $.extend(!0,{},obj1,obj2)},addTrailingSlash:function(url){return url?"/"===url.charAt(url.length-1)?url:url+"/":""}}}(); -},{}],51:[function(require,module,exports){ +},{}],49:[function(require,module,exports){ "use strict";var qutil=require("./query-util");var MAX_URL_LENGTH=2048;module.exports=function(){return{normalizeOperations:function(operations,args){args||(args=[]);var returnList={ops:[],args:[]};var _concat=function(arr){return null!==arr&&void 0!==arr?[].concat(arr):[]};var _normalizePlainObjects=function(operations,returnList){return returnList||(returnList={ops:[],args:[]}),$.each(operations,function(opn,arg){returnList.ops.push(opn),returnList.args.push(_concat(arg))}),returnList};var _normalizeStructuredObjects=function(operation,returnList){return returnList||(returnList={ops:[],args:[]}),returnList.ops.push(operation.name),returnList.args.push(_concat(operation.params)),returnList};var _normalizeObject=function(operation,returnList){return(operation.name?_normalizeStructuredObjects:_normalizePlainObjects)(operation,returnList)};var _normalizeLiterals=function(operation,args,returnList){return returnList||(returnList={ops:[],args:[]}),returnList.ops.push(operation),returnList.args.push(_concat(args)),returnList};var _normalizeArrays=function(operations,arg,returnList){return returnList||(returnList={ops:[],args:[]}),$.each(operations,function(index,opn){$.isPlainObject(opn)?_normalizeObject(opn,returnList):_normalizeLiterals(opn,args[index],returnList)}),returnList};return $.isPlainObject(operations)?_normalizeObject(operations,returnList):$.isArray(operations)?_normalizeArrays(operations,args,returnList):_normalizeLiterals(operations,args,returnList),returnList},splitGetFactory:function(httpOptions){return function(params,options){var http=this;var getValue=function(name){var value=options[name]||httpOptions[name];return"function"==typeof value&&(value=value()),value};var getFinalUrl=function(params){var url=getValue("url",options);var data=params;url=url.replace(/#.*$/,"");var queryParams=qutil.toQueryFormat(data);var questionIdx=url.indexOf("?");return queryParams&&questionIdx>-1?url+"&"+queryParams:queryParams?url+"?"+queryParams:url};var url=getFinalUrl(params);if(params&¶ms.include&&encodeURI(url).length>MAX_URL_LENGTH){var dtd=$.Deferred();var paramsCopy=$.extend(!0,{},params);delete paramsCopy.include;var urlNoIncludes=getFinalUrl(paramsCopy);var diff=MAX_URL_LENGTH-urlNoIncludes.length;var oldSuccess=options.success||httpOptions.success||$.noop;var oldError=options.error||httpOptions.error||$.noop;options.success=$.noop,options.error=$.noop;var include=params.include;var currIncludes=[];var includeOpts=[currIncludes];var currLength=encodeURIComponent("?include=").length;var variable=include.pop();for(;variable;){var varLenght=encodeURIComponent(variable).length;currLength+varLenght+1\n * https://github.com/forio/epicenter-js-libs\n */\n\nvar F = {\n util: {},\n factory: {},\n transport: {},\n store: {},\n service: {},\n manager: {\n strategy: {}\n },\n\n};\n\nF.load = require('./env-load');\nF.load();\n\nF.util.query = require('./util/query-util');\nF.util.makeSequence = require('./util/make-sequence');\nF.util.run = require('./util/run-util');\nF.util.classFrom = require('./util/inherit');\n\nF.factory.Transport = require('./transport/http-transport-factory');\nF.transport.Ajax = require('./transport/ajax-http-transport');\n\nF.service.URL = require('./service/url-config-service');\nF.service.Config = require('./service/configuration-service');\nF.service.Run = require('./service/run-api-service');\nF.service.File = require('./service/admin-file-service');\nF.service.Variables = require('./service/variables-api-service');\nF.service.Data = require('./service/data-api-service');\nF.service.Auth = require('./service/auth-api-service');\nF.service.World = require('./service/world-api-adapter');\nF.service.State = require('./service/state-api-adapter');\nF.service.User = require('./service/user-api-adapter');\nF.service.Member = require('./service/member-api-adapter');\nF.service.Asset = require('./service/asset-api-adapter');\nF.service.Group = require('./service/group-api-service');\n\nF.store.Cookie = require('./store/cookie-store');\nF.factory.Store = require('./store/store-factory');\n\nF.manager.ScenarioManager = require('./managers/scenario-manager');\nF.manager.RunManager = require('./managers/run-manager');\nF.manager.AuthManager = require('./managers/auth-manager');\nF.manager.WorldManager = require('./managers/world-manager');\n\nF.manager.strategy['always-new'] = require('./managers/run-strategies/always-new-strategy');\nF.manager.strategy['conditional-creation'] = require('./managers/run-strategies/conditional-creation-strategy');\nF.manager.strategy.identity = require('./managers/run-strategies/identity-strategy');\nF.manager.strategy['new-if-missing'] = require('./managers/run-strategies/new-if-missing-strategy');\nF.manager.strategy['new-if-missing'] = require('./managers/run-strategies/new-if-missing-strategy');\nF.manager.strategy['new-if-persisted'] = require('./managers/run-strategies/new-if-persisted-strategy');\nF.manager.strategy['new-if-initialized'] = require('./managers/run-strategies/new-if-initialized-strategy');\n\nF.manager.ChannelManager = require('./managers/epicenter-channel-manager');\nF.service.Channel = require('./service/channel-service');\n\nF.version = '<%= version %>';\nF.api = require('./api-version.json');\n\nglobal.F = F;\nmodule.exports = F;\n","'use strict';\n\nvar urlConfigService = require('./service/url-config-service');\n\nvar envLoad = function (callback) {\n var envPromise;\n var host;\n var urlService = urlConfigService();\n var envPath = '/epicenter/v1/config';\n if (urlService.isLocalhost()) {\n host = 'https://forio.com';\n } else {\n host = '';\n }\n var infoUrl = host + envPath;\n envPromise = $.ajax({ url: infoUrl, async: false });\n envPromise.done(function (res) {\n var api = res.api;\n $.extend(urlConfigService, api);\n }).fail(function (res) {\n // Epicenter/webserver not properly configured\n // fallback to api.forio.com\n $.extend(urlConfigService, { protocol: 'https', host: 'api.forio.com' });\n });\n return envPromise.done(callback).fail(callback);\n};\n\nmodule.exports = envLoad;\n","/**\n * Utilities for working with query strings\n*/\n'use strict';\n\nmodule.exports = (function () {\n\n return {\n /**\n * Converts to matrix format\n * @param {Object} qs Object to convert to query string\n * @return { string} Matrix-format query parameters\n */\n toMatrixFormat: function (qs) {\n if (qs === null || qs === undefined || qs === '') {\n return ';';\n }\n if (typeof qs === 'string' || qs instanceof String) {\n return qs;\n }\n\n var returnArray = [];\n var OPERATORS = ['<', '>', '!'];\n $.each(qs, function (key, value) {\n if (typeof value !== 'string' || $.inArray($.trim(value).charAt(0), OPERATORS) === -1) {\n value = '=' + value;\n }\n returnArray.push(key + value);\n });\n\n var mtrx = ';' + returnArray.join(';');\n return mtrx;\n },\n\n /**\n * Converts strings/arrays/objects to type 'a=b&b=c'\n * @param { string|Array|Object} qs\n * @return { string}\n */\n toQueryFormat: function (qs) {\n if (qs === null || qs === undefined) {\n return '';\n }\n if (typeof qs === 'string' || qs instanceof String) {\n return qs;\n }\n\n var returnArray = [];\n $.each(qs, function (key, value) {\n if ($.isArray(value)) {\n value = value.join(',');\n }\n if ($.isPlainObject(value)) {\n //Mostly for data api\n value = JSON.stringify(value);\n }\n returnArray.push(key + '=' + value);\n });\n\n var result = returnArray.join('&');\n return result;\n },\n\n /**\n * Converts strings of type 'a=b&b=c' to { a:b, b:c}\n * @param { string} qs\n * @return {object}\n */\n qsToObject: function (qs) {\n if (qs === null || qs === undefined || qs === '') {\n return {};\n }\n\n var qsArray = qs.split('&');\n var returnObj = {};\n $.each(qsArray, function (index, value) {\n var qKey = value.split('=')[0];\n var qVal = value.split('=')[1];\n\n if (qVal.indexOf(',') !== -1) {\n qVal = qVal.split(',');\n }\n\n returnObj[qKey] = qVal;\n });\n\n return returnObj;\n },\n\n /**\n * Normalizes and merges strings of type 'a=b', { b:c} to { a:b, b:c}\n * @param { string|Array|Object} qs1\n * @param { string|Array|Object} qs2\n * @return {Object}\n */\n mergeQS: function (qs1, qs2) {\n var obj1 = this.qsToObject(this.toQueryFormat(qs1));\n var obj2 = this.qsToObject(this.toQueryFormat(qs2));\n return $.extend(true, {}, obj1, obj2);\n },\n\n addTrailingSlash: function (url) {\n if (!url) {\n return '';\n }\n return (url.charAt(url.length - 1) === '/') ? url : (url + '/');\n }\n };\n}());\n\n\n\n","'use strict';\n/*jshint loopfunc:false */\n\nfunction _w(val) {\n if (val && val.then) {\n return val;\n }\n var p = $.Deferred();\n p.resolve(val);\n\n return p.promise();\n}\n\nfunction seq() {\n var list = Array.prototype.slice.apply(arguments);\n\n function next(p) {\n var cur = list.splice(0,1)[0];\n\n if (!cur) {\n return p;\n }\n\n return _w(cur(p)).then(next);\n }\n\n return function (seed) {\n return next(seed).fail(seq.fail);\n };\n}\n\nfunction MakeSeq(obj) {\n var res = {\n __calls: [],\n\n original: obj,\n\n then: function (fn) {\n this.__calls.push(fn);\n return this;\n },\n\n start: function () {\n var _this = this;\n\n // clean up\n this.then(function (run) {\n _this.__calls.length = 0;\n return run;\n });\n\n return seq.apply(null, this.__calls)();\n },\n\n fail: function (fn) {\n seq.fail = fn;\n return this;\n }\n };\n\n var funcMaker = function (p, obj) {\n var fn = obj[p].bind(obj);\n return function () {\n var args = Array.prototype.slice.apply(arguments);\n this.__calls.push(Function.bind.apply(fn, [null].concat(args)));\n return this;\n };\n };\n\n for (var prop in obj) {\n if (typeof obj[prop] === 'function') {\n res[prop] = funcMaker(prop, obj);\n } else {\n res[prop] = obj[prop];\n }\n }\n\n return res;\n}\n\nmodule.exports = MakeSeq;\n","/**\n * Utilities for working with the run service\n*/\n'use strict';\nvar qutil = require('./query-util');\nvar MAX_URL_LENGTH = 2048;\n\nmodule.exports = (function () {\n return {\n /**\n * returns operations of the form `[[op1,op2], [arg1, arg2]]`\n * @param {Object|Array|String} `operations` operations to perform\n * @param {Array} `args` arguments for operation\n * @return {String} Matrix-format query parameters\n */\n normalizeOperations: function (operations, args) {\n if (!args) {\n args = [];\n }\n var returnList = {\n ops: [],\n args: []\n };\n\n var _concat = function (arr) {\n return (arr !== null && arr !== undefined) ? [].concat(arr) : [];\n };\n\n //{ add: [1,2], subtract: [2,4] }\n var _normalizePlainObjects = function (operations, returnList) {\n if (!returnList) {\n returnList = { ops: [], args: [] };\n }\n $.each(operations, function (opn, arg) {\n returnList.ops.push(opn);\n returnList.args.push(_concat(arg));\n });\n return returnList;\n };\n //{ name: 'add', params: [1] }\n var _normalizeStructuredObjects = function (operation, returnList) {\n if (!returnList) {\n returnList = { ops: [], args: [] };\n }\n returnList.ops.push(operation.name);\n returnList.args.push(_concat(operation.params));\n return returnList;\n };\n\n var _normalizeObject = function (operation, returnList) {\n return ((operation.name) ? _normalizeStructuredObjects : _normalizePlainObjects)(operation, returnList);\n };\n\n var _normalizeLiterals = function (operation, args, returnList) {\n if (!returnList) {\n returnList = { ops: [], args: [] };\n }\n returnList.ops.push(operation);\n returnList.args.push(_concat(args));\n return returnList;\n };\n\n\n var _normalizeArrays = function (operations, arg, returnList) {\n if (!returnList) {\n returnList = { ops: [], args: [] };\n }\n $.each(operations, function (index, opn) {\n if ($.isPlainObject(opn)) {\n _normalizeObject(opn, returnList);\n } else {\n _normalizeLiterals(opn, args[index], returnList);\n }\n });\n return returnList;\n };\n\n if ($.isPlainObject(operations)) {\n _normalizeObject(operations, returnList);\n } else if ($.isArray(operations)) {\n _normalizeArrays(operations, args, returnList);\n } else {\n _normalizeLiterals(operations, args, returnList);\n }\n\n return returnList;\n },\n\n splitGetFactory: function (httpOptions) {\n return function (params, options) {\n var http = this;\n var getValue = function (name) {\n var value = options[name] || httpOptions[name];\n if (typeof value === 'function') {\n value = value();\n }\n return value;\n };\n var getFinalUrl = function (params) {\n var url = getValue('url', options);\n var data = params;\n // There is easy (or known) way to get the final URL jquery is going to send so\n // we're replicating it. The process might change at some point but it probably will not.\n // 1. Remove hash\n url = url.replace(/#.*$/, '');\n // 1. Append query string\n var queryParams = qutil.toQueryFormat(data);\n var questionIdx = url.indexOf('?');\n if (queryParams && questionIdx > -1) {\n return url + '&' + queryParams;\n } else if (queryParams) {\n return url + '?' + queryParams;\n }\n return url;\n };\n var url = getFinalUrl(params);\n // We must split the GET in multiple short URL's\n // The only property allowed to be split is \"include\"\n if (params && params.include && encodeURI(url).length > MAX_URL_LENGTH) {\n var dtd = $.Deferred();\n var paramsCopy = $.extend(true, {}, params);\n delete paramsCopy.include;\n var urlNoIncludes = getFinalUrl(paramsCopy);\n var diff = MAX_URL_LENGTH - urlNoIncludes.length;\n var oldSuccess = options.success || httpOptions.success || $.noop;\n var oldError = options.error || httpOptions.error || $.noop;\n // remove the original success and error callbacks\n options.success = $.noop;\n options.error = $.noop;\n\n var include = params.include;\n var currIncludes = [];\n var includeOpts = [currIncludes];\n var currLength = encodeURIComponent('?include=').length;\n var variable = include.pop();\n while (variable) {\n var varLenght = encodeURIComponent(variable).length;\n // Use a greedy approach for now, can be optimized to be solved in a more\n // efficient way\n // + 1 is the comma\n if (currLength + varLenght + 1 < diff) {\n currIncludes.push(variable);\n currLength += varLenght + 1;\n } else {\n currIncludes = [variable];\n includeOpts.push(currIncludes);\n currLength = '?include='.length + varLenght;\n }\n variable = include.pop();\n }\n var reqs = $.map(includeOpts, function (include) {\n var reqParams = $.extend({}, params, { include: include });\n return http.get(reqParams, options);\n });\n $.when.apply($, reqs).then(function () {\n // Each argument are arrays of the arguments of each done request\n // So the first argument of the first array of arguments is the data\n var isValid = arguments[0] && arguments[0][0];\n if (!isValid) {\n // Should never happen...\n oldError();\n return dtd.reject();\n }\n var firstResponse = arguments[0][0];\n var isObject = $.isPlainObject(firstResponse);\n var isRunAPI = (isObject && $.isPlainObject(firstResponse.variables)) || !isObject;\n if (isRunAPI) {\n if (isObject) {\n // aggregate the variables property only\n var aggregateRun = arguments[0][0];\n $.each(arguments, function (idx, args) {\n var run = args[0];\n $.extend(true, aggregateRun.variables, run.variables);\n });\n oldSuccess(aggregateRun, arguments[0][1], arguments[0][2]);\n dtd.resolve(aggregateRun, arguments[0][1], arguments[0][2]);\n } else {\n // array of runs\n // Agregate variables in each run\n var aggregatedRuns = {};\n $.each(arguments, function (idx, args) {\n var runs = args[0];\n if (!$.isArray(runs)) {\n return;\n }\n $.each(runs, function (idxRun, run) {\n if (run.id && !aggregatedRuns[run.id]) {\n run.variables = run.variables || {};\n aggregatedRuns[run.id] = run;\n } else if (run.id) {\n $.extend(true, aggregatedRuns[run.id].variables, run.variables);\n }\n });\n });\n // turn it into an array\n aggregatedRuns = $.map(aggregatedRuns, function (run) { return run; });\n oldSuccess(aggregatedRuns, arguments[0][1], arguments[0][2]);\n dtd.resolve(aggregatedRuns, arguments[0][1], arguments[0][2]);\n }\n } else {\n // is variables API\n // aggregate the response\n var aggregatedVariables = {};\n $.each(arguments, function (idx, args) {\n var vars = args[0];\n $.extend(true, aggregatedVariables, vars);\n });\n oldSuccess(aggregatedVariables, arguments[0][1], arguments[0][2]);\n dtd.resolve(aggregatedVariables, arguments[0][1], arguments[0][2]);\n }\n }, function () {\n oldError.apply(http, arguments);\n dtd.reject.apply(dtd, arguments);\n });\n return dtd.promise();\n } else {\n return http.get(params, options);\n }\n };\n }\n };\n}());\n","/**\n/* Inherit from a class (using prototype borrowing)\n*/\n'use strict';\n\nfunction inherit(C, P) {\n var F = function () {};\n F.prototype = P.prototype;\n C.prototype = new F();\n C.__super = P.prototype;\n C.prototype.constructor = C;\n}\n\n/**\n* Shallow copy of an object\n*/\nvar extend = function (dest /*, var_args*/) {\n var obj = Array.prototype.slice.call(arguments, 1);\n var current;\n for (var j = 0; j 1,\n * // where variables.price has been persisted (recorded)\n * // in the model.\n * rs.query({\n * 'saved': 'true',\n * '.price': '>1'\n * },\n * {\n * startrecord: 2,\n * endrecord: 5\n * });\n *\n * **Parameters**\n * @param {Object} `qs` Query object. Each key can be a property of the run or the name of variable that has been saved in the run (prefaced by `variables.`). Each value can be a literal value, or a comparison operator and value. (See [more on filtering](../../../rest_apis/aggregate_run_api/#filters) allowed in the underlying Run API.) Querying for variables is available for runs [in memory](../../../run_persistence/#runs-in-memory) and for runs [in the database](../../../run_persistence/#runs-in-memory) if the variables are persisted (e.g. that have been `record`ed in your Julia model).\n * @param {Object} `outputModifier` (Optional) Available fields include: `startrecord`, `endrecord`, `sort`, and `direction` (`asc` or `desc`).\n * @param {Object} `options` (Optional) Overrides for configuration options.\n */\n query: function (qs, outputModifier, options) {\n serviceOptions.filter = qs; //shouldn't be able to over-ride\n var httpOptions = $.extend(true, {}, serviceOptions, options);\n httpOptions = urlConfig.addAutoRestoreHeader(httpOptions);\n\n return http.splitGet(outputModifier, httpOptions);\n },\n\n /**\n * Returns particular runs, based on conditions specified in the `qs` object.\n *\n * Similar to `.query()`.\n *\n * **Parameters**\n * @param {Object} `filter` Filter object. Each key can be a property of the run or the name of variable that has been saved in the run (prefaced by `variables.`). Each value can be a literal value, or a comparison operator and value. (See [more on filtering](../../../rest_apis/aggregate_run_api/#filters) allowed in the underlying Run API.) Filtering for variables is available for runs [in memory](../../../run_persistence/#runs-in-memory) and for runs [in the database](../../../run_persistence/#runs-in-memory) if the variables are persisted (e.g. that have been `record`ed in your Julia model).\n * @param {Object} `outputModifier` (Optional) Available fields include: `startrecord`, `endrecord`, `sort`, and `direction` (`asc` or `desc`).\n * @param {Object} `options` (Optional) Overrides for configuration options.\n */\n filter: function (filter, outputModifier, options) {\n if ($.isPlainObject(serviceOptions.filter)) {\n $.extend(serviceOptions.filter, filter);\n } else {\n serviceOptions.filter = filter;\n }\n var httpOptions = $.extend(true, {}, serviceOptions, options);\n httpOptions = urlConfig.addAutoRestoreHeader(httpOptions);\n return http.splitGet(outputModifier, httpOptions);\n },\n\n /**\n * Get data for a specific run. This includes standard run data such as the account, model, project, and created and last modified dates. To request specific model variables, pass them as part of the `filters` parameter.\n *\n * Note that if the run is [in memory](../../../run_persistence/#runs-in-memory), any model variables are available; if the run is [in the database](../../../run_persistence/#runs-in-db), only model variables that have been persisted — that is, `record`ed in your Julia model — are available.\n *\n * **Example**\n *\n * rs.load('bb589677-d476-4971-a68e-0c58d191e450', { include: ['.price', '.sales'] });\n *\n * **Parameters**\n * @param {String} `runID` The run id.\n * @param {Object} `filters` (Optional) Object containing filters and operation modifiers. Use key `include` to list model variables that you want to include in the response. Other available fields include: `startrecord`, `endrecord`, `sort`, and `direction` (`asc` or `desc`).\n * @param {Object} `options` (Optional) Overrides for configuration options.\n */\n load: function (runID, filters, options) {\n if (runID) {\n serviceOptions.filter = runID; //shouldn't be able to over-ride\n }\n var httpOptions = $.extend(true, {}, serviceOptions, options);\n httpOptions = urlConfig.addAutoRestoreHeader(httpOptions);\n return http.get(filters, httpOptions);\n },\n\n\n /**\n * Save attributes (data, model variables) of the run.\n *\n * **Examples**\n *\n * // add 'completed' field to run record\n * rs.save({ completed: true });\n *\n * // update 'saved' field of run record, and update values of model variables for this run\n * rs.save({ saved: true, variables: { a: 23, b: 23 } });\n *\n * **Parameters**\n * @param {Object} `attributes` The run data and variables to save.\n * @param {Object} `attributes.variables` Model variables must be included in a `variables` field within the `attributes` object. (Otherwise they are treated as run data and added to the run record directly.)\n * @param {Object} `options` (Optional) Overrides for configuration options.\n */\n save: function (attributes, options) {\n var httpOptions = $.extend(true, {}, serviceOptions, options);\n setFilterOrThrowError(httpOptions);\n return http.patch(attributes, httpOptions);\n },\n\n /**\n * Call a method from the model.\n *\n * Depending on the language in which you have written your model, the method may need to be exposed (e.g. `export` for a Julia model) in the model file in order to be called through the API. See [Writing your Model](../../../writing_your_model/)).\n *\n * The `params` argument is normally an array of arguments to the `operation`. In the special case where `operation` only takes one argument, you are not required to put that argument into an array.\n *\n * Note that you can combine the `operation` and `params` arguments into a single object if you prefer, as in the last example.\n *\n * **Examples**\n *\n * // method \"solve\" takes no arguments\n * rs.do('solve');\n * // method \"echo\" takes one argument, a string\n * rs.do('echo', ['hello']);\n * // method \"echo\" takes one argument, a string\n * rs.do('echo', 'hello');\n * // method \"sumArray\" takes one argument, an array\n * rs.do('sumArray', [[4,2,1]]);\n * // method \"add\" takes two arguments, both integers\n * rs.do({ name:'add', params:[2,4] });\n *\n * **Parameters**\n * @param {String} `operation` Name of method.\n * @param {Array} `params` (Optional) Any parameters the operation takes, passed as an array. In the special case where `operation` only takes one argument, you are not required to put that argument into an array, and can just pass it directly.\n * @param {Object} `options` (Optional) Overrides for configuration options.\n */\n do: function (operation, params, options) {\n // console.log('do', operation, params);\n var opsArgs;\n var postOptions;\n if (options) {\n opsArgs = params;\n postOptions = options;\n } else {\n if ($.isPlainObject(params)) {\n opsArgs = null;\n postOptions = params;\n } else {\n opsArgs = params;\n }\n }\n var result = rutil.normalizeOperations(operation, opsArgs);\n var httpOptions = $.extend(true, {}, serviceOptions, postOptions);\n\n setFilterOrThrowError(httpOptions);\n\n var prms = (result.args[0].length && (result.args[0] !== null && result.args[0] !== undefined)) ? result.args[0] : [];\n return http.post({ arguments: prms }, $.extend(true, {}, httpOptions, {\n url: urlConfig.getFilterURL() + 'operations/' + result.ops[0] + '/'\n }));\n },\n\n /**\n * Call several methods from the model, sequentially.\n *\n * Depending on the language in which you have written your model, the methods may need to be exposed (e.g. `export` for a Julia model) in the model file in order to be called through the API. See [Writing your Model](../../../writing_your_model/)).\n *\n * **Examples**\n *\n * // methods \"initialize\" and \"solve\" do not take any arguments\n * rs.serial(['initialize', 'solve']);\n * // methods \"init\" and \"reset\" take two arguments each\n * rs.serial([ { name: 'init', params: [1,2] },\n * { name: 'reset', params: [2,3] }]);\n * // method \"init\" takes two arguments,\n * // method \"runmodel\" takes none\n * rs.serial([ { name: 'init', params: [1,2] },\n * { name: 'runmodel', params: [] }]);\n *\n * **Parameters**\n * @param {Array} `operations` If none of the methods take parameters, pass an array of the method names (strings). If any of the methods do take parameters, pass an array of objects, each of which contains a method name and its own (possibly empty) array of parameters.\n * @param {*} `params` Parameters to pass to operations.\n * @param {Object} `options` (Optional) Overrides for configuration options.\n */\n serial: function (operations, params, options) {\n var opParams = rutil.normalizeOperations(operations, params);\n var ops = opParams.ops;\n var args = opParams.args;\n var me = this;\n\n var $d = $.Deferred();\n var postOptions = $.extend(true, {}, serviceOptions, options);\n\n var doSingleOp = function () {\n var op = ops.shift();\n var arg = args.shift();\n\n me.do(op, arg, {\n success: function () {\n if (ops.length) {\n doSingleOp();\n } else {\n $d.resolve.apply(this, arguments);\n postOptions.success.apply(this, arguments);\n }\n },\n error: function () {\n $d.reject.apply(this, arguments);\n postOptions.error.apply(this, arguments);\n }\n });\n };\n\n doSingleOp();\n\n return $d.promise();\n },\n\n /**\n * Call several methods from the model, executing them in parallel.\n *\n * Depending on the language in which you have written your model, the methods may need to be exposed (e.g. `export` for a Julia model) in the model file in order to be called through the API. See [Writing your Model](../../../writing_your_model/)).\n *\n * **Example**\n *\n * // methods \"solve\" and \"reset\" do not take any arguments\n * rs.parallel(['solve', 'reset']);\n * // methods \"add\" and \"subtract\" take two arguments each\n * rs.parallel([ { name: 'add', params: [1,2] },\n * { name: 'subtract', params:[2,3] }]);\n * // methods \"add\" and \"subtract\" take two arguments each\n * rs.parallel({ add: [1,2], subtract: [2,4] });\n *\n * **Parameters**\n * @param {Array|Object} `operations` If none of the methods take parameters, pass an array of the method names (as strings). If any of the methods do take parameters, you have two options. You can pass an array of objects, each of which contains a method name and its own (possibly empty) array of parameters. Alternatively, you can pass a single object with the method name and a (possibly empty) array of parameters.\n * @param {*} `params` Parameters to pass to operations.\n * @param {Object} `options` (Optional) Overrides for configuration options.\n */\n parallel: function (operations, params, options) {\n var $d = $.Deferred();\n\n var opParams = rutil.normalizeOperations(operations, params);\n var ops = opParams.ops;\n var args = opParams.args;\n var postOptions = $.extend(true, {}, serviceOptions, options);\n\n var queue = [];\n for (var i = 0; i< ops.length; i++) {\n queue.push(\n this.do(ops[i], args[i])\n );\n }\n $.when.apply(this, queue)\n .done(function () {\n $d.resolve.apply(this, arguments);\n postOptions.success.apply(this.arguments);\n })\n .fail(function () {\n $d.reject.apply(this, arguments);\n postOptions.error.apply(this.arguments);\n });\n\n return $d.promise();\n }\n };\n\n var publicSyncAPI = {\n getCurrentConfig: function () {\n return serviceOptions;\n },\n /**\n * Returns a Variables Service instance. Use the variables instance to load, save, and query for specific model variables. See the [Variable API Service](../variables-api-service/) for more information.\n *\n * **Example**\n *\n * var vs = rs.variables();\n * vs.save({ sample_int: 4 });\n *\n * **Parameters**\n * @param {Object} `config` (Optional) Overrides for configuration options.\n */\n variables: function (config) {\n var vs = new VariablesService($.extend(true, {}, serviceOptions, config, {\n runService: this\n }));\n return vs;\n }\n };\n\n $.extend(this, publicAsyncAPI);\n $.extend(this, publicSyncAPI);\n};\n","/**\n * ## File API Service\n *\n * This is used to upload/download files directly onto Epicenter, analogous to using the File Manager UI in Epicenter directly or SFTPing files in. The Asset API is typically used for all project use-cases, and it's unlikely this File Service will be used directly except by Admin tools (e.g. Flow Inspector).\n *\n * Partially implemented.\n */\n\n'use strict';\n\nvar ConfigService = require('./configuration-service');\nvar TransportFactory = require('../transport/http-transport-factory');\nvar SessionManager = require('../store/session-manager');\n\nmodule.exports = function (config) {\n var defaults = {\n /**\n * For projects that require authentication, pass in the user access token (defaults to empty string). If the user is already logged in to Epicenter, the user access token is already set in a cookie and automatically loaded from there. (See [more background on access tokens](../../../project_access/)).\n * @see [Authentication API Service](../auth-api-service/) for getting tokens.\n * @type {String}\n */\n token: undefined,\n\n /**\n * The account id. In the Epicenter UI, this is the **Team ID** (for team projects) or **User ID** (for personal projects). Defaults to empty string.\n * @type {String}\n */\n account: undefined,\n\n /**\n * The project id. Defaults to empty string.\n * @type {String}\n */\n project: undefined,\n\n /**\n * The folder type. One of Model|Static|Node\n * @type {String}\n */\n folderType: 'static',\n\n\n /**\n * Options to pass on to the underlying transport layer. All jquery.ajax options at http://api.jquery.com/jQuery.ajax/ are available. Defaults to empty object.\n * @type {Object}\n */\n transport: {}\n };\n\n this.sessionManager = new SessionManager();\n var serviceOptions = this.sessionManager.getMergedOptions(defaults, config);\n var urlConfig = new ConfigService(serviceOptions).get('server');\n if (serviceOptions.account) {\n urlConfig.accountPath = serviceOptions.account;\n }\n if (serviceOptions.project) {\n urlConfig.projectPath = serviceOptions.project;\n }\n\n var httpOptions = $.extend(true, {}, serviceOptions.transport, {\n url: urlConfig.getAPIPath('file')\n });\n\n if (serviceOptions.token) {\n httpOptions.headers = {\n 'Authorization': 'Bearer ' + serviceOptions.token\n };\n }\n var http = new TransportFactory(httpOptions);\n\n var publicAsyncAPI = {\n /**\n * Get a directory listing, or contents of a file\n * @param {String} `filePath` Path to the file\n * @param {Object} `options` (Optional) Overrides for configuration options.\n */\n getContents: function (filePath, options) {\n var path = serviceOptions.folderType + '/' + filePath;\n var httpOptions = $.extend(true, {}, serviceOptions, options, {\n url: urlConfig.getAPIPath('file') + path\n });\n return http.get('', httpOptions);\n },\n\n /**\n * Writes to the given file path; replaces the existing file if it exists\n * @param {String} `filePath` Path to the file\n * @param {String} `contents` Contents to write to file\n * @param {Object} `options` (Optional) Overrides for configuration options\n */\n writeToFile: function (filePath, contents, options) {\n filePath = filePath.split('/');\n var fileName = filePath.pop();\n filePath = filePath.join('/');\n var path = serviceOptions.folderType + '/' + filePath;\n var boundary = '---------------------------7da24f2e50046';\n\n var body = '--' + boundary + '\\r\\n' +\n 'Content-Disposition: form-data; name=\"file\";' +\n 'filename=\"' + fileName + '\"\\r\\n' +\n 'Content-type: text/html\\r\\n\\r\\n' +\n contents + '\\r\\n' +\n '--' + boundary + '--';\n\n var httpOptions = $.extend(true, {}, serviceOptions, options, {\n url: urlConfig.getAPIPath('file') + path,\n data: body,\n contentType: 'multipart/form-data; boundary=' + boundary\n });\n\n return http.put(body, httpOptions);\n },\n\n /**\n * Removes the file\n * @param {String} `filePath` Path to the file\n * @param {Object} `options` (Optional) Overrides for configuration options\n */\n remove: function (filePath, options) {\n var path = serviceOptions.folderType + '/' + filePath;\n var httpOptions = $.extend(true, {}, serviceOptions, options, {\n url: urlConfig.getAPIPath('file') + path\n });\n return http.delete(null, httpOptions);\n },\n\n /**\n * Rename the file\n * @param {String} filePath Path to the file\n * @param {Stirng} newName New name of file\n * @param {Object} options (Optional) Overrides for configuration options\n */\n rename: function (filePath, newName, options) {\n var path = serviceOptions.folderType + '/' + filePath;\n var httpOptions = $.extend(true, {}, serviceOptions, options, {\n url: urlConfig.getAPIPath('file') + path\n });\n return http.patch({ 'name': newName }, httpOptions);\n }\n };\n\n $.extend(this, publicAsyncAPI);\n};\n","/**\n *\n * ## Variables API Service\n *\n * Used in conjunction with the [Run API Service](../run-api-service/) to read, write, and search for specific model variables.\n *\n * var rm = new F.manager.RunManager({\n * run: {\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * model: 'supply-chain-model.jl'\n * }\n * });\n * rm.getRun()\n * .then(function() {\n * var vs = rm.run.variables();\n * vs.save({sample_int: 4});\n * });\n *\n */\n\n\n 'use strict';\n\n var TransportFactory = require('../transport/http-transport-factory');\n var rutil = require('../util/run-util');\n\nmodule.exports = function (config) {\n var defaults = {\n /**\n * The runs object to which the variable filters apply. Defaults to null.\n * @type {runService}\n */\n runService: null\n };\n var serviceOptions = $.extend({}, defaults, config);\n\n var getURL = function () {\n return serviceOptions.runService.urlConfig.getFilterURL() + 'variables/';\n };\n\n var addAutoRestoreHeader = function (options) {\n return serviceOptions.runService.urlConfig.addAutoRestoreHeader(options);\n };\n\n var httpOptions = {\n url: getURL\n };\n if (serviceOptions.token) {\n httpOptions.headers = {\n 'Authorization': 'Bearer ' + serviceOptions.token\n };\n }\n var http = new TransportFactory(httpOptions);\n http.splitGet = rutil.splitGetFactory(httpOptions);\n\n var publicAPI = {\n\n /**\n * Get values for a variable.\n *\n * **Example**\n *\n * vs.load('sample_int')\n * .then(function(val){\n * // val contains the value of sample_int\n * });\n *\n * **Parameters**\n * @param {String} `variable` Name of variable to load.\n * @param {Object} `outputModifier` (Optional) Available fields include: `startrecord`, `endrecord`, `sort`, and `direction` (`asc` or `desc`).\n * @param {Object} `options` (Optional) Overrides for configuration options.\n */\n load: function (variable, outputModifier, options) {\n var httpOptions = $.extend(true, {}, serviceOptions, options);\n httpOptions = addAutoRestoreHeader(httpOptions);\n return http.get(outputModifier, $.extend({}, httpOptions, {\n url: getURL() + variable + '/'\n }));\n },\n\n /**\n * Returns particular variables, based on conditions specified in the `query` object.\n *\n * **Example**\n *\n * vs.query(['price', 'sales'])\n * .then(function(val) {\n * // val is an object with the values of the requested variables: val.price, val.sales\n * });\n *\n * vs.query({ include:['price', 'sales'] });\n *\n * **Parameters**\n * @param {Object|Array} `query` The names of the variables requested.\n * @param {Object} `outputModifier` (Optional) Available fields include: `startrecord`, `endrecord`, `sort`, and `direction` (`asc` or `desc`).\n * @param {Object} `options` (Optional) Overrides for configuration options.\n *\n */\n query: function (query, outputModifier, options) {\n //Query and outputModifier are both querystrings in the url; only calling them out separately here to be consistent with the other calls\n var httpOptions = $.extend(true, {}, serviceOptions, options);\n httpOptions = addAutoRestoreHeader(httpOptions);\n\n if ($.isArray(query)) {\n query = { include: query };\n }\n $.extend(query, outputModifier);\n return http.splitGet(query, httpOptions);\n },\n\n /**\n * Save values to model variables. Overwrites existing values. Note that you can only update model variables if the run is [in memory](../../../run_persistence/#runs-in-memory). (An alternate way to update model variables is to call a method from the model and make sure that the method persists the variables. See `do`, `serial`, and `parallel` in the [Run API Service](../run-api-service/) for calling methods from the model.)\n *\n * **Example**\n *\n * vs.save('price', 4);\n * vs.save({ price: 4, quantity: 5, products: [2,3,4] });\n *\n * **Parameters**\n * @param {Object|String} `variable` An object composed of the model variables and the values to save. Alternatively, a string with the name of the variable.\n * @param {Object} `val` (Optional) If passing a string for `variable`, use this argument for the value to save.\n * @param {Object} `options` (Optional) Overrides for configuration options.\n */\n save: function (variable, val, options) {\n var attrs;\n if (typeof variable === 'object') {\n attrs = variable;\n options = val;\n } else {\n (attrs = {})[variable] = val;\n }\n var httpOptions = $.extend(true, {}, serviceOptions, options);\n\n return http.patch.call(this, attrs, httpOptions);\n }\n\n // Not Available until underlying API supports PUT. Otherwise save would be PUT and merge would be PATCH\n // *\n // * Save values to the api. Merges arrays, but otherwise same as save\n // * @param {Object|String} variable Object with attributes, or string key\n // * @param {Object} val Optional if prev parameter was a string, set value here\n // * @param {Object} options Overrides for configuration options\n // *\n // * @example\n // * vs.merge({ price: 4, quantity: 5, products: [2,3,4] })\n // * vs.merge('price', 4);\n\n // merge: function (variable, val, options) {\n // var attrs;\n // if (typeof variable === 'object') {\n // attrs = variable;\n // options = val;\n // } else {\n // (attrs = {})[variable] = val;\n // }\n // var httpOptions = $.extend(true, {}, serviceOptions, options);\n\n // return http.patch.call(this, attrs, httpOptions);\n // }\n };\n $.extend(this, publicAPI);\n};\n","/**\n * ## Data API Service\n *\n * The Data API Service allows you to create, access, and manipulate data related to any of your projects. Data are organized in collections. Each collection contains a document; each element of this top-level document is a JSON object. (See additional information on the underlying [Data API](../../../rest_apis/data_api/).)\n *\n * All API calls take in an \"options\" object as the last parameter. The options can be used to extend/override the Data API Service defaults. In particular, there are three required parameters when you instantiate the Data Service:\n *\n * * `account`: Epicenter account id (**Team ID** for team projects, **User ID** for personal projects).\n * * `project`: Epicenter project id.\n * * `root`: The the name of the collection. If you have multiple collections within each of your projects, you can also pass the collection name as an option for each call.\n *\n * var ds = new F.service.Data({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * root: 'survey-responses',\n * server: { host: 'api.forio.com' }\n * });\n * ds.saveAs('user1',\n * { 'question1': 2, 'question2': 10,\n * 'question3': false, 'question4': 'sometimes' } );\n * ds.saveAs('user2',\n * { 'question1': 3, 'question2': 8,\n * 'question3': true, 'question4': 'always' } );\n * ds.query('',{ 'question2': { '$gt': 9} });\n *\n * Note that in addition to the `account`, `project`, and `root`, the Data Service parameters optionally include a `server` object, whose `host` field contains the URI of the Forio server. This is automatically set, but you can pass it explicitly if desired. It is most commonly used for clarity when you are [hosting an Epicenter project on your own server](../../../how_to/self_hosting/).\n */\n\n'use strict';\n\nvar ConfigService = require('./configuration-service');\nvar qutil = require('../util/query-util');\nvar TransportFactory = require('../transport/http-transport-factory');\nvar SessionManager = require('../store/session-manager');\n\nmodule.exports = function (config) {\n var defaults = {\n /**\n * Name of collection. Defaults to `/`, that is, the root level of your project at `forio.com/app/your-account-id/your-project-id/`. Required.\n * @type {String}\n */\n root: '/',\n\n /**\n * The account id. In the Epicenter UI, this is the **Team ID** (for team projects) or **User ID** (for personal projects). Defaults to empty string. If left undefined, taken from the URL.\n * @type {String}\n */\n account: undefined,\n\n /**\n * The project id. Defaults to empty string. If left undefined, taken from the URL.\n * @type {String}\n */\n project: undefined,\n\n /**\n * For operations that require authentication, pass in the user access token (defaults to empty string). If the user is already logged in to Epicenter, the user access token is already set in a cookie and automatically loaded from there. (See [more background on access tokens](../../../project_access/)).\n * @see [Authentication API Service](../auth-api-service/) for getting tokens.\n * @type {String}\n */\n token: undefined,\n\n //Options to pass on to the underlying transport layer\n transport: {}\n };\n this.sessionManager = new SessionManager();\n var serviceOptions = this.sessionManager.getMergedOptions(defaults, config);\n\n var urlConfig = new ConfigService(serviceOptions).get('server');\n if (serviceOptions.account) {\n urlConfig.accountPath = serviceOptions.account;\n }\n if (serviceOptions.project) {\n urlConfig.projectPath = serviceOptions.project;\n }\n\n var getURL = function (key, root) {\n if (!root) {\n root = serviceOptions.root;\n }\n var url = urlConfig.getAPIPath('data') + qutil.addTrailingSlash(root);\n if (key) {\n url+= qutil.addTrailingSlash(key);\n }\n return url;\n };\n\n var httpOptions = $.extend(true, {}, serviceOptions.transport, {\n url: getURL\n });\n if (serviceOptions.token) {\n httpOptions.headers = {\n 'Authorization': 'Bearer ' + serviceOptions.token\n };\n }\n var http = new TransportFactory(httpOptions);\n\n var publicAPI = {\n\n /**\n * Search for data within a collection.\n *\n * Searching using comparison or logical operators (as opposed to exact matches) requires MongoDB syntax. See the underlying [Data API](../../../rest_apis/data_api/#searching) for additional details.\n *\n * **Examples**\n *\n * // request all data associated with document 'user1'\n * ds.query('user1');\n *\n * // exact matching:\n * // request all documents in collection where 'question2' is 9\n * ds.query('', { 'question2': 9});\n *\n * // comparison operators:\n * // request all documents in collection\n * // where 'question2' is greater than 9\n * ds.query('', { 'question2': { '$gt': 9} });\n *\n * // logical operators:\n * // request all documents in collection\n * // where 'question2' is less than 10, and 'question3' is false\n * ds.query('', { '$and': [ { 'question2': { '$lt':10} }, { 'question3': false }] });\n *\n * // regular expresssions: use any Perl-compatible regular expressions\n * // request all documents in collection\n * // where 'question5' contains the string '.*day'\n * ds.query('', { 'question5': { '$regex': '.*day' } });\n *\n * **Parameters**\n * @param {String} `key` The name of the document to search. Pass the empty string ('') to search the entire collection.\n * @param {Object} `query` The query object. For exact matching, this object contains the field name and field value to match. For matching based on comparison, this object contains the field name and the comparison expression. For matching based on logical operators, this object contains an expression using MongoDB syntax. See the underlying [Data API](../../../rest_apis/data_api/#searching) for additional examples.\n * @param {Object} `outputModifier` (Optional) Available fields include: `startrecord`, `endrecord`, `sort`, and `direction` (`asc` or `desc`).\n * @param {Object} `options` (Optional) Overrides for configuration options.\n *\n */\n query: function (key, query, outputModifier, options) {\n var params = $.extend(true, { q: query }, outputModifier);\n var httpOptions = $.extend(true, {}, serviceOptions, options);\n httpOptions.url = getURL(key, httpOptions.root);\n return http.get(params, httpOptions);\n },\n\n /**\n * Save data to an anonymous document within the collection.\n *\n * (Documents are top-level elements within a collection. Collections must be unique within this account (team or personal account) and project and are set with the `root` field in the `option` parameter. See the underlying [Data API](../../../rest_apis/data_api/) for additional background.)\n *\n * **Example**\n *\n * ds.save('question1', 'yes');\n * ds.save({question1:'yes', question2: 32 });\n * ds.save({ name:'John', className: 'CS101' }, { root: 'students' });\n *\n * **Parameters**\n *\n * @param {String|Object} `key` If `key` is a string, it is the id of the element to save (create) in this document. If `key` is an object, the object is the data to save (create) in this document. In both cases, the id for the document is generated automatically.\n * @param {Object} `value` (Optional) The data to save. If `key` is a string, this is the value to save. If `key` is an object, the value(s) to save are already part of `key` and this argument is not required.\n * @param {Object} `options` (Optional) Overrides for configuration options.\n */\n save: function (key, value, options) {\n var attrs;\n if (typeof key === 'object') {\n attrs = key;\n options = value;\n } else {\n (attrs = {})[key] = value;\n }\n var httpOptions = $.extend(true, {}, serviceOptions, options);\n httpOptions.url = getURL('', httpOptions.root);\n\n return http.post(attrs, httpOptions);\n },\n\n /**\n * Save data to a named document or element within the collection. The `root` of the collection must be specified separately in configuration options, either as part of the call or as part of the initialization of ds.\n *\n * (Documents are top-level elements within a collection. Collections must be unique within this account (team or personal account) and project and are set with the `root` field in the `option` parameter. See the underlying [Data API](../../../rest_apis/data_api/) for additional background.)\n *\n * **Example**\n *\n * ds.saveAs('user1',\n * { 'question1': 2, 'question2': 10,\n * 'question3': false, 'question4': 'sometimes' } );\n * ds.saveAs('student1',\n * { firstName: 'john', lastName: 'smith' },\n * { root: 'students' });\n * ds.saveAs('mgmt100/groupB',\n * { scenarioYear: '2015' },\n * { root: 'myclasses' });\n *\n * **Parameters**\n *\n * @param {String} `key` Id of the document.\n * @param {Object} `value` (Optional) The data to save, in key:value pairs.\n * @param {Object} `options` (Optional) Overrides for configuration options.\n */\n saveAs: function (key, value, options) {\n var httpOptions = $.extend(true, {}, serviceOptions, options);\n httpOptions.url = getURL(key, httpOptions.root);\n\n return http.put(value, httpOptions);\n },\n\n /**\n * Get data for a specific document or field.\n *\n * **Example**\n *\n * ds.load('user1');\n * ds.load('user1/question3');\n *\n * **Parameters**\n * @param {String|Object} `key` The id of the data to return. Can be the id of a document, or a path to data within that document.\n * @param {Object} `outputModifier` (Optional) Available fields include: `startrecord`, `endrecord`, `sort`, and `direction` (`asc` or `desc`).\n * @param {Object} `options` Overrides for configuration options.\n */\n load: function (key, outputModifier, options) {\n var httpOptions = $.extend(true, {}, serviceOptions, options);\n httpOptions.url = getURL(key, httpOptions.root);\n return http.get(outputModifier, httpOptions);\n },\n\n /**\n * Removes data from collection. Only documents (top-level elements in each collection) can be deleted.\n *\n * **Example**\n *\n * ds.remove('user1');\n *\n *\n * **Parameters**\n *\n * @param {String|Array} `keys` The id of the document to remove from this collection, or an array of such ids.\n * @param {Object} `options` (Optional) Overrides for configuration options.\n */\n remove: function (keys, options) {\n var httpOptions = $.extend(true, {}, serviceOptions, options);\n var params;\n if ($.isArray(keys)) {\n params = { id: keys };\n } else {\n params = '';\n httpOptions.url = getURL(keys, httpOptions.root);\n }\n return http.delete(params, httpOptions);\n }\n\n // Epicenter doesn't allow nuking collections\n // /**\n // * Removes collection being referenced\n // * @return null\n // */\n // destroy: function (options) {\n // return this.remove('', options);\n // }\n };\n\n $.extend(this, publicAPI);\n};\n","/**\n *\n * ## Authentication API Service\n *\n * The Authentication API Service provides a method for logging in, which creates and returns a user access token.\n *\n * User access tokens are required for each call to Epicenter. (See [Project Access](../../../project_access/) for more information.)\n *\n * If you need additional functionality -- such as tracking session information, easily retrieving the user token, or getting the groups to which an end user belongs -- consider using the [Authorization Manager](../auth-manager/) instead.\n *\n * var auth = new F.service.Auth();\n * auth.login({ userName: 'jsmith@acmesimulations.com',\n * password: 'passw0rd' });\n */\n\n'use strict';\n\nvar ConfigService = require('./configuration-service');\nvar TransportFactory = require('../transport/http-transport-factory');\n\nmodule.exports = function (config) {\n var defaults = {\n /**\n * Email or username to use for logging in. Defaults to empty string.\n * @type {String}\n */\n userName: '',\n\n /**\n * Password for specified `userName`. Defaults to empty string.\n * @type {String}\n */\n password: '',\n\n /**\n * The account id for this `userName`. In the Epicenter UI, this is the **Team ID** (for team projects) or the **User ID** (for personal projects). Required if the `userName` is for an [end user](../../../glossary/#users). Defaults to empty string.\n * @type {String}\n */\n account: '',\n\n /**\n * Options to pass on to the underlying transport layer. All jquery.ajax options at http://api.jquery.com/jQuery.ajax/ are available. Defaults to empty object.\n * @type {Object}\n */\n transport: {}\n };\n var serviceOptions = $.extend({}, defaults, config);\n var urlConfig = new ConfigService(serviceOptions).get('server');\n\n var transportOptions = $.extend(true, {}, serviceOptions.transport, {\n url: urlConfig.getAPIPath('authentication')\n });\n var http = new TransportFactory(transportOptions);\n\n var publicAPI = {\n\n /**\n * Logs user in, returning the user access token.\n *\n * If no `userName` or `password` were provided in the initial configuration options, they are required in the `options` here. If no `account` was provided in the initial configuration options and the `userName` is for an [end user](../../../glossary/#users), the `account` is required as well.\n *\n * **Example**\n *\n * auth.login({\n * userName: 'jsmith',\n * password: 'passw0rd',\n * account: 'acme-simulations' })\n * .then(function (token) {\n * console.log(\"user access token is: \", token.access_token);\n * });\n *\n * **Parameters**\n * @param {Object} `options` (Optional) Overrides for configuration options.\n */\n login: function (options) {\n var httpOptions = $.extend(true, { success: $.noop }, serviceOptions, options);\n if (!httpOptions.userName || !httpOptions.password) {\n var resp = { status: 401, statusMessage: 'No username or password specified.' };\n if (options.error) {\n options.error.call(this, resp);\n }\n\n return $.Deferred().reject(resp).promise();\n }\n\n var postParams = {\n userName: httpOptions.userName,\n password: httpOptions.password,\n };\n if (httpOptions.account) {\n //pass in null for account under options if you don't want it to be sent\n postParams.account = httpOptions.account;\n }\n\n return http.post(postParams, httpOptions);\n },\n\n // (replace with /* */ comment block, to make visible in docs, once this is more than a noop)\n //\n // Logs user out from specified accounts.\n //\n // Epicenter logout is not implemented yet, so for now this is a dummy promise that gets automatically resolved.\n //\n // **Example**\n //\n // auth.logout();\n //\n // **Parameters**\n // @param {Object} `options` (Optional) Overrides for configuration options.\n //\n logout: function (options) {\n var dtd = $.Deferred();\n dtd.resolve();\n return dtd.promise();\n }\n };\n\n $.extend(this, publicAPI);\n};\n","'use strict';\n/**\n * ## State API Adapter\n *\n * The State API Adapter allows you to replay or clone runs. It brings existing, persisted run data from the database back into memory, using the same run id (`replay`) or a new run id (`clone`). Runs must be in memory in order for you to update variables or call operations on them.\n *\n * Specifically, the State API Adapter works by \"re-running\" the run (user interactions) from the creation of the run up to the time it was last persisted in the database. This process uses the current version of the run's model. Therefore, if the model has changed since the original run was created, the retrieved run will use the new model — and may end up having different values or behavior as a result. Use with care!\n *\n * To use the State API Adapter, instantiate it and then call its methods:\n *\n * var sa = new F.service.State();\n * sa.replay({runId: '1842bb5c-83ad-4ba8-a955-bd13cc2fdb4f'});\n *\n * The constructor takes an optional `options` parameter in which you can specify the `account` and `project` if they are not already available in the current context.\n *\n */\n\nvar ConfigService = require('./configuration-service');\nvar TransportFactory = require('../transport/http-transport-factory');\nvar _pick = require('../util/object-util')._pick;\nvar SessionManager = require('../store/session-manager');\nvar apiEndpoint = 'model/state';\n\nmodule.exports = function (config) {\n\n var defaults = {\n\n };\n\n this.sessionManager = new SessionManager();\n var serviceOptions = this.sessionManager.getMergedOptions(defaults, config);\n var urlConfig = new ConfigService(serviceOptions).get('server');\n\n var transportOptions = $.extend(true, {}, serviceOptions.transport, {\n url: urlConfig.getAPIPath(apiEndpoint)\n });\n\n if (serviceOptions.token) {\n transportOptions.headers = {\n 'Authorization': 'Bearer ' + serviceOptions.token\n };\n }\n\n var http = new TransportFactory(transportOptions);\n var parseRunIdOrError = function (params) {\n if ($.isPlainObject(params) && params.runId) {\n return params.runId;\n } else {\n throw new Error('Please pass in a run id');\n }\n };\n\n var publicAPI = {\n /**\n * Replay a run. After this call, the run, with its original run id, is now available [in memory](../../../run_persistence/#runs-in-memory). (It continues to be persisted into the Epicenter database at regular intervals.)\n *\n * **Example**\n *\n * var sa = new F.service.State();\n * sa.replay({runId: '1842bb5c-83ad-4ba8-a955-bd13cc2fdb4f', stopBefore: 'calculateScore'});\n *\n * **Parameters**\n * @param {object} `params` Parameters object.\n * @param {string} `params.runId` The id of the run to bring back to memory.\n * @param {string} `params.stopBefore` (Optional) The run is advanced only up to the first occurrence of this method.\n * @param {array} `params.exclude` (Optional) Array of methods to exclude when advancing the run.\n * @param {object} `options` (Optional) Overrides for configuration options.\n */\n replay: function (params, options) {\n var runId = parseRunIdOrError(params);\n\n var replayOptions = $.extend(true, {},\n serviceOptions,\n options,\n { url: urlConfig.getAPIPath(apiEndpoint) + runId }\n );\n\n params = $.extend(true, { action: 'replay' }, _pick(params, ['stopBefore', 'exclude']));\n\n return http.post(params, replayOptions);\n },\n\n /**\n * Clone a given run and return a new run in the same state as the given run.\n *\n * The new run id is now available [in memory](../../../run_persistence/#runs-in-memory). The new run includes a copy of all of the data from the original run, EXCEPT:\n *\n * * The `saved` field in the new run record is not copied from the original run record. It defaults to `false`.\n * * The `initialized` field in the new run record is not copied from the original run record. It defaults to `false` but may change to `true` as the new run is advanced. For example, if there has been a call to the `step` function (for Vensim models), the `initialized` field is set to `true`.\n * * The `created` field in the new run record is the date and time at which the clone was created (not the time that the original run was created.)\n *\n * The original run remains only [in the database](../../../run_persistence/#runs-in-db).\n *\n * **Example**\n *\n * var sa = new F.service.State();\n * sa.clone({runId: '1842bb5c-83ad-4ba8-a955-bd13cc2fdb4f', stopBefore: 'calculateScore', exclude: ['interimCalculation'] });\n *\n * **Parameters**\n * @param {object} `params` Parameters object.\n * @param {string} `params.runId` The id of the run to clone from memory.\n * @param {string} `params.stopBefore` (Optional) The newly cloned run is advanced only up to the first occurrence of this method.\n * @param {array} `params.exclude` (Optional) Array of methods to exclude when advancing the newly cloned run.\n * @param {object} `options` (Optional) Overrides for configuration options.\n */\n clone: function (params, options) {\n var runId = parseRunIdOrError(params);\n\n var replayOptions = $.extend(true, {},\n serviceOptions,\n options,\n { url: urlConfig.getAPIPath(apiEndpoint) + runId }\n );\n\n params = $.extend(true, { action: 'clone' }, _pick(params, ['stopBefore', 'exclude']));\n\n return http.post(params, replayOptions);\n }\n };\n\n $.extend(this, publicAPI);\n};\n","/**\n * ## World API Adapter\n *\n * A [run](../../../glossary/#run) is a collection of end user interactions with a project and its model -- including setting variables, making decisions, and calling operations. For building multiplayer simulations you typically want multiple end users to share the same set of interactions, and work within a common state. Epicenter allows you to create \"worlds\" to handle such cases. Only [team projects](../../../glossary/#team) can be multiplayer.\n *\n * The World API Adapter allows you to create, access, and manipulate multiplayer worlds within your Epicenter project. You can use this to add and remove end users from the world, and to create, access, and remove their runs. Because of this, typically the World Adapter is used for facilitator pages in your project. (The related [World Manager](../world-manager/) provides an easy way to access runs and worlds for particular end users, so is typically used in pages that end users will interact with.)\n *\n * As with all the other [API Adapters](../../), all methods take in an \"options\" object as the last parameter. The options can be used to extend/override the World API Service defaults.\n *\n * To use the World Adapter, instantiate it and then access the methods provided. Instantiating requires the account id (**Team ID** in the Epicenter user interface), project id (**Project ID**), and group (**Group Name**).\n *\n * var wa = new F.service.World({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * group: 'team1' });\n * wa.create()\n * .then(function(world) {\n * // call methods, e.g. wa.addUsers()\n * });\n */\n\n'use strict';\n\nvar ConfigService = require('./configuration-service');\n// var qutil = require('../util/query-util');\nvar TransportFactory = require('../transport/http-transport-factory');\nvar SessionManager = require('../store/session-manager');\nvar _pick = require('../util/object-util')._pick;\n\nvar apiBase = 'multiplayer/';\nvar assignmentEndpoint = apiBase + 'assign';\nvar apiEndpoint = apiBase + 'world';\nvar projectEndpoint = apiBase + 'project';\n\nmodule.exports = function (config) {\n var defaults = {\n /**\n * For projects that require authentication, pass in the user access token (defaults to empty string). If the user is already logged in to Epicenter, the user access token is already set in a cookie and automatically loaded from there. (See [more background on access tokens](../../../project_access/)).\n * @see [Authentication API Service](../auth-api-service/) for getting tokens.\n * @type {String}\n */\n token: undefined,\n\n /**\n * The project id. If left undefined, taken from the URL.\n * @type {String}\n */\n project: undefined,\n\n /**\n * The account id. In the Epicenter UI, this is the **Team ID** (for team projects). If left undefined, taken from the URL.\n * @type {String}\n */\n account: undefined,\n\n /**\n * The group name. Defaults to undefined.\n * @type {String}\n */\n group: undefined,\n\n /**\n * The model file to use to create runs in this world. Defaults to undefined.\n * @type {String}\n */\n model: undefined,\n\n /**\n * Criteria by which to filter world. Currently only supports world-ids as filters.\n * @type {String}\n */\n filter: '',\n\n /**\n * Convenience alias for filter\n * @type {String}\n */\n id: '',\n\n /**\n * Options to pass on to the underlying transport layer. All jquery.ajax options at http://api.jquery.com/jQuery.ajax/ are available. Defaults to empty object.\n * @type {Object}\n */\n transport: {},\n\n /**\n * Called when the call completes successfully. Defaults to `$.noop`.\n * @type {function}\n */\n success: $.noop,\n\n /**\n * Called when the call fails. Defaults to `$.noop`.\n * @type {function}\n */\n error: $.noop\n };\n\n this.sessionManager = new SessionManager();\n var serviceOptions = this.sessionManager.getMergedOptions(defaults, config);\n if (serviceOptions.id) {\n serviceOptions.filter = serviceOptions.id;\n }\n\n var urlConfig = new ConfigService(serviceOptions).get('server');\n\n if (!serviceOptions.account) {\n serviceOptions.account = urlConfig.accountPath;\n }\n\n if (!serviceOptions.project) {\n serviceOptions.project = urlConfig.projectPath;\n }\n\n var transportOptions = $.extend(true, {}, serviceOptions.transport, {\n url: urlConfig.getAPIPath(apiEndpoint)\n });\n\n if (serviceOptions.token) {\n transportOptions.headers = {\n 'Authorization': 'Bearer ' + serviceOptions.token\n };\n }\n\n var http = new TransportFactory(transportOptions);\n\n var setIdFilterOrThrowError = function (options) {\n if (options.id) {\n serviceOptions.filter = options.id;\n }\n if (options.filter) {\n serviceOptions.filter = options.filter;\n }\n if (!serviceOptions.filter) {\n throw new Error('No world id specified to apply operations against. This could happen if the user is not assigned to a world and is trying to work with runs from that world.');\n }\n };\n\n var validateModelOrThrowError = function (options) {\n if (!options.model) {\n throw new Error('No model specified to get the current run');\n }\n };\n\n var publicAPI = {\n\n /**\n * Creates a new World.\n *\n * Using this method is rare. It is more common to create worlds automatically while you `autoAssign()` end users to worlds. (In this case, configuration data for the world, such as the roles, are read from the project-level world configuration information, for example by `getProjectSettings()`.)\n *\n * **Example**\n *\n * var wa = new F.service.World({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * group: 'team1' });\n * wa.create({\n * roles: ['VP Marketing', 'VP Sales', 'VP Engineering']\n * });\n *\n * **Parameters**\n * @param {object} `params` Parameters to create the world.\n * @param {string} `params.group` (Optional) The **Group Name** to create this world under. Only end users in this group are eligible to join the world. Optional here; required when instantiating the service (`new F.service.World()`).\n * @param {object} `params.roles` (Optional) The list of roles (strings) for this world. Some worlds have specific roles that **must** be filled by end users. Listing the roles allows you to autoassign users to worlds and ensure that all roles are filled in each world.\n * @param {object} `params.optionalRoles` (Optional) The list of optional roles (strings) for this world. Some worlds have specific roles that **may** be filled by end users. Listing the optional roles as part of the world object allows you to autoassign users to worlds and ensure that all roles are filled in each world.\n * @param {integer} `params.minUsers` (Optional) The minimum number of users for the world. Including this number allows you to autoassign end users to worlds and ensure that the correct number of users are in each world.\n * @param {object} `options` (Optional) Options object to override global options.\n *\n */\n create: function (params, options) {\n var createOptions = $.extend(true, {}, serviceOptions, options, { url: urlConfig.getAPIPath(apiEndpoint) });\n var worldApiParams = ['scope', 'files', 'roles', 'optionalRoles', 'minUsers', 'group', 'name'];\n var validParams = _pick(serviceOptions, ['account', 'project', 'group']);\n // whitelist the fields that we actually can send to the api\n params = _pick(params, worldApiParams);\n\n // account and project go in the body, not in the url\n params = $.extend({}, validParams, params);\n\n var oldSuccess = createOptions.success;\n createOptions.success = function (response) {\n serviceOptions.filter = response.id; //all future chained calls to operate on this id\n return oldSuccess.apply(this, arguments);\n };\n\n return http.post(params, createOptions);\n },\n\n /**\n * Updates a World, for example to replace the roles in the world.\n *\n * Typically, you complete world configuration at the project level, rather than at the world level. For example, each world in your project probably has the same roles for end users. And your project is probably either configured so that all end users share the same world (and run), or smaller sets of end users share worlds — but not both. However, this method is available if you need to update the configuration of a particular world.\n *\n * **Example**\n *\n * var wa = new F.service.World({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * group: 'team1' });\n * wa.create()\n * .then(function(world) {\n * wa.update({ roles: ['VP Marketing', 'VP Sales', 'VP Engineering'] });\n * });\n *\n * **Parameters**\n * @param {object} `params` Parameters to update the world.\n * @param {string} `params.name` A string identifier for the linked end users, for example, \"name\": \"Our Team\".\n * @param {object} `params.roles` (Optional) The list of roles (strings) for this world. Some worlds have specific roles that **must** be filled by end users. Listing the roles allows you to autoassign users to worlds and ensure that all roles are filled in each world.\n * @param {object} `params.optionalRoles` (Optional) The list of optional roles (strings) for this world. Some worlds have specific roles that **may** be filled by end users. Listing the optional roles as part of the world object allows you to autoassign users to worlds and ensure that all roles are filled in each world.\n * @param {integer} `params.minUsers` (Optional) The minimum number of users for the world. Including this number allows you to autoassign end users to worlds and ensure that the correct number of users are in each world.\n * @param {object} `options` (Optional) Options object to override global options.\n *\n */\n update: function (params, options) {\n var whitelist = ['roles', 'optionalRoles', 'minUsers'];\n options = options || {};\n setIdFilterOrThrowError(options);\n\n var updateOptions = $.extend(true, {},\n serviceOptions,\n options,\n { url: urlConfig.getAPIPath(apiEndpoint) + serviceOptions.filter }\n );\n\n params = _pick(params || {}, whitelist);\n\n return http.patch(params, updateOptions);\n },\n\n /**\n * Deletes an existing world.\n *\n * This function optionally takes one argument. If the argument is a string, it is the id of the world to delete. If the argument is an object, it is the override for global options.\n *\n * **Example**\n *\n * var wa = new F.service.World({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * group: 'team1' });\n * wa.create()\n * .then(function(world) {\n * wa.delete();\n * });\n *\n * **Parameters**\n * @param {String|Object} `options` (Optional) The id of the world to delete, or options object to override global options.\n *\n */\n delete: function (options) {\n options = (options && (typeof options === 'string')) ? { filter: options } : {};\n setIdFilterOrThrowError(options);\n\n var deleteOptions = $.extend(true, {},\n serviceOptions,\n options,\n { url: urlConfig.getAPIPath(apiEndpoint) + serviceOptions.filter }\n );\n\n return http.delete(null, deleteOptions);\n },\n\n /**\n * Updates the configuration for the current instance of the World API Adapter (including all subsequent function calls, until the configuration is updated again).\n *\n * **Example**\n *\n * var wa = new F.service.World({...}).updateConfig({ filter: '123' }).addUser({ userId: '123' });\n *\n * **Parameters**\n * @param {object} `config` The configuration object to use in updating existing configuration.\n */\n updateConfig: function (config) {\n $.extend(serviceOptions, config);\n\n return this;\n },\n\n /**\n * Lists all worlds for a given account, project, and group. All three are required, and if not specified as parameters, are read from the service.\n *\n * **Example**\n *\n * var wa = new F.service.World({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * group: 'team1' });\n * wa.create()\n * .then(function(world) {\n * // lists all worlds in group \"team1\"\n * wa.list();\n *\n * // lists all worlds in group \"other-group-name\"\n * wa.list({ group: 'other-group-name' });\n * });\n *\n * **Parameters**\n * @param {object} `options` (Optional) Options object to override global options.\n *\n */\n list: function (options) {\n options = options || {};\n\n var getOptions = $.extend(true, {},\n serviceOptions,\n options,\n { url: urlConfig.getAPIPath(apiEndpoint) }\n );\n\n var filters = _pick(getOptions, ['account', 'project', 'group']);\n\n return http.get(filters, getOptions);\n },\n\n /**\n * Gets all worlds that an end user belongs to for a given account (team), project, and group.\n *\n * **Example**\n *\n * var wa = new F.service.World({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * group: 'team1' });\n * wa.create()\n * .then(function(world) {\n * wa.getWorldsForUser('b1c19dda-2d2e-4777-ad5d-3929f17e86d3')\n * });\n *\n * ** Parameters **\n * @param {string} `userId` The `userId` of the user whose worlds are being retrieved.\n * @param {object} `options` (Optional) Options object to override global options.\n */\n getWorldsForUser: function (userId, options) {\n options = options || {};\n\n var getOptions = $.extend(true, {},\n serviceOptions,\n options,\n { url: urlConfig.getAPIPath(apiEndpoint) }\n );\n\n var filters = $.extend(\n _pick(getOptions, ['account', 'project', 'group']),\n { userId: userId }\n );\n\n return http.get(filters, getOptions);\n },\n\n /**\n * Load information for a specific world. All further calls to the world service will use the id provided.\n *\n * **Parameters**\n * @param {String} `worldId` The id of the world to load.\n * @param {Object} `options` (Optional) Options object to override global options.\n */\n load: function (worldId, options) {\n if (worldId) {\n serviceOptions.filter = worldId;\n }\n if (!serviceOptions.filter) {\n throw new Error('Please provide a worldid to load');\n }\n var httpOptions = $.extend(true, {}, serviceOptions, options, { url: urlConfig.getAPIPath(apiEndpoint) + serviceOptions.filter + '/' });\n return http.get('', httpOptions);\n },\n\n /**\n * Adds an end user or list of end users to a given world. The end user must be a member of the `group` that is associated with this world.\n *\n * **Example**\n *\n * var wa = new F.service.World({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * group: 'team1' });\n * wa.create()\n * .then(function(world) {\n * // add one user\n * wa.addUsers('b1c19dda-2d2e-4777-ad5d-3929f17e86d3');\n * wa.addUsers(['b1c19dda-2d2e-4777-ad5d-3929f17e86d3']);\n * wa.addUsers({ userId: 'b1c19dda-2d2e-4777-ad5d-3929f17e86d3', role: 'VP Sales' });\n *\n * // add several users\n * wa.addUsers([\n * { userId: 'a6fe0c1e-f4b8-4f01-9f5f-01ccf4c2ed44',\n * role: 'VP Marketing' },\n * { userId: '8f2604cf-96cd-449f-82fa-e331530734ee',\n * role: 'VP Engineering' }\n * ]);\n *\n * // add one user to a specific world\n * wa.addUsers('b1c19dda-2d2e-4777-ad5d-3929f17e86d3', world.id);\n * wa.addUsers('b1c19dda-2d2e-4777-ad5d-3929f17e86d3', { filter: world.id });\n * });\n *\n * ** Parameters **\n * @param {string|object|array} `users` User id, array of user ids, object, or array of objects of the users to add to this world.\n * @param {string} `users.role` The `role` the user should have in the world. It is up to the caller to ensure, if needed, that the `role` passed in is one of the `roles` or `optionalRoles` of this world.\n * @param {string} `worldId` The world to which the users should be added. If not specified, the filter parameter of the `options` object is used.\n * @param {object} `options` (Optional) Options object to override global options.\n */\n addUsers: function (users, worldId, options) {\n\n if (!users) {\n throw new Error('Please provide a list of users to add to the world');\n }\n\n // normalize the list of users to an array of user objects\n users = $.map([].concat(users), function (u) {\n var isObject = $.isPlainObject(u);\n\n if (typeof u !== 'string' && !isObject) {\n throw new Error('Some of the users in the list are not in the valid format: ' + u);\n }\n\n return isObject ? u : { userId: u };\n });\n\n // check if options were passed as the second parameter\n if ($.isPlainObject(worldId) && !options) {\n options = worldId;\n worldId = null;\n }\n\n options = options || {};\n\n // we must have options by now\n if (typeof worldId === 'string') {\n options.filter = worldId;\n }\n\n setIdFilterOrThrowError(options);\n\n var updateOptions = $.extend(true, {},\n serviceOptions,\n options,\n { url: urlConfig.getAPIPath(apiEndpoint) + serviceOptions.filter + '/users' }\n );\n\n return http.post(users, updateOptions);\n },\n\n /**\n * Updates the role of an end user in a given world. (You can only update one end user at a time.)\n *\n * **Example**\n *\n * var wa = new F.service.World({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * group: 'team1' });\n *\n * wa.create().then(function(world) {\n * wa.addUsers('b1c19dda-2d2e-4777-ad5d-3929f17e86d3');\n * wa.updateUser({ userId: 'b1c19dda-2d2e-4777-ad5d-3929f17e86d3', role: 'leader' });\n * });\n *\n * **Parameters**\n * @param {object} `user` User object with `userId` and the new `role`.\n * @param {object} `options` (Optional) Options object to override global options.\n *\n */\n updateUser: function (user, options) {\n options = options || {};\n\n if (!user || !user.userId) {\n throw new Error('You need to pass a userId to update from the world');\n }\n\n setIdFilterOrThrowError(options);\n\n var patchOptions = $.extend(true, {},\n serviceOptions,\n options,\n { url: urlConfig.getAPIPath(apiEndpoint) + serviceOptions.filter + '/users/' + user.userId }\n );\n\n return http.patch(_pick(user, 'role'), patchOptions);\n },\n\n /**\n * Removes an end user from a given world.\n *\n * **Example**\n *\n * var wa = new F.service.World({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * group: 'team1' });\n * wa.create()\n * .then(function(world) {\n * wa.addUsers(['a6fe0c1e-f4b8-4f01-9f5f-01ccf4c2ed44', '8f2604cf-96cd-449f-82fa-e331530734ee']);\n * wa.removeUser('a6fe0c1e-f4b8-4f01-9f5f-01ccf4c2ed44');\n * wa.removeUser({ userId: '8f2604cf-96cd-449f-82fa-e331530734ee' });\n * });\n *\n * ** Parameters **\n * @param {object|string} `user` The `userId` of the user to remove from the world, or an object containing the `userId` field.\n * @param {object} `options` (Optional) Options object to override global options.\n */\n removeUser: function (user, options) {\n options = options || {};\n\n if (typeof user === 'string') {\n user = { userId: user };\n }\n\n if (!user.userId) {\n throw new Error('You need to pass a userId to remove from the world');\n }\n\n setIdFilterOrThrowError(options);\n\n var getOptions = $.extend(true, {},\n serviceOptions,\n options,\n { url: urlConfig.getAPIPath(apiEndpoint) + serviceOptions.filter + '/users/' + user.userId }\n );\n\n return http.delete(null, getOptions);\n },\n\n /**\n * Gets the run id of current run for the given world. If the world does not have a run, creates a new one and returns the run id.\n *\n * Remember that a [run](../../glossary/#run) is a collection of interactions with a project and its model. In the case of multiplayer projects, the run is shared by all end users in the world.\n *\n * **Example**\n *\n * var wa = new F.service.World({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * group: 'team1' });\n * wa.create()\n * .then(function(world) {\n * wa.getCurrentRunId({ model: 'model.py' });\n * });\n *\n * ** Parameters **\n * @param {object} `options` (Optional) Options object to override global options.\n * @param {object} `options.model` The model file to use to create a run if needed.\n */\n getCurrentRunId: function (options) {\n options = options || {};\n\n setIdFilterOrThrowError(options);\n\n var getOptions = $.extend(true, {},\n serviceOptions,\n options,\n { url: urlConfig.getAPIPath(apiEndpoint) + serviceOptions.filter + '/run' }\n );\n\n validateModelOrThrowError(getOptions);\n return http.post(_pick(getOptions, 'model'), getOptions);\n },\n\n /**\n * Gets the current (most recent) world for the given end user in the given group. Brings this most recent world into memory if needed.\n *\n * **Example**\n *\n * var wa = new F.service.World({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * group: 'team1' });\n * wa.getCurrentWorldForUser('8f2604cf-96cd-449f-82fa-e331530734ee')\n * .then(function(world) {\n * // use data from world\n * });\n *\n * ** Parameters **\n * @param {string} `userId` The `userId` of the user whose current (most recent) world is being retrieved.\n * @param {string} `groupName` (Optional) The name of the group. If not provided, defaults to the group used to create the service.\n */\n getCurrentWorldForUser: function (userId, groupName) {\n var dtd = $.Deferred();\n var me = this;\n this.getWorldsForUser(userId, { group: groupName })\n .then(function (worlds) {\n // assume the most recent world as the 'active' world\n worlds.sort(function (a, b) { return new Date(b.lastModified) - new Date(a.lastModified); });\n var currentWorld = worlds[0];\n\n if (currentWorld) {\n serviceOptions.filter = currentWorld.id;\n }\n\n dtd.resolve(currentWorld, me);\n })\n .fail(dtd.reject);\n\n return dtd.promise();\n },\n\n /**\n * Deletes the current run from the world.\n *\n * (Note that the world id remains part of the run record, indicating that the run was formerly an active run for the world.)\n *\n * **Example**\n *\n * var wa = new F.service.World({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * group: 'team1' });\n *\n * wa.deleteRun('sample-world-id');\n *\n * **Parameters**\n * @param {string} `worldId` The `worldId` of the world from which the current run is being deleted.\n * @param {object} `options` (Optional) Options object to override global options.\n */\n deleteRun: function (worldId, options) {\n options = options || {};\n\n if (worldId) {\n options.filter = worldId;\n }\n\n setIdFilterOrThrowError(options);\n\n var deleteOptions = $.extend(true, {},\n serviceOptions,\n options,\n { url: urlConfig.getAPIPath(apiEndpoint) + serviceOptions.filter + '/run' }\n );\n\n return http.delete(null, deleteOptions);\n },\n\n /**\n * Creates a new run for the world.\n *\n * **Example**\n *\n * var wa = new F.service.World({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * group: 'team1' });\n *\n * wa.getCurrentWorldForUser('8f2604cf-96cd-449f-82fa-e331530734ee')\n * .then(function (world) {\n * wa.newRunForWorld(world.id);\n * });\n *\n * **Parameters**\n * @param {string} `worldId` worldId in which we create the new run.\n * @param {object} `options` (Optional) Options object to override global options.\n * @param {object} `options.model` The model file to use to create a run if needed.\n */\n newRunForWorld: function (worldId, options) {\n var currentRunOptions = $.extend(true, {},\n options,\n { filter: worldId || serviceOptions.filter }\n );\n var _this = this;\n\n validateModelOrThrowError(currentRunOptions);\n\n return this.deleteRun(worldId, options)\n .then(function () {\n return _this.getCurrentRunId(currentRunOptions);\n });\n },\n\n /**\n * Assigns end users to worlds, creating new worlds as appropriate, automatically. Assigns all end users in the group, and creates new worlds as needed based on the project-level world configuration (roles, optional roles, and minimum end users per world).\n *\n * **Example**\n *\n * var wa = new F.service.World({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * group: 'team1' });\n *\n * wa.autoAssign();\n *\n * **Parameters**\n * @param {object} `options` (Optional) Options object to override global options.\n *\n */\n autoAssign: function (options) {\n options = options || {};\n\n var opt = $.extend(true, {},\n serviceOptions,\n options,\n { url: urlConfig.getAPIPath(assignmentEndpoint) }\n );\n\n var params = {\n account: opt.account,\n project: opt.project,\n group: opt.group\n };\n\n if (opt.maxUsers) {\n params.maxUsers = opt.maxUsers;\n }\n\n return http.post(params, opt);\n },\n\n /**\n * Gets the project's world configuration.\n *\n * Typically, every interaction with your project uses the same configuration of each world. For example, each world in your project probably has the same roles for end users. And your project is probably either configured so that all end users share the same world (and run), or smaller sets of end users share worlds — but not both.\n *\n * (The [Multiplayer Project REST API](../../../rest_apis/multiplayer/multiplayer_project/) allows you to set these project-level world configurations. The World Adapter simply retrieves them, for example so they can be used in auto-assignment of end users to worlds.)\n *\n * **Example**\n *\n * var wa = new F.service.World({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * group: 'team1' });\n *\n * wa.getProjectSettings()\n * .then(function(settings) {\n * console.log(settings.roles);\n * console.log(settings.optionalRoles);\n * });\n *\n * **Parameters**\n * @param {object} `options` (Optional) Options object to override global options.\n */\n getProjectSettings: function (options) {\n options = options || {};\n\n var opt = $.extend(true, {},\n serviceOptions,\n options,\n { url: urlConfig.getAPIPath(projectEndpoint) }\n );\n\n opt.url += [opt.account, opt.project].join('/');\n\n return http.get(null, opt);\n }\n\n };\n\n $.extend(this, publicAPI);\n};\n","'use strict';\n/**\n* ## User API Adapter\n*\n* The User API Adapter allows you to retrieve details about end users in your team (account). It is based on the querying capabilities of the underlying RESTful [User API](../../../rest_apis/user_management/user/).\n*\n* To use the User API Adapter, instantiate it and then call its methods.\n*\n* var ua = new F.service.User({\n* account: 'acme-simulations',\n* token: 'user-or-project-access-token'\n* });\n* ua.getById('42836d4b-5b61-4fe4-80eb-3136e956ee5c');\n* ua.get({ userName: 'jsmith' });\n* ua.get({ id: ['42836d4b-5b61-4fe4-80eb-3136e956ee5c',\n* '4ea75631-4c8d-4872-9d80-b4600146478e'] });\n*\n* The constructor takes an optional `options` parameter in which you can specify the `account` and `token` if they are not already available in the current context.\n*/\n\nvar ConfigService = require('./configuration-service');\nvar TransportFactory = require('../transport/http-transport-factory');\nvar SessionManager = require('../store/session-manager');\nvar qutil = require('../util/query-util');\n\nmodule.exports = function (config) {\n var defaults = {\n\n /**\n * The account id. In the Epicenter UI, this is the **Team ID** (for team projects) or **User ID** (for personal projects). Defaults to empty string.\n * @type {String}\n */\n account: undefined,\n\n /**\n * The access token to use when searching for end users. (See [more background on access tokens](../../../project_access/)).\n * @type {String}\n */\n token: undefined,\n\n /**\n * Options to pass on to the underlying transport layer. All jquery.ajax options at http://api.jquery.com/jQuery.ajax/ are available. Defaults to empty object.\n * @type {Object}\n */\n transport: {}\n };\n\n this.sessionManager = new SessionManager();\n var serviceOptions = this.sessionManager.getMergedOptions(defaults, config);\n var urlConfig = new ConfigService(serviceOptions).get('server');\n var transportOptions = $.extend(true, {}, serviceOptions.transport, {\n url: urlConfig.getAPIPath('user')\n });\n\n if (serviceOptions.token) {\n transportOptions.headers = {\n 'Authorization': 'Bearer ' + serviceOptions.token\n };\n }\n\n var http = new TransportFactory(transportOptions);\n\n var publicAPI = {\n\n /**\n * Retrieve details about particular end users in your team, based on user name or user id.\n *\n * **Example**\n *\n * var ua = new F.service.User({\n * account: 'acme-simulations',\n * token: 'user-or-project-access-token'\n * });\n * ua.get({ userName: 'jsmith' });\n * ua.get({ id: ['42836d4b-5b61-4fe4-80eb-3136e956ee5c',\n * '4ea75631-4c8d-4872-9d80-b4600146478e'] });\n *\n * **Parameters**\n * @param {object} `filter` Object with field `userName` and value of the username. Alternatively, object with field `id` and value of an array of user ids.\n * @param {object} `options` (Optional) Overrides for configuration options.\n */\n\n get: function (filter, options) {\n options = options || {};\n filter = filter || {};\n\n var getOptions = $.extend(true, {},\n serviceOptions,\n options\n );\n\n var toQFilter = function (filter) {\n var res = {};\n\n // API only supports filtering by username for now\n if (filter.userName) {\n res.q = filter.userName;\n }\n\n return res;\n };\n\n var toIdFilters = function (id) {\n if (!id) {\n return '';\n }\n\n id = $.isArray(id) ? id : [id];\n return 'id=' + id.join('&id=');\n };\n\n var getFilters = [\n 'account=' + getOptions.account,\n toIdFilters(filter.id),\n qutil.toQueryFormat(toQFilter(filter))\n ].join('&');\n\n // special case for queries with large number of ids\n // make it as a post with GET semantics\n var threshold = 30;\n if (filter.id && $.isArray(filter.id) && filter.id.length >= threshold) {\n getOptions.url = urlConfig.getAPIPath('user') + '?_method=GET';\n return http.post({ id: filter.id }, getOptions);\n } else {\n return http.get(getFilters, getOptions);\n }\n },\n\n /**\n * Retrieve details about a single end user in your team, based on user id.\n *\n * **Example**\n *\n * var ua = new F.service.User({\n * account: 'acme-simulations',\n * token: 'user-or-project-access-token'\n * });\n * ua.getById('42836d4b-5b61-4fe4-80eb-3136e956ee5c');\n *\n * **Parameters**\n * @param {string} `userId` The user id for the end user in your team.\n * @param {object} `options` (Optional) Overrides for configuration options.\n */\n\n getById: function (userId, options) {\n return publicAPI.get({ id: userId }, options);\n }\n };\n\n $.extend(this, publicAPI);\n};\n\n\n\n\n","/**\n *\n * ## Member API Adapter\n *\n * The Member API Adapter provides methods to look up information about end users for your project and how they are divided across groups. It is based on query capabilities of the underlying RESTful [Member API](../../../rest_apis/user_management/member/).\n *\n * This is only needed for Authenticated projects, that is, team projects with [end users and groups](../../../groups_and_end_users/). For example, if some of your end users are facilitators, or if your end users should be treated differently based on which group they are in, use the Member API to find that information.\n *\n * var ma = new F.service.Member({ token: 'user-or-project-access-token' });\n * ma.getGroupsForUser({ userId: 'b6b313a3-ab84-479c-baea-206f6bff337' });\n * ma.getGroupDetails({ groupId: '00b53308-9833-47f2-b21e-1278c07d53b8' });\n */\n\n'use strict';\n\nvar ConfigService = require('./configuration-service');\nvar TransportFactory = require('../transport/http-transport-factory');\nvar SessionManager = require('../store/session-manager');\nvar _pick = require('../util/object-util')._pick;\nvar apiEndpoint = 'member/local';\n\nmodule.exports = function (config) {\n var defaults = {\n /**\n * Epicenter user id. Defaults to a blank string.\n * @type {string}\n */\n userId: undefined,\n\n /**\n * Epicenter group id. Defaults to a blank string. Note that this is the group *id*, not the group *name*.\n * @type {string}\n */\n groupId: undefined,\n\n /**\n * Options to pass on to the underlying transport layer. All jquery.ajax options at http://api.jquery.com/jQuery.ajax/ are available. Defaults to empty object.\n * @type {object}\n */\n transport: {}\n };\n this.sessionManager = new SessionManager();\n var serviceOptions = this.sessionManager.getMergedOptions(defaults, config);\n var urlConfig = new ConfigService(serviceOptions).get('server');\n\n var transportOptions = $.extend(true, {}, serviceOptions.transport, {\n url: urlConfig.getAPIPath(apiEndpoint)\n });\n\n if (serviceOptions.token) {\n transportOptions.headers = {\n 'Authorization': 'Bearer ' + serviceOptions.token\n };\n }\n var http = new TransportFactory(transportOptions, serviceOptions);\n\n var getFinalParams = function (params) {\n if (typeof params === 'object') {\n return $.extend(true, serviceOptions, params);\n }\n return serviceOptions;\n };\n\n var patchUserActiveField = function (params, active, options) {\n var httpOptions = $.extend(true, serviceOptions, options, {\n url: urlConfig.getAPIPath(apiEndpoint) + params.groupId + '/' + params.userId\n });\n\n return http.patch({ active: active }, httpOptions);\n };\n\n var publicAPI = {\n\n /**\n * Retrieve details about all of the group memberships for one end user. The membership details are returned in an array, with one element (group record) for each group to which the end user belongs.\n *\n * In the membership array, each group record includes the group id, project id, account (team) id, and an array of members. However, only the user whose userId is included in the call is listed in the members array (regardless of whether there are other members in this group).\n *\n * **Example**\n *\n * var ma = new F.service.Member({ token: 'user-or-project-access-token' });\n * ma.getGroupsForUser('42836d4b-5b61-4fe4-80eb-3136e956ee5c')\n * .then(function(memberships){\n * for (var i=0; i\n * // \n * // \n * // \n * // \n * //\n * $('#upload-file').on('submit', function (e) {\n * e.preventDefault();\n * var filename = $('#filename').val();\n * var data = new FormData();\n * var inputControl = $('#file')[0];\n * data.append('file', inputControl.files[0], filename);\n *\n * aa.create(filename, data, { scope: 'user' });\n * });\n *\n */\n\n'use strict';\n\nvar ConfigService = require('./configuration-service');\nvar TransportFactory = require('../transport/http-transport-factory');\nvar _pick = require('../util/object-util')._pick;\nvar SessionManager = require('../store/session-manager');\n\nvar apiEndpoint = 'asset';\n\nmodule.exports = function (config) {\n var defaults = {\n /**\n * For projects that require authentication, pass in the user access token (defaults to empty string). If the user is already logged in to Epicenter, the user access token is already set in a cookie and automatically loaded from there. (See [more background on access tokens](../../../project_access/)).\n * @see [Authentication API Service](../auth-api-service/) for getting tokens.\n * @type {String}\n */\n token: undefined,\n /**\n * The account id. In the Epicenter UI, this is the **Team ID** (for team projects). If left undefined, taken from the URL.\n * @type {String}\n */\n account: undefined,\n /**\n * The project id. If left undefined, taken from the URL.\n * @type {String}\n */\n project: undefined,\n /**\n * The group name. Defaults to session's `groupName`.\n * @type {String}\n */\n group: undefined,\n /**\n * The user id. Defaults to session's `userId`.\n * @type {String}\n */\n userId: undefined,\n /**\n * The scope for the asset. Valid values are: `user`, `group`, and `project`. See above for the required permissions to write to each scope. Defaults to `user`, meaning the current end user or a facilitator in the end user's group can edit the asset.\n * @type {String}\n */\n scope: 'user',\n /**\n * Determines if a request to list the assets in a scope includes the complete URL for each asset (`true`), or only the file names of the assets (`false`). Defaults to `true`.\n * @type {boolean}\n */\n fullUrl: true,\n /**\n * The transport object contains the options passed to the XHR request.\n * @type {object}\n */\n transport: {\n processData: false\n }\n };\n this.sessionManager = new SessionManager();\n var serviceOptions = this.sessionManager.getMergedOptions(defaults, config);\n var urlConfig = new ConfigService(serviceOptions).get('server');\n\n if (!serviceOptions.account) {\n serviceOptions.account = urlConfig.accountPath;\n }\n\n if (!serviceOptions.project) {\n serviceOptions.project = urlConfig.projectPath;\n }\n\n var transportOptions = $.extend(true, {}, serviceOptions.transport, {\n url: urlConfig.getAPIPath(apiEndpoint)\n });\n\n if (serviceOptions.token) {\n transportOptions.headers = {\n 'Authorization': 'Bearer ' + serviceOptions.token\n };\n }\n\n var http = new TransportFactory(transportOptions);\n\n var assetApiParams = ['encoding', 'data', 'contentType'];\n var scopeConfig = {\n user: ['scope', 'account', 'project', 'group', 'userId'],\n group: ['scope', 'account', 'project', 'group'],\n project: ['scope', 'account', 'project'],\n };\n\n var validateFilename = function (filename) {\n if (!filename) {\n throw new Error('filename is needed.');\n }\n };\n\n var validateUrlParams = function (options) {\n var partKeys = scopeConfig[options.scope];\n if (!partKeys) {\n throw new Error('scope parameter is needed.');\n }\n\n $.each(partKeys, function () {\n if (!options[this]) {\n throw new Error(this + ' parameter is needed.');\n }\n });\n };\n\n var buildUrl = function (filename, options) {\n validateUrlParams(options);\n var partKeys = scopeConfig[options.scope];\n var parts = $.map(partKeys, function (key) {\n return options[key];\n });\n if (filename) {\n // This prevents adding a trailing / in the URL as the Asset API\n // does not work correctly with it\n filename = '/' + filename;\n }\n return urlConfig.getAPIPath(apiEndpoint) + parts.join('/') + filename;\n };\n\n // Private function, all requests follow a more or less same approach to\n // use the Asset API and the difference is the HTTP verb\n //\n // @param {string} `method` (Required) HTTP verb\n // @param {string} `filename` (Required) Name of the file to delete/replace/create\n // @param {object} `params` (Optional) Body parameters to send to the Asset API\n // @param {object} `options` (Optional) Options object to override global options.\n var upload = function (method, filename, params, options) {\n validateFilename(filename);\n // make sure the parameter is clean\n method = method.toLowerCase();\n var contentType = params instanceof FormData === true ? false : 'application/json';\n if (contentType === 'application/json') {\n // whitelist the fields that we actually can send to the api\n params = _pick(params, assetApiParams);\n } else { // else we're sending form data which goes directly in request body\n // For multipart/form-data uploads the filename is not set in the URL,\n // it's getting picked by the FormData field filename.\n filename = method === 'post' || method === 'put' ? '' : filename;\n }\n var urlOptions = $.extend({}, serviceOptions, options);\n var url = buildUrl(filename, urlOptions);\n var createOptions = $.extend(true, {}, urlOptions, { url: url, contentType: contentType });\n\n return http[method](params, createOptions);\n };\n\n var publicAPI = {\n /**\n * Creates a file in the Asset API. The server returns an error (status code `409`, conflict) if the file already exists, so\n * check first with a `list()` or a `get()`.\n *\n * **Example**\n *\n * var aa = new F.service.Asset({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * group: 'team1',\n * userId: ''\n * });\n *\n * // create a new asset using encoded text\n * aa.create('test.txt', {\n * encoding: 'BASE_64',\n * data: 'VGhpcyBpcyBhIHRlc3QgZmlsZS4=',\n * contentType: 'text/plain'\n * }, { scope: 'user' });\n *\n * // alternatively, create a new asset using a file uploaded through a form\n * // this sample code goes with an html form that looks like this:\n * //\n * //
\n * // \n * // \n * // \n * //
\n * //\n * $('#upload-file').on('submit', function (e) {\n * e.preventDefault();\n * var filename = $('#filename').val();\n * var data = new FormData();\n * var inputControl = $('#file')[0];\n * data.append('file', inputControl.files[0], filename);\n *\n * aa.create(filename, data, { scope: 'user' });\n * });\n *\n *\n * **Parameters**\n * @param {string} `filename` (Required) Name of the file to create.\n * @param {object} `params` (Optional) Body parameters to send to the Asset API. Required if the `options.transport.contentType` is `application/json`, otherwise ignored.\n * @param {string} `params.encoding` Either `HEX` or `BASE_64`. Required if `options.transport.contentType` is `application/json`.\n * @param {string} `params.data` The encoded data for the file. Required if `options.transport.contentType` is `application/json`.\n * @param {string} `params.contentType` The mime type of the file. Optional.\n * @param {object} `options` (Optional) Options object to override global options.\n *\n */\n create: function (filename, params, options) {\n return upload('post', filename, params, options);\n },\n\n /**\n * Gets a file from the Asset API, fetching the asset content. (To get a list\n * of the assets in a scope, use `list()`.)\n *\n * **Parameters**\n * @param {string} `filename` (Required) Name of the file to retrieve.\n * @param {object} `options` (Optional) Options object to override global options.\n *\n */\n get: function (filename, options) {\n var getServiceOptions = _pick(serviceOptions, ['scope', 'account', 'project', 'group', 'userId']);\n var urlOptions = $.extend({}, getServiceOptions, options);\n var url = buildUrl(filename, urlOptions);\n var getOptions = $.extend(true, {}, urlOptions, { url: url });\n\n return http.get({}, getOptions);\n },\n\n /**\n * Gets the list of the assets in a scope.\n *\n * **Example**\n *\n * aa.list({ fullUrl: true }).then(function(fileList){\n * console.log('array of files = ', fileList);\n * });\n *\n * **Parameters**\n * @param {object} `options` (Optional) Options object to override global options.\n * @param {string} `options.scope` (Optional) The scope (`user`, `group`, `project`).\n * @param {boolean} `options.fullUrl` (Optional) Determines if the list of assets in a scope includes the complete URL for each asset (`true`), or only the file names of the assets (`false`).\n *\n */\n list: function (options) {\n var dtd = $.Deferred();\n var me = this;\n var urlOptions = $.extend({}, serviceOptions, options);\n var url = buildUrl('', urlOptions);\n var getOptions = $.extend(true, {}, urlOptions, { url: url });\n var fullUrl = getOptions.fullUrl;\n\n if (!fullUrl) {\n return http.get({}, getOptions);\n }\n\n http.get({}, getOptions)\n .then(function (files) {\n var fullPathFiles = $.map(files, function (file) {\n return buildUrl(file, urlOptions);\n });\n dtd.resolve(fullPathFiles, me);\n })\n .fail(dtd.reject);\n\n return dtd.promise();\n },\n\n /**\n * Replaces an existing file in the Asset API.\n *\n * **Example**\n *\n * // replace an asset using encoded text\n * aa.replace('test.txt', {\n * encoding: 'BASE_64',\n * data: 'VGhpcyBpcyBhIHNlY29uZCB0ZXN0IGZpbGUu',\n * contentType: 'text/plain'\n * }, { scope: 'user' });\n *\n * // alternatively, replace an asset using a file uploaded through a form\n * // this sample code goes with an html form that looks like this:\n * //\n * //
\n * // \n * // \n * // \n * //
\n * //\n * $('#replace-file').on('submit', function (e) {\n * e.preventDefault();\n * var filename = $('#replace-filename').val();\n * var data = new FormData();\n * var inputControl = $('#file')[0];\n * data.append('file', inputControl.files[0], filename);\n *\n * aa.replace(filename, data, { scope: 'user' });\n * });\n *\n * **Parameters**\n * @param {string} `filename` (Required) Name of the file being replaced.\n * @param {object} `params` (Optional) Body parameters to send to the Asset API. Required if the `options.transport.contentType` is `application/json`, otherwise ignored.\n * @param {string} `params.encoding` Either `HEX` or `BASE_64`. Required if `options.transport.contentType` is `application/json`.\n * @param {string} `params.data` The encoded data for the file. Required if `options.transport.contentType` is `application/json`.\n * @param {string} `params.contentType` The mime type of the file. Optional.\n * @param {object} `options` (Optional) Options object to override global options.\n *\n */\n replace: function (filename, params, options) {\n return upload('put', filename, params, options);\n },\n\n /**\n * Deletes a file from the Asset API.\n *\n * **Example**\n *\n * aa.delete(sampleFileName);\n *\n * **Parameters**\n * @param {string} `filename` (Required) Name of the file to delete.\n * @param {object} `options` (Optional) Options object to override global options.\n *\n */\n delete: function (filename, options) {\n return upload('delete', filename, {}, options);\n },\n\n assetUrl: function (filename, options) {\n var urlOptions = $.extend({}, serviceOptions, options);\n return buildUrl(filename, urlOptions);\n }\n };\n $.extend(this, publicAPI);\n};\n","/**\n *\n * ## Group API Adapter\n *\n * The Group API Adapter provides methods to look up, create, change or remove information about groups in a project. It is based on query capabilities of the underlying RESTful [Group API](../../../rest_apis/user_management/group/).\n *\n * This is only needed for Authenticated projects, that is, team projects with [end users and groups](../../../groups_and_end_users/).\n *\n * var ma = new F.service.Group({ token: 'user-or-project-access-token' });\n * ma.getGroupsForProject({ account: 'acme', project: 'sample' });\n */\n\n'use strict';\n\nvar serviceUtils = require('./service-utils');\nvar TransportFactory = require('../transport/http-transport-factory');\nvar objectAssign = require('object-assign');\n\nvar apiEndpoint = 'group/local';\n\nvar GroupService = function (config) {\n var defaults = {\n /**\n * Epicenter account name. Defaults to undefined.\n * @type {string}\n */\n account: undefined,\n\n /**\n * Epicenter project name. Defaults to undefined.\n * @type {string}\n */\n project: undefined,\n\n /**\n * Options to pass on to the underlying transport layer. All jquery.ajax options at http://api.jquery.com/jQuery.ajax/ are available. Defaults to empty object.\n * @type {object}\n */\n transport: {}\n };\n var serviceOptions = serviceUtils.getDefaultOptions(defaults, config, { apiEndpoint: apiEndpoint });\n var transportOptions = serviceOptions.transport;\n delete serviceOptions.transport;\n var http = new TransportFactory(transportOptions, serviceOptions);\n var publicAPI = {\n /*\n * Gets information for a group or multiple groups.\n * @param {string} `params` the groupId of the target group\n * @param {Object} `params` object with query parameters\n * @patam {string} `params.q` partial match for name, organization or event.\n * @patam {string} `params.account` Epicenter's Team ID\n * @patam {string} `params.project` Epicenter's Project ID\n * @patam {string} `params.name` Epicenter's Group Name\n * @param {Object} `options` (Optional) Overrides for configuration options.\n */\n getGroups: function (params, options) {\n //groupID is part of the URL\n //q, account and project are part of the query string\n var finalOpts = objectAssign({}, serviceOptions, options);\n var finalParams;\n if (typeof params === 'string') {\n finalOpts.url = serviceUtils.getApiUrl(apiEndpoint + '/' + params, finalOpts);\n } else {\n finalParams = params;\n }\n return http.get(finalParams, finalOpts);\n }\n };\n objectAssign(this, publicAPI);\n};\n\nmodule.exports = GroupService;\n","/**\n * @class Cookie Storage Service\n *\n * @example\n * var people = require('cookie-store')({ root: 'people' });\n people\n .save({lastName: 'smith' })\n\n */\n\n\n'use strict';\n\n// Thin document.cookie wrapper to allow unit testing\nvar Cookie = function () {\n this.get = function () {\n return document.cookie;\n };\n\n this.set = function (newCookie) {\n document.cookie = newCookie;\n };\n};\n\nmodule.exports = function (config) {\n var host = window.location.hostname;\n var validHost = host.split('.').length > 1;\n var domain = validHost ? '.' + host : null;\n\n var defaults = {\n /**\n * Name of collection\n * @type { string}\n */\n root: '/',\n\n domain: domain,\n cookie: new Cookie()\n };\n this.serviceOptions = $.extend({}, defaults, config);\n\n var publicAPI = {\n // * TBD\n // * Query collection; uses MongoDB syntax\n // * @see \n // *\n // * @param { string} qs Query Filter\n // * @param { string} limiters @see \n // *\n // * @example\n // * cs.query(\n // * { name: 'John', className: 'CSC101' },\n // * {limit: 10}\n // * )\n\n // query: function (qs, limiters) {\n\n // },\n\n /**\n * Save cookie value\n * @param { string|Object} key If given a key save values under it, if given an object directly, save to top-level api\n * @param {Object} value (Optional)\n * @param {Object} options Overrides for service options\n *\n * @return {*} The saved value\n *\n * @example\n * cs.set('person', { firstName: 'john', lastName: 'smith' });\n * cs.set({ name:'smith', age:'32' });\n */\n set: function (key, value, options) {\n var setOptions = $.extend(true, {}, this.serviceOptions, options);\n\n var domain = setOptions.domain;\n var path = setOptions.root;\n var cookie = setOptions.cookie;\n\n cookie.set(encodeURIComponent(key) + '=' +\n encodeURIComponent(value) +\n (domain ? '; domain=' + domain : '') +\n (path ? '; path=' + path : '')\n );\n\n return value;\n },\n\n /**\n * Load cookie value\n * @param { string|Object} key If given a key save values under it, if given an object directly, save to top-level api\n * @return {*} The value stored\n *\n * @example\n * cs.get('person');\n */\n get: function (key) {\n var cookie = this.serviceOptions.cookie;\n var cookieReg = new RegExp('(?:^|;)\\\\s*' + encodeURIComponent(key).replace(/[\\-\\.\\+\\*]/g, '\\\\$&') + '\\\\s*\\\\=\\\\s*([^;]*).*$');\n var res = cookieReg.exec(cookie.get());\n var val = res ? decodeURIComponent(res[1]) : null;\n return val;\n },\n\n /**\n * Removes key from collection\n * @param { string} key key to remove\n * @return { string} key The key removed\n *\n * @example\n * cs.remove('person');\n */\n remove: function (key, options) {\n var remOptions = $.extend(true, {}, this.serviceOptions, options);\n\n var domain = remOptions.domain;\n var path = remOptions.root;\n var cookie = remOptions.cookie;\n\n cookie.set(encodeURIComponent(key) +\n '=; expires=Thu, 01 Jan 1970 00:00:00 GMT' +\n (domain ? '; domain=' + domain : '') +\n (path ? '; path=' + path : '')\n );\n return key;\n },\n\n /**\n * Removes collection being referenced\n * @return { array} keys All the keys removed\n */\n destroy: function () {\n var cookie = this.serviceOptions.cookie;\n var aKeys = cookie.get().replace(/((?:^|\\s*;)[^\\=]+)(?=;|$)|^\\s*|\\s*(?:\\=[^;]*)?(?:\\1|$)/g, '').split(/\\s*(?:\\=[^;]*)?;\\s*/);\n for (var nIdx = 0; nIdx < aKeys.length; nIdx++) {\n var cookieKey = decodeURIComponent(aKeys[nIdx]);\n this.remove(cookieKey);\n }\n return aKeys;\n }\n };\n\n $.extend(this, publicAPI);\n};\n","/**\n Decides type of store to provide\n*/\n\n'use strict';\n// var isNode = false; FIXME: Browserify/minifyify has issues with the next link\n// var store = (isNode) ? require('./session-store') : require('./cookie-store');\nvar store = require('./cookie-store');\n\nmodule.exports = store;\n","'use strict';\nvar RunService = require('../service/run-api-service');\n\nvar defaults = {\n validFilter: { saved: true }\n};\n\nfunction ScenarioManager(options) {\n this.options = $.extend(true, {}, defaults, options);\n this.runService = this.options.run || new RunService(this.options);\n}\n\nScenarioManager.prototype = {\n getRuns: function (filter) {\n this.filter = $.extend(true, {}, this.options.validFilter, filter);\n return this.runService.query(this.filter);\n },\n\n loadVariables: function (vars) {\n return this.runService.query(this.filter, { include: vars });\n },\n\n save: function (run, meta) {\n return this._getService(run).save($.extend(true, {}, { saved: true }, meta));\n },\n\n archive: function (run) {\n return this._getService(run).save({ saved: false });\n },\n\n _getService: function (run) {\n if (typeof run === 'string') {\n return new RunService($.extend(true, {}, this.options, { filter: run }));\n }\n\n if (typeof run === 'object' && run instanceof RunService) {\n return run;\n }\n\n throw new Error('Save method requires a run service or a runId');\n },\n\n getRun: function (runId) {\n return new RunService($.extend(true, {}, this.options, { filter: runId }));\n }\n};\n\nmodule.exports = ScenarioManager;\n\n","/**\n* ## Run Manager\n*\n* The Run Manager gives you access to runs for your project. This allows you to read and update variables, call operations, etc. Additionally, the Run Manager gives you control over run creation depending on run states. Specifically, you can select [run creation strategies (rules)](../../strategy/) for which runs end users of your project work with when they log in to your project.\n*\n* There are many ways to create new runs, including the Epicenter.js [Run Service](../run-api-service/), the RESFTful [Run API](../../../rest_apis/aggregate_run_api) and the [Model Run API](../../../rest_apis/other_apis/model_apis/run/). However, for some projects it makes more sense to pick up where the user left off, using an existing run. And in some projects, whether to create a new run or use an existing one is conditional, for example based on characteristics of the existing run or your own knowledge about the model. The Run Manager provides this level of control: your call to `getRun()`, rather than always returning a new run, returns a run based on the strategy you've specified. (Note that many of the Epicenter sample projects use a Run Service directly, because generally the sample projects are played in one end user session and don't care about run states or run strategies.)\n*\n*\n* ### Using the Run Manager to create and access runs\n*\n* To use the Run Manager, instantiate it by passing in:\n*\n* * `run`: (required) Run object. Must contain:\n* * `account`: Epicenter account id (**Team ID** for team projects, **User ID** for personal projects).\n* * `project`: Epicenter project id.\n* * `model`: The name of your primary model file. (See more on [Writing your Model](../../../writing_your_model/).)\n* * `scope`: (optional) Scope object for the run, for example `scope.group` with value of the name of the group.\n* * `server`: (optional) An object with one field, `host`. The value of `host` is the string `api.forio.com`, the URI of the Forio server. This is automatically set, but you can pass it explicitly if desired. It is most commonly used for clarity when you are [hosting an Epicenter project on your own server](../../../how_to/self_hosting/).\n* * `files`: (optional) If and only if you are using a Vensim model and you have additional data to pass in to your model, you can pass a `files` object with the names of the files, for example: `\"files\": {\"data\": \"myExtraData.xls\"}`. (Note that you'll also need to add this same files object to your Vensim [configuration file](../../../model_code/vensim/).) See the [underlying Model Run API](../../../rest_apis/other_apis/model_apis/run/#post-creating-a-new-run-for-this-project) for additional information.\n*\n* * `strategy`: (optional) Run creation strategy for when to create a new run and when to reuse an end user's existing run. See [Run Manager Strategies](../../strategy/) for details. Defaults to `new-if-initialized`.\n*\n* * `sessionKey`: (optional) Name of browser cookie in which to store run information, including run id. Many conditional strategies, including the provided strategies, rely on this browser cookie to store the run id and help make the decision of whether to create a new run or use an existing one. The name of this cookie defaults to `epicenter-scenario` and can be set with the `sessionKey` parameter.\n*\n*\n* After instantiating a Run Manager, make a call to `getRun()` whenever you need to access a run for this end user. The `RunManager.run` contains the instantiated [Run Service](../run-api-service/). The Run Service allows you to access variables, call operations, etc.\n*\n* **Example**\n*\n* var rm = new F.manager.RunManager({\n* run: {\n* account: 'acme-simulations',\n* project: 'supply-chain-game',\n* model: 'supply-chain-model.jl',\n* server: { host: 'api.forio.com' }\n* },\n* strategy: 'always-new',\n* sessionKey: 'epicenter-session'\n* });\n* rm.getRun()\n* .then(function(run) {\n* // the return value of getRun() is a run object\n* var thisRunId = run.id;\n* // the RunManager.run also contains the instantiated Run Service,\n* // so any Run Service method is valid here\n* rm.run.do('runModel');\n* })\n*\n*/\n\n'use strict';\nvar strategiesMap = require('./run-strategies/strategies-map');\nvar specialOperations = require('./special-operations');\nvar RunService = require('../service/run-api-service');\n\n\nfunction patchRunService(service, manager) {\n if (service.patched) {\n return service;\n }\n\n var orig = service.do;\n service.do = function (operation, params, options) {\n var reservedOps = Object.keys(specialOperations);\n if (reservedOps.indexOf(operation) === -1) {\n return orig.apply(service, arguments);\n } else {\n return specialOperations[operation].call(service, params, options, manager);\n }\n };\n\n service.patched = true;\n\n return service;\n}\n\n\n\nvar defaults = {\n /**\n * Run creation strategy for when to create a new run and when to reuse an end user's existing run. See [Run Manager Strategies](../../strategy/) for details. Defaults to `new-if-initialized`.\n * @type {String}\n */\n\n strategy: 'new-if-initialized'\n};\n\nfunction RunManager(options) {\n this.options = $.extend(true, {}, defaults, options);\n\n if (this.options.run instanceof RunService) {\n this.run = this.options.run;\n } else {\n this.run = new RunService(this.options.run);\n }\n\n patchRunService(this.run, this);\n\n var StrategyCtor = typeof this.options.strategy === 'function' ? this.options.strategy : strategiesMap[this.options.strategy];\n\n if (!StrategyCtor) {\n throw new Error('Specified run creation strategy was invalid:', this.options.strategy);\n }\n\n this.strategy = new StrategyCtor(this.run, this.options);\n}\n\nRunManager.prototype = {\n /**\n * Returns the run object for a 'good' run.\n *\n * A good run is defined by the strategy. For example, if the strategy is `always-new`, the call\n * to `getRun()` always returns a newly created run; if the strategy is `new-if-persisted`,\n * `getRun()` creates a new run if the previous run is in a persisted state, otherwise\n * it returns the previous run. See [Run Manager Strategies](../../strategy/) for more on strategies.\n *\n * **Example**\n *\n * rm.getRun().then(function (run) {\n * // use the run object\n * var thisRunId = run.id;\n *\n * // use the Run Service object\n * rm.run.do('runModel');\n * });\n *\n * @return {$promise} Promise to complete the call.\n */\n getRun: function () {\n return this.strategy\n .getRun();\n },\n\n /**\n * Returns the run object for a new run, regardless of strategy: force creation of a new run.\n *\n * **Example**\n *\n * rm.reset().then(function (run) {\n * // use the (new) run object\n * var thisRunId = run.id;\n *\n * // use the Run Service object\n * rm.run.do('runModel');\n * });\n *\n * **Parameters**\n * @param {Object} `runServiceOptions` The options object to configure the Run Service. See [Run API Service](../run-api-service/) for more.\n */\n reset: function (runServiceOptions) {\n return this.strategy.reset(runServiceOptions);\n }\n};\n\nmodule.exports = RunManager;\n","/**\n* ## Authorization Manager\n*\n* The Authorization Manager provides an easy way to manage user authentication (logging in and out) and authorization (keeping track of tokens, sessions, and groups) for projects.\n*\n* The Authorization Manager is most useful for [team projects](../../../glossary/#team) with an access level of [Authenticated](../../../glossary/#access). These projects are accessed by [end users](../../../glossary/#users) who are members of one or more [groups](../../../glossary/#groups).\n*\n* #### Using the Authorization Manager\n*\n* To use the Authorization Manager, instantiate it. Then, make calls to any of the methods you need:\n*\n* var authMgr = new F.manager.AuthManager({\n* account: 'acme-simulations',\n* userName: 'enduser1',\n* password: 'passw0rd'\n* });\n* authMgr.login().then(function () {\n* authMgr.getCurrentUserSessionInfo();\n* });\n*\n*\n* The `options` object passed to the `F.manager.AuthManager()` call can include:\n*\n* * `account`: The account id for this `userName`. In the Epicenter UI, this is the **Team ID** (for team projects) or the **User ID** (for personal projects).\n* * `userName`: Email or username to use for logging in.\n* * `password`: Password for specified `userName`.\n* * `project`: The **Project ID** for the project to log this user into. Optional.\n* * `groupId`: Id of the group to which `userName` belongs. Required for end users if the `project` is specified.\n*\n* If you prefer starting from a template, the Epicenter JS Libs [Login Component](../../#components) uses the Authorization Manager as well. This sample HTML page (and associated CSS and JS files) provides a login form for team members and end users of your project. It also includes a group selector for end users that are members of multiple groups.\n*/\n\n'use strict';\nvar AuthAdapter = require('../service/auth-api-service');\nvar MemberAdapter = require('../service/member-api-adapter');\nvar GroupService = require('../service/group-api-service');\nvar SessionManager = require('../store/session-manager');\nvar Buffer = require('buffer').Buffer;\nvar _pick = require('../util/object-util')._pick;\nvar objectAssign = require('object-assign');\n\nvar defaults = {\n requiresGroup: true\n};\n\nfunction AuthManager(options) {\n options = $.extend(true, {}, defaults, options);\n this.sessionManager = new SessionManager(options);\n this.options = this.sessionManager.getMergedOptions();\n\n this.isLocal = this.options.isLocal;\n this.authAdapter = new AuthAdapter(this.options);\n}\n\nvar _findUserInGroup = function (members, id) {\n for (var j = 0; j 1) {\n if (groupId) {\n var filteredGroups = $.grep(groupList, function (resGroup) {\n return resGroup.groupId === groupId;\n });\n group = filteredGroups.length === 1 ? filteredGroups[0] : null;\n }\n }\n\n if (group) {\n // A team member does not get the group members because is calling the Group API\n // but it's automatically a fac user\n var isFac = isTeamMember ? true : _findUserInGroup(group.members, userInfo.user_id).role === 'facilitator';\n var groupData = {\n groupId: group.groupId,\n groupName: group.name,\n isFac: isFac\n };\n var sessionInfoWithGroup = objectAssign({}, sessionInfo, groupData);\n sessionInfo.groups[project] = groupData;\n _this.sessionManager.saveSession(sessionInfoWithGroup, adapterOptions);\n outSuccess.apply(this, [data]);\n $d.resolve(data);\n } else {\n handleGroupError('This user is associated with more than one group. Please specify a group id to log into and try again', 403, data);\n }\n };\n\n if (!isTeamMember) {\n _this.getUserGroups({ userId: userInfo.user_id, token: token }, userGroupOpts)\n .then(handleGroupList, $d.reject);\n } else {\n var opts = objectAssign({}, userGroupOpts, { token: token });\n var groupService = new GroupService(opts);\n groupService.getGroups({ account: adapterOptions.account, project: project })\n .then(function (groups) {\n // Group API returns id instead of groupId\n groups.forEach(function (group) {\n group.groupId = group.id;\n });\n handleGroupList(groups);\n }, $d.reject);\n }\n };\n\n adapterOptions.success = handleSuccess;\n adapterOptions.error = function (response) {\n if (adapterOptions.account) {\n // Try to login as a system user\n adapterOptions.account = null;\n adapterOptions.error = function () {\n outError.apply(this, arguments);\n $d.reject(response);\n };\n\n _this.authAdapter.login(adapterOptions);\n return;\n }\n\n outError.apply(this, arguments);\n $d.reject(response);\n };\n\n this.authAdapter.login(adapterOptions);\n return $d.promise();\n },\n\n /**\n * Logs user out by clearing all session information.\n *\n * **Example**\n *\n * authMgr.logout();\n *\n * **Parameters**\n *\n * @param {Object} `options` (Optional) Overrides for configuration options.\n */\n logout: function (options) {\n var _this = this;\n var adapterOptions = this.sessionManager.getMergedOptions(options);\n\n var removeCookieFn = function (response) {\n _this.sessionManager.removeSession();\n };\n\n return this.authAdapter.logout(adapterOptions).done(removeCookieFn);\n },\n\n /**\n * Returns the existing user access token if the user is already logged in. Otherwise, logs the user in, creating a new user access token, and returns the new token. (See [more background on access tokens](../../../project_access/)).\n *\n * **Example**\n *\n * authMgr.getToken()\n * .then(function (token) {\n * console.log('My token is ', token);\n * });\n *\n * **Parameters**\n * @param {Object} `options` (Optional) Overrides for configuration options.\n */\n getToken: function (options) {\n var httpOptions = this.sessionManager.getMergedOptions(options);\n\n var session = this.sessionManager.getSession();\n var $d = $.Deferred();\n //jshint camelcase: false\n //jscs:disable\n if (session.auth_token) {\n $d.resolve(session.auth_token);\n } else {\n this.login(httpOptions).then($d.resolve);\n }\n return $d.promise();\n },\n\n /**\n * Returns an array of group records, one for each group of which the current user is a member. Each group record includes the group `name`, `account`, `project`, and `groupId`.\n *\n * If some end users in your project are members of multiple groups, this is a useful method to call on your project's login page. When the user attempts to log in, you can use this to display the groups of which the user is member, and have the user select the correct group to log in to for this session.\n *\n * **Example**\n *\n * // get groups for current user\n * var sessionObj = authMgr.getCurrentUserSessionInfo();\n * authMgr.getUserGroups({ userId: sessionObj.userId, token: sessionObj.auth_token })\n * .then(function (groups) {\n * for (var i=0; i < groups.length; i++)\n * { console.log(groups[i].name); }\n * });\n *\n * // get groups for particular user\n * authMgr.getUserGroups({userId: 'b1c19dda-2d2e-4777-ad5d-3929f17e86d3', token: savedProjAccessToken });\n *\n * **Parameters**\n * @param {Object} `params` Object with a userId and token properties.\n * @param {String} `params.userId` The userId. If looking up groups for the currently logged in user, this is in the session information. Otherwise, pass a string.\n * @param {String} `params.token` The authorization credentials (access token) to use for checking the groups for this user. If looking up groups for the currently logged in user, this is in the session information. A team member's token or a project access token can access all the groups for all end users in the team or project.\n * @param {Object} `options` (Optional) Overrides for configuration options.\n */\n getUserGroups: function (params, options) {\n var adapterOptions = this.sessionManager.getMergedOptions({ success: $.noop }, options);\n var $d = $.Deferred();\n var outSuccess = adapterOptions.success;\n\n adapterOptions.success = function (memberInfo) {\n // The member API is at the account scope, we filter by project\n if (adapterOptions.project) {\n memberInfo = $.grep(memberInfo, function (group) {\n return group.project === adapterOptions.project;\n });\n }\n\n outSuccess.apply(this, [memberInfo]);\n $d.resolve(memberInfo);\n };\n\n var memberAdapter = new MemberAdapter({ token: params.token });\n memberAdapter.getGroupsForUser(params, adapterOptions).fail($d.reject);\n return $d.promise();\n },\n\n /**\n * Returns session information for the current user, including the `userId`, `account`, `project`, `groupId`, `groupName`, `isFac` (whether the end user is a facilitator of this group), and `auth_token` (user access token).\n *\n * *Important*: This method is synchronous. The session information is returned immediately in an object; no callbacks or promises are needed.\n *\n * Session information is stored in a cookie in the browser.\n *\n * **Example**\n *\n * var sessionObj = authMgr.getCurrentUserSessionInfo();\n *\n * **Parameters**\n * @param {Object} `options` (Optional) Overrides for configuration options.\n */\n getCurrentUserSessionInfo: function (options) {\n return this.sessionManager.getSession(options);\n },\n\n /*\n * Adds one or more groups to the current session. \n *\n * This method assumes that the project and group exist and the user specified in the session is part of this project and group.\n *\n * Returns the new session object.\n *\n * **Example**\n *\n * authMgr.addGroups({ project: 'hello-world', groupName: 'groupName', groupId: 'groupId' });\n * authMgr.addGroups([{ project: 'hello-world', groupName: 'groupName', groupId: 'groupId' }, { project: 'hello-world', groupName: '...' }]);\n *\n * **Parameters**\n * @param {object|array} `groups` (Required) The group object must contain the `project` (**Project ID**) and `groupName` properties. If passing an array of such objects, all of the objects must contain *different* `project` (**Project ID**) values: although end users may be logged in to multiple projects at once, they may only be logged in to one group per project at a time.\n * @param {string} `group.isFac` (optional) Defaults to `false`. Set to `true` if the user in the session should be a facilitator in this group.\n * @param {string} `group.groupId` (optional) Defaults to undefined. Needed mostly for the Members API.\n */\n addGroups: function (groups) {\n var session = this.getCurrentUserSessionInfo();\n var isArray = Array.isArray(groups);\n groups = isArray ? groups : [groups];\n\n $.each(groups, function (index, group) {\n var extendedGroup = $.extend({}, { isFac: false }, group);\n var project = extendedGroup.project;\n var validProps = ['groupName', 'groupId', 'isFac'];\n if (!project || !extendedGroup.groupName) {\n throw new Error('No project or groupName specified.');\n }\n // filter object\n extendedGroup = _pick(extendedGroup, validProps);\n session.groups[project] = extendedGroup;\n });\n this.sessionManager.saveSession(session);\n return session;\n }\n});\n\nmodule.exports = AuthManager;\n","/**\n* ## World Manager\n*\n* As discussed under the [World API Adapter](../world-api-adapter/), a [run](../../../glossary/#run) is a collection of end user interactions with a project and its model. For building multiplayer simulations you typically want multiple end users to share the same set of interactions, and work within a common state. Epicenter allows you to create \"worlds\" to handle such cases.\n*\n* The World Manager provides an easy way to track and access the current world and run for particular end users. It is typically used in pages that end users will interact with. (The related [World API Adapter](../world-api-adapter/) handles creating multiplayer worlds, and adding and removing end users and runs from a world. Because of this, typically the World Adapter is used for facilitator pages in your project.)\n*\n* ### Using the World Manager\n*\n* To use the World Manager, instantiate it. Then, make calls to any of the methods you need.\n*\n* When you instantiate a World Manager, the world's account id, project id, and group are automatically taken from the session (thanks to the [Authentication Service](../auth-api-service)).\n*\n* Note that the World Manager does *not* create worlds automatically. (This is different than the [Run Manager](../run-manager).) However, you can pass in specific options to any runs created by the manager, using a `run` object.\n*\n* The parameters for creating a World Manager are:\n*\n* * `account`: The **Team ID** in the Epicenter user interface for this project.\n* * `project`: The **Project ID** for this project.\n* * `group`: The **Group Name** for this world.\n* * `run`: Options to use when creating new runs with the manager, e.g. `run: { files: ['data.xls'] }`.\n* * `run.model`: The name of the primary model file for this project. Required if you have not already passed it in as part of the `options` parameter for an enclosing call.\n*\n* For example:\n*\n* var wMgr = new F.manager.WorldManager({\n* account: 'acme-simulations',\n* project: 'supply-chain-game',\n* run: { model: 'supply-chain.py' },\n* group: 'team1'\n* });\n*\n* wMgr.getCurrentRun();\n*/\n\n'use strict';\n\nvar WorldApi = require('../service/world-api-adapter');\nvar RunManager = require('./run-manager');\nvar AuthManager = require('./auth-manager');\nvar worldApi;\n\n// var defaults = {\n// account: '',\n// project: '',\n// group: '',\n// transport: {\n// }\n// };\n\n\nfunction buildStrategy(worldId, dtd) {\n\n return function Ctor(runService, options) {\n this.runService = runService;\n this.options = options;\n\n $.extend(this, {\n reset: function () {\n throw new Error('not implementd. Need api changes');\n },\n\n getRun: function () {\n var _this = this;\n //get or create!\n // Model is required in the options\n var model = this.options.run.model || this.options.model;\n return worldApi.getCurrentRunId({ model: model, filter: worldId })\n .then(function (runId) {\n return _this.runService.load(runId);\n })\n .then(function (run) {\n dtd.resolve.call(this, run, _this.runService);\n })\n .fail(dtd.reject);\n }\n }\n );\n };\n}\n\n\nmodule.exports = function (options) {\n this.options = options || { run: {}, world: {} };\n\n $.extend(true, this.options, this.options.run);\n $.extend(true, this.options, this.options.world);\n\n worldApi = new WorldApi(this.options);\n this._auth = new AuthManager();\n var _this = this;\n\n var api = {\n\n /**\n * Returns the current world (object) and an instance of the [World API Adapter](../world-api-adapter/).\n *\n * **Example**\n *\n * wMgr.getCurrentWorld()\n * .then(function(world, worldAdapter) {\n * console.log(world.id);\n * worldAdapter.getCurrentRunId();\n * });\n *\n * **Parameters**\n * @param {string} `userId` (Optional) The id of the user whose world is being accessed. Defaults to the user in the current session.\n * @param {string} `groupName` (Optional) The name of the group whose world is being accessed. Defaults to the group for the user in the current session.\n */\n getCurrentWorld: function (userId, groupName) {\n var session = this._auth.getCurrentUserSessionInfo();\n if (!userId) {\n userId = session.userId;\n }\n if (!groupName) {\n groupName = session.groupName;\n }\n return worldApi.getCurrentWorldForUser(userId, groupName);\n },\n\n /**\n * Returns the current run (object) and an instance of the [Run API Service](../run-api-service/).\n *\n * **Example**\n *\n * wMgr.getCurrentRun({model: 'myModel.py'})\n * .then(function(run, runService) {\n * console.log(run.id);\n * runService.do('startGame');\n * });\n *\n * **Parameters**\n * @param {string} `model` (Optional) The name of the model file. Required if not already passed in as `run.model` when the World Manager is created.\n */\n getCurrentRun: function (model) {\n var dtd = $.Deferred();\n var session = this._auth.getCurrentUserSessionInfo();\n var curUserId = session.userId;\n var curGroupName = session.groupName;\n\n function getAndRestoreLatestRun(world) {\n if (!world) {\n return dtd.reject({ error: 'The user is not part of any world!' });\n }\n\n var currentWorldId = world.id;\n var runOpts = $.extend(true, _this.options, { model: model });\n var strategy = buildStrategy(currentWorldId, dtd);\n var opt = $.extend(true, {}, {\n strategy: strategy,\n run: runOpts\n });\n var rm = new RunManager(opt);\n\n return rm.getRun()\n .then(function (run) {\n dtd.resolve(run, rm.runService, rm);\n });\n }\n\n this.getCurrentWorld(curUserId, curGroupName)\n .then(getAndRestoreLatestRun);\n\n return dtd.promise();\n }\n };\n\n $.extend(this, api);\n};\n","'use strict';\n\nvar classFrom = require('../../util/inherit');\nvar ConditionalStrategy = require('./conditional-creation-strategy');\n\nvar __super = ConditionalStrategy.prototype;\n\nvar Strategy = classFrom(ConditionalStrategy, {\n constructor: function (runService, options) {\n __super.constructor.call(this, runService, this.createIf, options);\n },\n\n createIf: function (run, headers) {\n // always create a new run!\n return true;\n }\n});\n\nmodule.exports = Strategy;\n","'use strict';\n\nvar makeSeq = require('../../util/make-sequence');\nvar Base = require('./identity-strategy');\nvar SessionManager = require('../../store/session-manager');\nvar classFrom = require('../../util/inherit');\nvar AuthManager = require('../auth-manager');\n\nvar keyNames = require('../key-names');\n\nvar defaults = {\n sessionKey: keyNames.STRATEGY_SESSION_KEY,\n path: ''\n};\n\nfunction setRunInSession(sessionKey, run, sessionManager) {\n sessionManager.getStore().set(sessionKey, JSON.stringify({ runId: run.id }));\n}\n\n/**\n* Conditional Creation Strategy\n* This strategy will try to get the run stored in the cookie and\n* evaluate if needs to create a new run by calling the 'condition' function\n*/\n\n/* jshint eqnull: true */\nvar Strategy = classFrom(Base, {\n constructor: function Strategy(runService, condition, options) {\n\n if (condition == null) {\n throw new Error('Conditional strategy needs a condition to createte a run');\n }\n\n this._auth = new AuthManager();\n this.run = makeSeq(runService);\n this.condition = typeof condition !== 'function' ? function () { return condition; } : condition;\n this.options = $.extend(true, {}, defaults, options);\n this.sessionManager = new SessionManager(options);\n this.runOptions = this.options.run;\n },\n\n runOptionsWithScope: function () {\n var userSession = this._auth.getCurrentUserSessionInfo();\n return $.extend({\n scope: { group: userSession.groupName }\n }, this.runOptions);\n },\n\n reset: function (runServiceOptions) {\n var _this = this;\n var opt = this.runOptionsWithScope();\n\n return this.run\n .create(opt, runServiceOptions)\n .then(function (run) {\n setRunInSession(_this.options.sessionKey, run, _this.sessionManager);\n run.freshlyCreated = true;\n return run;\n })\n .start();\n },\n\n getRun: function () {\n var sessionStore = this.sessionManager.getStore();\n var runSession = JSON.parse(sessionStore.get(this.options.sessionKey));\n\n if (runSession && runSession.runId) {\n return this._loadAndCheck(runSession).fail(function () {\n return this.reset(); //if it got the wrong cookie for e.g.\n }.bind(this));\n } else {\n return this.reset();\n }\n },\n\n _loadAndCheck: function (runSession) {\n var shouldCreate = false;\n var _this = this;\n\n return this.run\n .load(runSession.runId, null, {\n success: function (run, msg, headers) {\n shouldCreate = _this.condition.call(_this, run, headers);\n }\n })\n .then(function (run) {\n if (shouldCreate) {\n var opt = _this.runOptionsWithScope();\n // we need to do this, on the original runService (ie not sequencialized)\n // so we don't get in the middle of the queue\n return _this.run.original.create(opt)\n .then(function (run) {\n setRunInSession(_this.options.sessionKey, run, _this.sessionManager);\n run.freshlyCreated = true;\n return run;\n });\n }\n\n return run;\n })\n .start();\n }\n});\n\nmodule.exports = Strategy;\n","'use strict';\n\nvar classFrom = require('../../util/inherit');\nvar Base = {};\n\n// Interface that all strategies need to implement\nmodule.exports = classFrom(Base, {\n constructor: function (runService, options) {\n this.runService = runService;\n },\n\n reset: function () {\n // return a newly created run\n return $.Deferred().resolve().promise();\n },\n\n getRun: function () {\n // return a usable run\n return $.Deferred().resolve(this.runService).promise();\n }\n});\n","'use strict';\n\nvar classFrom = require('../../util/inherit');\nvar ConditionalStrategy = require('./conditional-creation-strategy');\n\nvar __super = ConditionalStrategy.prototype;\n\n/*\n* create a new run only if nothing is stored in the cookie\n* this is useful for baseRuns.\n*/\nvar Strategy = classFrom(ConditionalStrategy, {\n constructor: function (runService, options) {\n __super.constructor.call(this, runService, this.createIf, options);\n },\n\n createIf: function (run, headers) {\n // if we are here, it means that the run exists... so we don't need a new one\n return false;\n }\n});\n\nmodule.exports = Strategy;\n","'use strict';\nvar classFrom = require('../../util/inherit');\nvar ConditionalStrategy = require('./conditional-creation-strategy');\n\nvar __super = ConditionalStrategy.prototype;\n\nvar Strategy = classFrom(ConditionalStrategy, {\n constructor: function (runService, options) {\n __super.constructor.call(this, runService, this.createIf, options);\n },\n\n createIf: function (run, headers) {\n return headers.getResponseHeader('pragma') === 'persistent';\n }\n});\n\nmodule.exports = Strategy;\n","'use strict';\nvar classFrom = require('../../util/inherit');\nvar ConditionalStrategy = require('./conditional-creation-strategy');\n\nvar __super = ConditionalStrategy.prototype;\n\nvar Strategy = classFrom(ConditionalStrategy, {\n constructor: function (runService, options) {\n __super.constructor.call(this, runService, this.createIf, options);\n },\n\n createIf: function (run, headers) {\n return headers.getResponseHeader('pragma') === 'persistent' || run.initialized;\n }\n});\n\nmodule.exports = Strategy;\n","'use strict';\n\n/**\n * ## Channel Service\n *\n * The Epicenter platform provides a push channel, which allows you to publish and subscribe to messages within a [project](../../../glossary/#projects), [group](../../../glossary/#groups), or [multiplayer world](../../../glossary/#world). There are two main use cases for the channel: event notifications and chat messages.\n *\n * The Channel Service is a building block for this functionality. It creates a publish-subscribe object, allowing you to publish messages, subscribe to messages, or unsubscribe from messages for a given 'topic' on a `$.cometd` transport instance.\n *\n * Typically, you use the [Epicenter Channel Manager](../epicenter-channel-manager/) to create or retrieve channels, then use the Channel Service `subscribe()` and `publish()` methods to listen to or update data. (For additional background on Epicenter's push channel, see the introductory notes on the [Push Channel API](../../../rest_apis/multiplayer/channel/) page.)\n *\n * You'll need to include the `epicenter-multiplayer-dependencies.js` library in addition to the `epicenter.js` library in your project to use the Channel Service. See [Including Epicenter.js](../../#include).\n *\n * To use the Channel Service, instantiate it, then make calls to any of the methods you need.\n *\n * var cs = new F.service.Channel();\n * cs.publish('/acme-simulations/supply-chain-game/fall-seminar/run/variables', { price: 50 });\n *\n * The parameters for instantiating a Channel Service include:\n *\n * * `options` The options object to configure the Channel Service.\n * * `options.base` The base topic. This is added as a prefix to all further topics you publish or subscribe to while working with this Channel Service.\n * * `options.topicResolver` A function that processes all 'topics' passed into the `publish` and `subscribe` methods. This is useful if you want to implement your own serialize functions for converting custom objects to topic names. Returns a String. By default, it just echoes the topic.\n * * `options.transport` The instance of `$.cometd` to hook onto. See http://docs.cometd.org/reference/javascript.html for additional background on cometd.\n */\nvar Channel = function (options) {\n var defaults = {\n\n /**\n * The base topic. This is added as a prefix to all further topics you publish or subscribe to while working with this Channel Service.\n * @type {string}\n */\n base: '',\n\n /**\n * A function that processes all 'topics' passed into the `publish` and `subscribe` methods. This is useful if you want to implement your own serialize functions for converting custom objects to topic names. By default, it just echoes the topic.\n *\n * **Parameters**\n *\n * * `topic` Topic to parse.\n *\n * **Return Value**\n *\n * * *String*: This function should return a string topic.\n *\n * @type {function}\n */\n topicResolver: function (topic) {\n return topic;\n },\n\n /**\n * The instance of `$.cometd` to hook onto.\n * @type {object}\n */\n transport: null\n };\n this.channelOptions = $.extend(true, {}, defaults, options);\n};\n\nvar makeName = function (channelName, topic) {\n //Replace trailing/double slashes\n var newName = (channelName ? (channelName + '/' + topic) : topic).replace(/\\/\\//g, '/').replace(/\\/$/,'');\n return newName;\n};\n\n\nChannel.prototype = $.extend(Channel.prototype, {\n\n // future functionality:\n // // Set the context for the callback\n // cs.subscribe('run', function () { this.innerHTML = 'Triggered'}, document.body);\n //\n // // Control the order of operations by setting the `priority`\n // cs.subscribe('run', cb, this, {priority: 9});\n //\n // // Only execute the callback, `cb`, if the value of the `price` variable is 50\n // cs.subscribe('run/variables/price', cb, this, {priority: 30, value: 50});\n //\n // // Only execute the callback, `cb`, if the value of the `price` variable is greater than 50\n // subscribe('run/variables/price', cb, this, {priority: 30, value: '>50'});\n //\n // // Only execute the callback, `cb`, if the value of the `price` variable is even\n // subscribe('run/variables/price', cb, this, {priority: 30, value: function (val) {return val % 2 === 0}});\n\n\n /**\n * Subscribe to changes on a topic.\n *\n * The topic should include the full path of the account id (**Team ID** for team projects), project id, and group name. (In most cases, it is simpler to use the [Epicenter Channel Manager](../epicenter-channel-manager/) instead, in which case this is configured for you.)\n *\n * **Examples**\n *\n * var cb = function(val) { console.log(val.data); };\n *\n * // Subscribe to changes on a top-level 'run' topic\n * cs.subscribe('/acme-simulations/supply-chain-game/fall-seminar/run', cb);\n *\n * // Subscribe to changes on children of the 'run' topic. Note this will also be triggered for changes to run.x.y.z.\n * cs.subscribe('/acme-simulations/supply-chain-game/fall-seminar/run/*', cb);\n *\n * // Subscribe to changes on both the top-level 'run' topic and its children\n * cs.subscribe(['/acme-simulations/supply-chain-game/fall-seminar/run',\n * '/acme-simulations/supply-chain-game/fall-seminar/run/*'], cb);\n *\n * // Subscribe to changes on a particular variable\n * subscribe('/acme-simulations/supply-chain-game/fall-seminar/run/variables/price', cb);\n *\n *\n * **Return Value**\n *\n * * *String* Returns a token you can later use to unsubscribe.\n *\n * **Parameters**\n * @param {String|Array} `topic` List of topics to listen for changes on.\n * @param {Function} `callback` Callback function to execute. Callback is called with signature `(evt, payload, metadata)`.\n * @param {Object} `context` Context in which the `callback` is executed.\n * @param {Object} `options` (Optional) Overrides for configuration options.\n * @param {Number} `options.priority` Used to control order of operations. Defaults to 0. Can be any +ve or -ve number.\n * @param {String|Number|Function} `options.value` The `callback` is only triggered if this condition matches. See examples for details.\n *\n */\n subscribe: function (topic, callback, context, options) {\n\n var topics = [].concat(topic);\n var me = this;\n var subscriptionIds = [];\n var opts = me.channelOptions;\n\n opts.transport.batch(function () {\n $.each(topics, function (index, topic) {\n topic = makeName(opts.base, opts.topicResolver(topic));\n subscriptionIds.push(opts.transport.subscribe(topic, callback));\n });\n });\n return (subscriptionIds[1] ? subscriptionIds : subscriptionIds[0]);\n },\n\n /**\n * Publish data to a topic.\n *\n * **Examples**\n *\n * // Send data to all subscribers of the 'run' topic\n * cs.publish('/acme-simulations/supply-chain-game/fall-seminar/run', { completed: false });\n *\n * // Send data to all subscribers of the 'run/variables' topic\n * cs.publish('/acme-simulations/supply-chain-game/fall-seminar/run/variables', { price: 50 });\n *\n * **Parameters**\n *\n * @param {String} `topic` Topic to publish to.\n * @param {*} `data` Data to publish to topic.\n *\n */\n publish: function (topic, data) {\n var topics = [].concat(topic);\n var me = this;\n var returnObjs = [];\n var opts = me.channelOptions;\n\n\n opts.transport.batch(function () {\n $.each(topics, function (index, topic) {\n topic = makeName(opts.base, opts.topicResolver(topic));\n if (topic.charAt(topic.length - 1) === '*') {\n topic = topic.replace(/\\*+$/, '');\n console.warn('You can cannot publish to channels with wildcards. Publishing to ', topic, 'instead');\n }\n returnObjs.push(opts.transport.publish(topic, data));\n });\n });\n return (returnObjs[1] ? returnObjs : returnObjs[0]);\n },\n\n /**\n * Unsubscribe from changes to a topic.\n *\n * **Example**\n *\n * cs.unsubscribe('sampleToken');\n *\n * **Parameters**\n * @param {String} `token` The token for topic is returned when you initially subscribe. Pass it here to unsubscribe from that topic.\n */\n unsubscribe: function (token) {\n this.channelOptions.transport.unsubscribe(token);\n return token;\n },\n\n /**\n * Start listening for events on this instance. Signature is same as for jQuery Events: http://api.jquery.com/on/.\n *\n * Supported events are: `connect`, `disconnect`, `subscribe`, `unsubscribe`, `publish`, `error`.\n *\n * **Parameters**\n *\n * @param {string} `event` The event type. See more detail at jQuery Events: http://api.jquery.com/on/.\n */\n on: function (event) {\n $(this).on.apply($(this), arguments);\n },\n\n /**\n * Stop listening for events on this instance. Signature is same as for jQuery Events: http://api.jquery.com/off/.\n *\n * **Parameters**\n *\n * @param {string} `event` The event type. See more detail at jQuery Events: http://api.jquery.com/off/.\n */\n off: function (event) {\n $(this).off.apply($(this), arguments);\n },\n\n /**\n * Trigger events and execute handlers. Signature is same as for jQuery Events: http://api.jquery.com/trigger/.\n *\n * **Parameters**\n *\n * @param {string} `event` The event type. See more detail at jQuery Events: http://api.jquery.com/trigger/.\n */\n trigger: function (event) {\n $(this).trigger.apply($(this), arguments);\n }\n\n});\n\nmodule.exports = Channel;\n","'use strict';\n\n/**\n * ## Epicenter Channel Manager\n *\n * The Epicenter platform provides a push channel, which allows you to publish and subscribe to messages within a [project](../../../glossary/#projects), [group](../../../glossary/#groups), or [multiplayer world](../../../glossary/#world). There are two main use cases for the channel: event notifications and chat messages.\n *\n * The Epicenter Channel Manager is a wrapper around the (more generic) [Channel Manager](../channel-manager/), to instantiate it with Epicenter-specific defaults. If you are interested in including a notification or chat feature in your project, using an Epicenter Channel Manager is probably the easiest way to get started.\n *\n * You'll need to include the `epicenter-multiplayer-dependencies.js` library in addition to the `epicenter.js` library in your project to use the Epicenter Channel Manager. See [Including Epicenter.js](../../#include).\n *\n * To use the Epicenter Channel Manager: instantiate it, get the channel of the scope you want ([user](../../../glossary/#users), [world](../../../glossary/#world), or [group](../../../glossary/#groups)), then use the channel's `subscribe()` and `publish()` methods to subscribe to topics or publish data to topics.\n *\n * var cm = new F.manager.ChannelManager();\n * var gc = cm.getGroupChannel();\n * gc.subscribe('broadcasts', callback);\n *\n * For additional background on Epicenter's push channel, see the introductory notes on the [Push Channel API](../../../rest_apis/multiplayer/channel/) page.\n *\n * The parameters for instantiating an Epicenter Channel Manager include:\n *\n * * `options` Object with details about the Epicenter project for this Epicenter Channel Manager instance.\n * * `options.account` The Epicenter account id (**Team ID** for team projects, **User ID** for personal projects).\n * * `options.project` Epicenter project id.\n * * `options.userName` Epicenter userName used for authentication.\n * * `options.userId` Epicenter user id used for authentication. Optional; `options.userName` is preferred.\n * * `options.token` Epicenter token used for authentication. (You can retrieve this using `authManager.getToken()` from the [Authorization Manager](../auth-manager/).)\n * * `options.allowAllChannels` If not included or if set to `false`, all channel paths are validated; if your project requires [Push Channel Authorization](../../../updating_your_settings/), you should use this option. If you want to allow other channel paths, set to `true`; this is not common.\n */\n\nvar ChannelManager = require('./channel-manager');\nvar classFrom = require('../util/inherit');\nvar urlService = require('../service/url-config-service');\nvar SessionManager = require('../store/session-manager');\n\nvar AuthManager = require('./auth-manager');\n\nvar validTypes = {\n project: true,\n group: true,\n world: true,\n user: true,\n data: true,\n general: true,\n chat: true\n};\nvar session = new AuthManager();\nvar getFromSettingsOrSessionOrError = function (value, sessionKeyName, settings) {\n if (!value) {\n var userInfo = session.getCurrentUserSessionInfo();\n if (settings && settings[sessionKeyName]) {\n value = settings[sessionKeyName];\n } else if (userInfo[sessionKeyName]) {\n value = userInfo[sessionKeyName];\n } else {\n throw new Error(sessionKeyName + ' not found. Please log-in again, or specify ' + sessionKeyName + ' explicitly');\n }\n }\n return value;\n};\nvar __super = ChannelManager.prototype;\nvar EpicenterChannelManager = classFrom(ChannelManager, {\n constructor: function (options) {\n this.sessionManager = new SessionManager();\n var defaultCometOptions = this.sessionManager.getMergedOptions(options);\n\n var urlOpts = urlService(defaultCometOptions.server);\n if (!defaultCometOptions.url) {\n //Default epicenter cometd endpoint\n defaultCometOptions.url = urlOpts.protocol + '://' + urlOpts.host + '/channel/subscribe';\n }\n\n if (defaultCometOptions.handshake === undefined) {\n var userName = defaultCometOptions.userName;\n var userId = defaultCometOptions.userId;\n var token = defaultCometOptions.token;\n if ((userName || userId) && token) {\n var userProp = userName ? 'userName' : 'userId';\n var ext = {\n authorization: 'Bearer ' + token\n };\n ext[userProp] = userName ? userName : userId;\n\n defaultCometOptions.handshake = {\n ext: ext\n };\n }\n }\n\n this.options = defaultCometOptions;\n return __super.constructor.call(this, defaultCometOptions);\n },\n\n /**\n * Creates and returns a channel, that is, an instance of a [Channel Service](../channel-service/).\n *\n * This method enforces Epicenter-specific channel naming: all channels requested must be in the form `/{type}/{account id}/{project id}/{...}`, where `type` is one of `run`, `data`, `user`, `world`, or `chat`.\n *\n * **Example**\n *\n * var cm = new F.manager.EpicenterChannelManager();\n * var channel = cm.getChannel('/group/acme/supply-chain-game/');\n *\n * channel.subscribe('topic', callback);\n * channel.publish('topic', { myData: 100 });\n *\n * **Parameters**\n * @param {Object|String} `options` (Optional) If string, assumed to be the base channel url. If object, assumed to be configuration options for the constructor.\n */\n getChannel: function (options) {\n if (options && typeof options !== 'object') {\n options = {\n base: options\n };\n }\n var channelOpts = $.extend({}, this.options, options);\n var base = channelOpts.base;\n if (!base) {\n throw new Error('No base topic was provided');\n }\n\n if (!channelOpts.allowAllChannels) {\n var baseParts = base.split('/');\n var channelType = baseParts[1];\n if (baseParts.length < 4) {\n throw new Error('Invalid channel base name, it must be in the form /{type}/{account id}/{project id}/{...}');\n }\n if (!validTypes[channelType]) {\n throw new Error('Invalid channel type');\n }\n }\n return __super.getChannel.apply(this, arguments);\n },\n\n /**\n * Create and return a publish/subscribe channel (from the underlying [Channel Manager](../channel-manager/)) for the given [group](../../../glossary/#groups). The group must exist in the account (team) and project provided.\n *\n * There are no notifications from Epicenter on this channel; all messages are user-originated.\n *\n * **Example**\n *\n * var cm = new F.manager.ChannelManager();\n * var gc = cm.getGroupChannel();\n * gc.subscribe('broadcasts', callback);\n *\n * **Return Value**\n *\n * * *Channel* Returns the channel (an instance of the [Channel Service](../channel-service/)).\n *\n * **Parameters**\n *\n * @param {String} `groupName` (Optional) Group to broadcast to. If not provided, picks up group from current session if end user is logged in.\n */\n getGroupChannel: function (groupName) {\n groupName = getFromSettingsOrSessionOrError(groupName, 'groupName', this.options);\n var account = getFromSettingsOrSessionOrError('', 'account', this.options);\n var project = getFromSettingsOrSessionOrError('', 'project', this.options);\n\n var baseTopic = ['/group', account, project, groupName].join('/');\n return __super.getChannel.call(this, { base: baseTopic });\n },\n\n /**\n * Create and return a publish/subscribe channel (from the underlying [Channel Manager](../channel-manager/)) for the given [world](../../../glossary/#world).\n *\n * This is typically used together with the [World Manager](../world-manager).\n *\n * **Example**\n *\n * var cm = new F.manager.ChannelManager();\n * var worldManager = new F.manager.WorldManager({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * group: 'team1',\n * run: { model: 'model.eqn' }\n * });\n * worldManager.getCurrentWorld().then(function (worldObject, worldAdapter) {\n * var worldChannel = cm.getWorldChannel(worldObject);\n * worldChannel.subscribe('', function (data) {\n * console.log(data);\n * });\n * });\n *\n * **Return Value**\n *\n * * *Channel* Returns the channel (an instance of the [Channel Service](../channel-service/)).\n *\n * **Parameters**\n *\n * @param {String|Object} `world` The world object or id.\n * @param {String} `groupName` (Optional) Group the world exists in. If not provided, picks up group from current session if end user is logged in.\n */\n getWorldChannel: function (world, groupName) {\n var worldid = ($.isPlainObject(world) && world.id) ? world.id : world;\n if (!worldid) {\n throw new Error('Please specify a world id');\n }\n groupName = getFromSettingsOrSessionOrError(groupName, 'groupName', this.options);\n var account = getFromSettingsOrSessionOrError('', 'account', this.options);\n var project = getFromSettingsOrSessionOrError('', 'project', this.options);\n\n var baseTopic = ['/world', account, project, groupName, worldid].join('/');\n return __super.getChannel.call(this, { base: baseTopic });\n },\n\n /**\n * Create and return a publish/subscribe channel (from the underlying [Channel Manager](../channel-manager/)) for the current [end user](../../../glossary/#users) in that user's current [world](../../../glossary/#world).\n *\n * This is typically used together with the [World Manager](../world-manager). Note that this channel only gets notifications for worlds currently in memory. (See more background on [persistence](../../../run_persistence).)\n *\n * **Example**\n *\n * var cm = new F.manager.ChannelManager();\n * var worldManager = new F.manager.WorldManager({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * group: 'team1',\n * run: { model: 'model.eqn' }\n * });\n * worldManager.getCurrentWorld().then(function (worldObject, worldAdapter) {\n * var userChannel = cm.getUserChannel(worldObject);\n * userChannel.subscribe('', function (data) {\n * console.log(data);\n * });\n * });\n *\n *\n * **Return Value**\n *\n * * *Channel* Returns the channel (an instance of the [Channel Service](../channel-service/)).\n *\n * **Parameters**\n *\n * @param {String|Object} `world` World object or id.\n * @param {String|Object} `user` (Optional) User object or id. If not provided, picks up user id from current session if end user is logged in.\n * @param {String} `groupName` (Optional) Group the world exists in. If not provided, picks up group from current session if end user is logged in.\n */\n getUserChannel: function (world, user, groupName) {\n var worldid = ($.isPlainObject(world) && world.id) ? world.id : world;\n if (!worldid) {\n throw new Error('Please specify a world id');\n }\n var userid = ($.isPlainObject(user) && user.id) ? user.id : user;\n userid = getFromSettingsOrSessionOrError(userid, 'userId', this.options);\n groupName = getFromSettingsOrSessionOrError(groupName, 'groupName', this.options);\n\n var account = getFromSettingsOrSessionOrError('', 'account', this.options);\n var project = getFromSettingsOrSessionOrError('', 'project', this.options);\n\n var baseTopic = ['/user', account, project, groupName, worldid, userid].join('/');\n return __super.getChannel.call(this, { base: baseTopic });\n },\n\n /**\n * Create and return a publish/subscribe channel (from the underlying [Channel Manager](../channel-manager/)) that automatically tracks the presence of an [end user](../../../glossary/#users), that is, whether the end user is currently online in this group and world. Notifications are automatically sent when the end user comes online, and when the end user goes offline (not present for more than 2 minutes). Useful in multiplayer games for letting each end user know whether other users in their shared world are also online.\n *\n * **Example**\n *\n * var cm = new F.manager.ChannelManager();\n * var worldManager = new F.manager.WorldManager({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * model: 'model.eqn'\n * });\n * worldManager.getCurrentWorld().then(function (worldObject, worldService) {\n * var presenceChannel = cm.getPresenceChannel(worldObject);\n * presenceChannel.on('presence', function (evt, notification) {\n * console.log(notification.online, notification.userId);\n * });\n * });\n *\n *\n * **Return Value**\n *\n * * *Channel* Returns the channel (an instance of the [Channel Service](../channel-service/)).\n *\n * **Parameters**\n *\n * @param {String|Object} `world` World object or id.\n * @param {String|Object} `userid` (Optional) User object or id. If not provided, picks up user id from current session if end user is logged in.\n * @param {String} `groupName` (Optional) Group the world exists in. If not provided, picks up group from current session if end user is logged in.\n */\n getPresenceChannel: function (world, userid, groupName) {\n var worldid = ($.isPlainObject(world) && world.id) ? world.id : world;\n if (!worldid) {\n throw new Error('Please specify a world id');\n }\n userid = getFromSettingsOrSessionOrError(userid, 'userId', this.options);\n groupName = getFromSettingsOrSessionOrError(groupName, 'groupName', this.options);\n\n var account = getFromSettingsOrSessionOrError('', 'account', this.options);\n var project = getFromSettingsOrSessionOrError('', 'project', this.options);\n\n var baseTopic = ['/user', account, project, groupName, worldid].join('/');\n var channel = __super.getChannel.call(this, { base: baseTopic });\n\n var lastPingTime = { };\n\n var PING_INTERVAL = 6000;\n channel.subscribe('internal-ping-channel', function (notification) {\n var incomingUserId = notification.data.user;\n if (!lastPingTime[incomingUserId] && incomingUserId !== userid) {\n channel.trigger.call(channel, 'presence', { userId: incomingUserId, online: true });\n }\n lastPingTime[incomingUserId] = (new Date()).valueOf();\n });\n\n setInterval(function () {\n channel.publish('internal-ping-channel', { user: userid });\n\n $.each(lastPingTime, function (key, value) {\n var now = (new Date()).valueOf();\n if (value && value + (PING_INTERVAL * 2) < now) {\n lastPingTime[key] = null;\n channel.trigger.call(channel, 'presence', { userId: key, online: false });\n }\n });\n }, PING_INTERVAL);\n\n return channel;\n },\n\n /**\n * Create and return a publish/subscribe channel (from the underlying [Channel Manager](../channel-manager/)) for the given collection. (The collection name is specified in the `root` argument when the [Data Service](../data-api-service/) is instantiated.) Must be one of the collections in this account (team) and project.\n *\n * There are automatic notifications from Epicenter on this channel when data is created, updated, or deleted in this collection. See more on [automatic messages to the data channel](../../../rest_apis/multiplayer/channel/#data-messages).\n *\n * **Example**\n *\n * var cm = new F.manager.ChannelManager();\n * var dc = cm.getDataChannel('survey-responses');\n * dc.subscribe('', function(data, meta) {\n * console.log(data);\n *\n * // meta.date is time of change,\n * // meta.subType is the kind of change: new, update, or delete\n * // meta.path is the full path to the changed data\n * console.log(meta);\n * });\n *\n * **Return Value**\n *\n * * *Channel* Returns the channel (an instance of the [Channel Service](../channel-service/)).\n *\n * **Parameters**\n *\n * @param {String} `collection` Name of collection whose automatic notifications you want to receive.\n */\n getDataChannel: function (collection) {\n if (!collection) {\n throw new Error('Please specify a collection to listen on.');\n }\n var account = getFromSettingsOrSessionOrError('', 'account', this.options);\n var project = getFromSettingsOrSessionOrError('', 'project', this.options);\n var baseTopic = ['/data', account, project, collection].join('/');\n var channel = __super.getChannel.call(this, { base: baseTopic });\n\n //TODO: Fix after Epicenter bug is resolved\n var oldsubs = channel.subscribe;\n channel.subscribe = function (topic, callback, context, options) {\n var callbackWithCleanData = function (payload) {\n var meta = {\n path: payload.channel,\n subType: payload.data.subType,\n date: payload.data.date\n };\n var actualData = payload.data.data;\n if (actualData.data) { //Delete notifications are one data-level behind of course\n actualData = actualData.data;\n }\n\n callback.call(context, actualData, meta);\n };\n return oldsubs.call(channel, topic, callbackWithCleanData, context, options);\n };\n\n return channel;\n }\n});\n\nmodule.exports = EpicenterChannelManager;\n","'use strict';\n\nmodule.exports = {\n _pick: function (obj, props) {\n var res = {};\n for (var p in obj) {\n if (props.indexOf(p) !== -1) {\n res[p] = obj[p];\n }\n }\n\n return res;\n }\n};\n","'use strict';\n\nvar keyNames = require('../managers/key-names');\nvar StorageFactory = require('./store-factory');\nvar optionUtils = require('../util/option-utils');\n\nvar EPI_SESSION_KEY = keyNames.EPI_SESSION_KEY;\nvar defaults = {\n /**\n * Where to store user access tokens for temporary access. Defaults to storing in a cookie in the browser.\n * @type {string}\n */\n store: { synchronous: true }\n};\n\nvar SessionManager = function (managerOptions) {\n managerOptions = managerOptions || {};\n function getBaseOptions(overrides) {\n overrides = overrides || {};\n var libOptions = optionUtils.getOptions();\n var finalOptions = $.extend(true, {}, defaults, libOptions, managerOptions, overrides);\n return finalOptions;\n }\n\n function getStore(overrides) {\n var baseOptions = getBaseOptions(overrides);\n var storeOpts = baseOptions.store || {};\n if (storeOpts.root === undefined && baseOptions.account && baseOptions.project && !baseOptions.isLocal) {\n storeOpts.root = '/app/' + baseOptions.account + '/' + baseOptions.project;\n }\n return new StorageFactory(storeOpts);\n }\n\n var publicAPI = {\n saveSession: function (userInfo, options) {\n var serialized = JSON.stringify(userInfo);\n getStore(options).set(EPI_SESSION_KEY, serialized);\n },\n getSession: function (options) {\n // var session = getStore(options).get(EPI_SESSION_KEY) || '{}';\n // return JSON.parse(session);\n var store = getStore(options);\n var finalOpts = store.serviceOptions;\n var serialized = store.get(EPI_SESSION_KEY) || '{}';\n var session = JSON.parse(serialized);\n // If the url contains the project and account\n // validate the account and project in the session\n // and override project, groupName, groupId and isFac\n // Otherwise (i.e. localhost) use the saved session values\n var account = finalOpts.account;\n var project = finalOpts.project;\n if (account && session.account !== account) {\n // This means that the token was not used to login to the same account\n return {};\n }\n if (session.groups && account && project) {\n var group = session.groups[project] || { groupId: '', groupName: '', isFac: false };\n $.extend(session, { project: project }, group);\n }\n return session;\n },\n removeSession: function (options) {\n var store = getStore(options);\n Object.keys(keyNames).forEach(function (cookieKey) {\n var cookieName = keyNames[cookieKey];\n store.remove(cookieName);\n });\n return true;\n },\n getStore: function (options) {\n return getStore(options);\n },\n\n getMergedOptions: function () {\n var args = Array.prototype.slice.call(arguments);\n var overrides = $.extend.apply($, [true, {}].concat(args));\n var baseOptions = getBaseOptions(overrides);\n var session = this.getSession(overrides);\n\n var sessionDefaults = {\n /**\n * For projects that require authentication, pass in the user access token (defaults to empty string). If the user is already logged in to Epicenter, the user access token is already set in a cookie and automatically loaded from there. (See [more background on access tokens](../../../project_access/)).\n * @see [Authentication API Service](../auth-api-service/) for getting tokens.\n * @type {String}\n */\n //jshint camelcase: false\n //jscs:disable\n token: session.auth_token,\n /**\n * The group name. If left undefined, taken from the cookie session.\n * @type {String}\n */\n group: session.groupName,\n /**\n * The group id. If left undefined, taken from the cookie session.\n * @type {String}\n */\n groupId: session.groupId,\n userId: session.userId\n };\n return $.extend(true, sessionDefaults, baseOptions);\n }\n };\n $.extend(this, publicAPI);\n};\n\nmodule.exports = SessionManager;","'use strict';\n\nvar ConfigService = require('./configuration-service');\nvar SessionManager = require('../store/session-manager');\nvar objectAssign = require('object-assign');\n\nvar serviceUtils = {\n /*\n * Gets the default options for a api service.\n * It will merge:\n * - The Session options (Using the Session Manager)\n * - The Authorization Header from the token option\n * - The full url from the endpoint option\n * With the supplied overrides and defaults\n *\n */\n getDefaultOptions: function (defaults) {\n var rest = Array.prototype.slice.call(arguments, 1);\n var sessionManager = new SessionManager();\n var serviceOptions = sessionManager.getMergedOptions.apply(sessionManager, [defaults].concat(rest));\n\n serviceOptions.transport = objectAssign({}, serviceOptions.transport, {\n url: this.getApiUrl(serviceOptions.apiEndpoint, serviceOptions)\n });\n\n if (serviceOptions.token) {\n serviceOptions.transport.headers = {\n 'Authorization': 'Bearer ' + serviceOptions.token\n };\n }\n return serviceOptions;\n },\n\n getApiUrl: function (apiEndpoint, serviceOptions) {\n var urlConfig = new ConfigService(serviceOptions).get('server');\n return urlConfig.getAPIPath(apiEndpoint);\n }\n};\n\nmodule.exports = serviceUtils;","module.exports = {\n 'new-if-initialized': require('./new-if-initialized-strategy'),\n 'new-if-persisted': require('./new-if-persisted-strategy'),\n 'new-if-missing': require('./new-if-missing-strategy'),\n 'always-new': require('./always-new-strategy'),\n 'multiplayer': require('./multiplayer-strategy'),\n 'persistent-single-player': require('./persistent-single-player-strategy'),\n 'none': require('./identity-strategy')\n};\n","'use strict';\n\n\nmodule.exports = {\n reset: function (params, options, manager) {\n return manager.reset(options);\n }\n};\n","'use strict';\n\nvar Channel = require('../service/channel-service');\nvar SessionManager = require('../store/session-manager');\n\n/**\n * ## Channel Manager\n *\n * There are two main use cases for the channel: event notifications and chat messages.\n *\n * The Channel Manager is a wrapper around the default [cometd JavaScript library](http://docs.cometd.org/2/reference/javascript.html), `$.cometd`. It provides a few nice features that `$.cometd` doesn't, including:\n *\n * * Automatic re-subscription to channels if you lose your connection\n * * Online / Offline notifications\n * * 'Events' for cometd notifications (instead of having to listen on specific meta channels)\n *\n * While you can work directly with the Channel Manager through Node.js (for example, `require('manager/channel-manager')`) -- or even work directly with `$.cometd` and Epicenter's underlying [Push Channel API](../../../rest_apis/multiplayer/channel/) -- most often it will be easiest to work with the [Epicenter Channel Manager](../epicenter-channel-manager/). The Epicenter Channel Manager is a wrapper that instantiates a Channel Manager with Epicenter-specific defaults.\n *\n * You'll need to include the `epicenter-multiplayer-dependencies.js` library in addition to the `epicenter.js` library in your project to use the Channel Manager. (See [Including Epicenter.js](../../#include).)\n *\n * To use the Channel Manager in client-side JavaScript, instantiate the [Epicenter Channel Manager](../epicenter-channel-manager/), get the channel, then use the channel's `subscribe()` and `publish()` methods to subscribe to topics or publish data to topics.\n *\n * var cm = new F.manager.ChannelManager();\n * var channel = cm.getChannel();\n *\n * channel.subscribe('topic', callback);\n * channel.publish('topic', { myData: 100 });\n *\n * The parameters for instantiating a Channel Manager include:\n *\n * * `options` The options object to configure the Channel Manager. Besides the common options listed here, see http://docs.cometd.org/reference/javascript.html for other supported options.\n * * `options.url` The Cometd endpoint URL.\n * * `options.websocketEnabled` Whether websocket support is active (boolean).\n * * `options.channel` Other defaults to pass on to instances of the underlying Channel Service. See [Channel Service](../channel-service/) for details.\n *\n */\nvar ChannelManager = function (options) {\n if (!$.cometd) {\n throw new Error('Cometd library not found. Please include epicenter-multiplayer-dependencies.js');\n }\n if (!options || !options.url) {\n throw new Error('Please provide an url for the cometd server');\n }\n\n var defaults = {\n /**\n * The Cometd endpoint URL.\n * @type {string}\n */\n url: '',\n\n /**\n * The log level for the channel (logs to console).\n * @type {string}\n */\n logLevel: 'info',\n\n /**\n * Whether websocket support is active. Defaults to `false`; Epicenter doesn't currently support communication through websockets.\n * @type {boolean}\n */\n websocketEnabled: false,\n\n /**\n * If false each instance of Channel will have a separate cometd connection to server, which could be noisy. Set to true to re-use the same connection across instances.\n * @type {boolean}\n */\n shareConnection: false,\n\n /**\n * Other defaults to pass on to instances of the underlying [Channel Service](../channel-service/), which are created through `getChannel()`.\n * @type {object}\n */\n channel: {\n\n },\n\n /**\n * Options to pass to the channel handshake.\n *\n * For example, the [Epicenter Channel Manager](../epicenter-channel-manager/) passes `ext` and authorization information. More information on possible options is in the details of the underlying [Push Channel API](../../../rest_apis/multiplayer/channel/).\n *\n * @type {object}\n */\n handshake: undefined\n };\n this.sessionManager = new SessionManager();\n var defaultCometOptions = this.sessionManager.getMergedOptions(defaults, options);\n this.currentSubscriptions = [];\n this.options = defaultCometOptions;\n\n if (defaultCometOptions.shareConnection && ChannelManager.prototype._cometd) {\n this.cometd = ChannelManager.prototype._cometd;\n return this;\n }\n var cometd = new $.Cometd();\n ChannelManager.prototype._cometd = cometd;\n\n cometd.websocketEnabled = defaultCometOptions.websocketEnabled;\n\n this.isConnected = false;\n var connectionBroken = function (message) {\n $(this).trigger('disconnect', message);\n };\n var connectionSucceeded = function (message) {\n $(this).trigger('connect', message);\n };\n var me = this;\n\n cometd.configure(defaultCometOptions);\n\n cometd.addListener('/meta/connect', function (message) {\n var wasConnected = this.isConnected;\n this.isConnected = (message.successful === true);\n if (!wasConnected && this.isConnected) { //Connecting for the first time\n connectionSucceeded.call(this, message);\n } else if (wasConnected && !this.isConnected) { //Only throw disconnected message fro the first disconnect, not once per try\n connectionBroken.call(this, message);\n }\n }.bind(this));\n\n cometd.addListener('/meta/disconnect', connectionBroken);\n\n cometd.addListener('/meta/handshake', function (message) {\n if (message.successful) {\n //http://docs.cometd.org/reference/javascript_subscribe.html#javascript_subscribe_meta_channels\n // ^ \"dynamic subscriptions are cleared (like any other subscription) and the application needs to figure out which dynamic subscription must be performed again\"\n cometd.batch(function () {\n $(me.currentSubscriptions).each(function (index, subs) {\n cometd.resubscribe(subs);\n });\n });\n }\n });\n\n //Other interesting events for reference\n cometd.addListener('/meta/subscribe', function (message) {\n $(me).trigger('subscribe', message);\n });\n cometd.addListener('/meta/unsubscribe', function (message) {\n $(me).trigger('unsubscribe', message);\n });\n cometd.addListener('/meta/publish', function (message) {\n $(me).trigger('publish', message);\n });\n cometd.addListener('/meta/unsuccessful', function (message) {\n $(me).trigger('error', message);\n });\n\n cometd.handshake(defaultCometOptions.handshake);\n\n this.cometd = cometd;\n};\n\n\nChannelManager.prototype = $.extend(ChannelManager.prototype, {\n\n /**\n * Creates and returns a channel, that is, an instance of a [Channel Service](../channel-service/).\n *\n * **Example**\n *\n * var cm = new F.manager.ChannelManager();\n * var channel = cm.getChannel();\n *\n * channel.subscribe('topic', callback);\n * channel.publish('topic', { myData: 100 });\n *\n * **Parameters**\n * @param {Object|String} `options` (Optional) If string, assumed to be the base channel url. If object, assumed to be configuration options for the constructor.\n */\n getChannel: function (options) {\n //If you just want to pass in a string\n if (options && !$.isPlainObject(options)) {\n options = {\n base: options\n };\n }\n var defaults = {\n transport: this.cometd\n };\n var channel = new Channel($.extend(true, {}, this.options.channel, defaults, options));\n\n\n //Wrap subs and unsubs so we can use it to re-attach handlers after being disconnected\n var subs = channel.subscribe;\n channel.subscribe = function () {\n var subid = subs.apply(channel, arguments);\n this.currentSubscriptions = this.currentSubscriptions.concat(subid);\n return subid;\n }.bind(this);\n\n\n var unsubs = channel.unsubscribe;\n channel.unsubscribe = function () {\n var removed = unsubs.apply(channel, arguments);\n for (var i = 0; i < this.currentSubscriptions.length; i++) {\n if (this.currentSubscriptions[i].id === removed.id) {\n this.currentSubscriptions.splice(i, 1);\n }\n }\n return removed;\n }.bind(this);\n\n return channel;\n },\n\n /**\n * Start listening for events on this instance. Signature is same as for jQuery Events: http://api.jquery.com/on/.\n *\n * Supported events are: `connect`, `disconnect`, `subscribe`, `unsubscribe`, `publish`, `error`.\n *\n * **Parameters**\n *\n * @param {string} `event` The event type. See more detail at jQuery Events: http://api.jquery.com/on/.\n */\n on: function (event) {\n $(this).on.apply($(this), arguments);\n },\n\n /**\n * Stop listening for events on this instance. Signature is same as for jQuery Events: http://api.jquery.com/off/.\n *\n * **Parameters**\n *\n * @param {string} `event` The event type. See more detail at jQuery Events: http://api.jquery.com/off/.\n */\n off: function (event) {\n $(this).off.apply($(this), arguments);\n },\n\n /**\n * Trigger events and execute handlers. Signature is same as for jQuery Events: http://api.jquery.com/trigger/.\n *\n * **Parameters**\n *\n * @param {string} `event` The event type. See more detail at jQuery Events: http://api.jquery.com/trigger/.\n */\n trigger: function (event) {\n $(this).trigger.apply($(this), arguments);\n }\n});\n\nmodule.exports = ChannelManager;\n","'use strict';\n\nmodule.exports = {\n EPI_SESSION_KEY: 'epicenterjs.session',\n STRATEGY_SESSION_KEY: 'epicenter-scenario'\n};","/*!\n * The buffer module from node.js, for the browser.\n *\n * @author Feross Aboukhadijeh \n * @license MIT\n */\n/* eslint-disable no-proto */\n\n'use strict'\n\nvar base64 = require('base64-js')\nvar ieee754 = require('ieee754')\nvar isArray = require('isarray')\n\nexports.Buffer = Buffer\nexports.SlowBuffer = SlowBuffer\nexports.INSPECT_MAX_BYTES = 50\n\n/**\n * If `Buffer.TYPED_ARRAY_SUPPORT`:\n * === true Use Uint8Array implementation (fastest)\n * === false Use Object implementation (most compatible, even IE6)\n *\n * Browsers that support typed arrays are IE 10+, Firefox 4+, Chrome 7+, Safari 5.1+,\n * Opera 11.6+, iOS 4.2+.\n *\n * Due to various browser bugs, sometimes the Object implementation will be used even\n * when the browser supports typed arrays.\n *\n * Note:\n *\n * - Firefox 4-29 lacks support for adding new properties to `Uint8Array` instances,\n * See: https://bugzilla.mozilla.org/show_bug.cgi?id=695438.\n *\n * - Chrome 9-10 is missing the `TypedArray.prototype.subarray` function.\n *\n * - IE10 has a broken `TypedArray.prototype.subarray` function which returns arrays of\n * incorrect length in some situations.\n\n * We detect these buggy browsers and set `Buffer.TYPED_ARRAY_SUPPORT` to `false` so they\n * get the Object implementation, which is slower but behaves correctly.\n */\nBuffer.TYPED_ARRAY_SUPPORT = global.TYPED_ARRAY_SUPPORT !== undefined\n ? global.TYPED_ARRAY_SUPPORT\n : typedArraySupport()\n\n/*\n * Export kMaxLength after typed array support is determined.\n */\nexports.kMaxLength = kMaxLength()\n\nfunction typedArraySupport () {\n try {\n var arr = new Uint8Array(1)\n arr.__proto__ = {__proto__: Uint8Array.prototype, foo: function () { return 42 }}\n return arr.foo() === 42 && // typed array instances can be augmented\n typeof arr.subarray === 'function' && // chrome 9-10 lack `subarray`\n arr.subarray(1, 1).byteLength === 0 // ie10 has broken `subarray`\n } catch (e) {\n return false\n }\n}\n\nfunction kMaxLength () {\n return Buffer.TYPED_ARRAY_SUPPORT\n ? 0x7fffffff\n : 0x3fffffff\n}\n\nfunction createBuffer (that, length) {\n if (kMaxLength() < length) {\n throw new RangeError('Invalid typed array length')\n }\n if (Buffer.TYPED_ARRAY_SUPPORT) {\n // Return an augmented `Uint8Array` instance, for best performance\n that = new Uint8Array(length)\n that.__proto__ = Buffer.prototype\n } else {\n // Fallback: Return an object instance of the Buffer class\n if (that === null) {\n that = new Buffer(length)\n }\n that.length = length\n }\n\n return that\n}\n\n/**\n * The Buffer constructor returns instances of `Uint8Array` that have their\n * prototype changed to `Buffer.prototype`. Furthermore, `Buffer` is a subclass of\n * `Uint8Array`, so the returned instances will have all the node `Buffer` methods\n * and the `Uint8Array` methods. Square bracket notation works as expected -- it\n * returns a single octet.\n *\n * The `Uint8Array` prototype remains unmodified.\n */\n\nfunction Buffer (arg, encodingOrOffset, length) {\n if (!Buffer.TYPED_ARRAY_SUPPORT && !(this instanceof Buffer)) {\n return new Buffer(arg, encodingOrOffset, length)\n }\n\n // Common case.\n if (typeof arg === 'number') {\n if (typeof encodingOrOffset === 'string') {\n throw new Error(\n 'If encoding is specified then the first argument must be a string'\n )\n }\n return allocUnsafe(this, arg)\n }\n return from(this, arg, encodingOrOffset, length)\n}\n\nBuffer.poolSize = 8192 // not used by this implementation\n\n// TODO: Legacy, not needed anymore. Remove in next major version.\nBuffer._augment = function (arr) {\n arr.__proto__ = Buffer.prototype\n return arr\n}\n\nfunction from (that, value, encodingOrOffset, length) {\n if (typeof value === 'number') {\n throw new TypeError('\"value\" argument must not be a number')\n }\n\n if (typeof ArrayBuffer !== 'undefined' && value instanceof ArrayBuffer) {\n return fromArrayBuffer(that, value, encodingOrOffset, length)\n }\n\n if (typeof value === 'string') {\n return fromString(that, value, encodingOrOffset)\n }\n\n return fromObject(that, value)\n}\n\n/**\n * Functionally equivalent to Buffer(arg, encoding) but throws a TypeError\n * if value is a number.\n * Buffer.from(str[, encoding])\n * Buffer.from(array)\n * Buffer.from(buffer)\n * Buffer.from(arrayBuffer[, byteOffset[, length]])\n **/\nBuffer.from = function (value, encodingOrOffset, length) {\n return from(null, value, encodingOrOffset, length)\n}\n\nif (Buffer.TYPED_ARRAY_SUPPORT) {\n Buffer.prototype.__proto__ = Uint8Array.prototype\n Buffer.__proto__ = Uint8Array\n if (typeof Symbol !== 'undefined' && Symbol.species &&\n Buffer[Symbol.species] === Buffer) {\n // Fix subarray() in ES2016. See: https://github.com/feross/buffer/pull/97\n Object.defineProperty(Buffer, Symbol.species, {\n value: null,\n configurable: true\n })\n }\n}\n\nfunction assertSize (size) {\n if (typeof size !== 'number') {\n throw new TypeError('\"size\" argument must be a number')\n }\n}\n\nfunction alloc (that, size, fill, encoding) {\n assertSize(size)\n if (size <= 0) {\n return createBuffer(that, size)\n }\n if (fill !== undefined) {\n // Only pay attention to encoding if it's a string. This\n // prevents accidentally sending in a number that would\n // be interpretted as a start offset.\n return typeof encoding === 'string'\n ? createBuffer(that, size).fill(fill, encoding)\n : createBuffer(that, size).fill(fill)\n }\n return createBuffer(that, size)\n}\n\n/**\n * Creates a new filled Buffer instance.\n * alloc(size[, fill[, encoding]])\n **/\nBuffer.alloc = function (size, fill, encoding) {\n return alloc(null, size, fill, encoding)\n}\n\nfunction allocUnsafe (that, size) {\n assertSize(size)\n that = createBuffer(that, size < 0 ? 0 : checked(size) | 0)\n if (!Buffer.TYPED_ARRAY_SUPPORT) {\n for (var i = 0; i < size; ++i) {\n that[i] = 0\n }\n }\n return that\n}\n\n/**\n * Equivalent to Buffer(num), by default creates a non-zero-filled Buffer instance.\n * */\nBuffer.allocUnsafe = function (size) {\n return allocUnsafe(null, size)\n}\n/**\n * Equivalent to SlowBuffer(num), by default creates a non-zero-filled Buffer instance.\n */\nBuffer.allocUnsafeSlow = function (size) {\n return allocUnsafe(null, size)\n}\n\nfunction fromString (that, string, encoding) {\n if (typeof encoding !== 'string' || encoding === '') {\n encoding = 'utf8'\n }\n\n if (!Buffer.isEncoding(encoding)) {\n throw new TypeError('\"encoding\" must be a valid string encoding')\n }\n\n var length = byteLength(string, encoding) | 0\n that = createBuffer(that, length)\n\n that.write(string, encoding)\n return that\n}\n\nfunction fromArrayLike (that, array) {\n var length = checked(array.length) | 0\n that = createBuffer(that, length)\n for (var i = 0; i < length; i += 1) {\n that[i] = array[i] & 255\n }\n return that\n}\n\nfunction fromArrayBuffer (that, array, byteOffset, length) {\n array.byteLength // this throws if `array` is not a valid ArrayBuffer\n\n if (byteOffset < 0 || array.byteLength < byteOffset) {\n throw new RangeError('\\'offset\\' is out of bounds')\n }\n\n if (array.byteLength < byteOffset + (length || 0)) {\n throw new RangeError('\\'length\\' is out of bounds')\n }\n\n if (byteOffset === undefined && length === undefined) {\n array = new Uint8Array(array)\n } else if (length === undefined) {\n array = new Uint8Array(array, byteOffset)\n } else {\n array = new Uint8Array(array, byteOffset, length)\n }\n\n if (Buffer.TYPED_ARRAY_SUPPORT) {\n // Return an augmented `Uint8Array` instance, for best performance\n that = array\n that.__proto__ = Buffer.prototype\n } else {\n // Fallback: Return an object instance of the Buffer class\n that = fromArrayLike(that, array)\n }\n return that\n}\n\nfunction fromObject (that, obj) {\n if (Buffer.isBuffer(obj)) {\n var len = checked(obj.length) | 0\n that = createBuffer(that, len)\n\n if (that.length === 0) {\n return that\n }\n\n obj.copy(that, 0, 0, len)\n return that\n }\n\n if (obj) {\n if ((typeof ArrayBuffer !== 'undefined' &&\n obj.buffer instanceof ArrayBuffer) || 'length' in obj) {\n if (typeof obj.length !== 'number' || isnan(obj.length)) {\n return createBuffer(that, 0)\n }\n return fromArrayLike(that, obj)\n }\n\n if (obj.type === 'Buffer' && isArray(obj.data)) {\n return fromArrayLike(that, obj.data)\n }\n }\n\n throw new TypeError('First argument must be a string, Buffer, ArrayBuffer, Array, or array-like object.')\n}\n\nfunction checked (length) {\n // Note: cannot use `length < kMaxLength` here because that fails when\n // length is NaN (which is otherwise coerced to zero.)\n if (length >= kMaxLength()) {\n throw new RangeError('Attempt to allocate Buffer larger than maximum ' +\n 'size: 0x' + kMaxLength().toString(16) + ' bytes')\n }\n return length | 0\n}\n\nfunction SlowBuffer (length) {\n if (+length != length) { // eslint-disable-line eqeqeq\n length = 0\n }\n return Buffer.alloc(+length)\n}\n\nBuffer.isBuffer = function isBuffer (b) {\n return !!(b != null && b._isBuffer)\n}\n\nBuffer.compare = function compare (a, b) {\n if (!Buffer.isBuffer(a) || !Buffer.isBuffer(b)) {\n throw new TypeError('Arguments must be Buffers')\n }\n\n if (a === b) return 0\n\n var x = a.length\n var y = b.length\n\n for (var i = 0, len = Math.min(x, y); i < len; ++i) {\n if (a[i] !== b[i]) {\n x = a[i]\n y = b[i]\n break\n }\n }\n\n if (x < y) return -1\n if (y < x) return 1\n return 0\n}\n\nBuffer.isEncoding = function isEncoding (encoding) {\n switch (String(encoding).toLowerCase()) {\n case 'hex':\n case 'utf8':\n case 'utf-8':\n case 'ascii':\n case 'binary':\n case 'base64':\n case 'raw':\n case 'ucs2':\n case 'ucs-2':\n case 'utf16le':\n case 'utf-16le':\n return true\n default:\n return false\n }\n}\n\nBuffer.concat = function concat (list, length) {\n if (!isArray(list)) {\n throw new TypeError('\"list\" argument must be an Array of Buffers')\n }\n\n if (list.length === 0) {\n return Buffer.alloc(0)\n }\n\n var i\n if (length === undefined) {\n length = 0\n for (i = 0; i < list.length; ++i) {\n length += list[i].length\n }\n }\n\n var buffer = Buffer.allocUnsafe(length)\n var pos = 0\n for (i = 0; i < list.length; ++i) {\n var buf = list[i]\n if (!Buffer.isBuffer(buf)) {\n throw new TypeError('\"list\" argument must be an Array of Buffers')\n }\n buf.copy(buffer, pos)\n pos += buf.length\n }\n return buffer\n}\n\nfunction byteLength (string, encoding) {\n if (Buffer.isBuffer(string)) {\n return string.length\n }\n if (typeof ArrayBuffer !== 'undefined' && typeof ArrayBuffer.isView === 'function' &&\n (ArrayBuffer.isView(string) || string instanceof ArrayBuffer)) {\n return string.byteLength\n }\n if (typeof string !== 'string') {\n string = '' + string\n }\n\n var len = string.length\n if (len === 0) return 0\n\n // Use a for loop to avoid recursion\n var loweredCase = false\n for (;;) {\n switch (encoding) {\n case 'ascii':\n case 'binary':\n case 'raw':\n case 'raws':\n return len\n case 'utf8':\n case 'utf-8':\n case undefined:\n return utf8ToBytes(string).length\n case 'ucs2':\n case 'ucs-2':\n case 'utf16le':\n case 'utf-16le':\n return len * 2\n case 'hex':\n return len >>> 1\n case 'base64':\n return base64ToBytes(string).length\n default:\n if (loweredCase) return utf8ToBytes(string).length // assume utf8\n encoding = ('' + encoding).toLowerCase()\n loweredCase = true\n }\n }\n}\nBuffer.byteLength = byteLength\n\nfunction slowToString (encoding, start, end) {\n var loweredCase = false\n\n // No need to verify that \"this.length <= MAX_UINT32\" since it's a read-only\n // property of a typed array.\n\n // This behaves neither like String nor Uint8Array in that we set start/end\n // to their upper/lower bounds if the value passed is out of range.\n // undefined is handled specially as per ECMA-262 6th Edition,\n // Section 13.3.3.7 Runtime Semantics: KeyedBindingInitialization.\n if (start === undefined || start < 0) {\n start = 0\n }\n // Return early if start > this.length. Done here to prevent potential uint32\n // coercion fail below.\n if (start > this.length) {\n return ''\n }\n\n if (end === undefined || end > this.length) {\n end = this.length\n }\n\n if (end <= 0) {\n return ''\n }\n\n // Force coersion to uint32. This will also coerce falsey/NaN values to 0.\n end >>>= 0\n start >>>= 0\n\n if (end <= start) {\n return ''\n }\n\n if (!encoding) encoding = 'utf8'\n\n while (true) {\n switch (encoding) {\n case 'hex':\n return hexSlice(this, start, end)\n\n case 'utf8':\n case 'utf-8':\n return utf8Slice(this, start, end)\n\n case 'ascii':\n return asciiSlice(this, start, end)\n\n case 'binary':\n return binarySlice(this, start, end)\n\n case 'base64':\n return base64Slice(this, start, end)\n\n case 'ucs2':\n case 'ucs-2':\n case 'utf16le':\n case 'utf-16le':\n return utf16leSlice(this, start, end)\n\n default:\n if (loweredCase) throw new TypeError('Unknown encoding: ' + encoding)\n encoding = (encoding + '').toLowerCase()\n loweredCase = true\n }\n }\n}\n\n// The property is used by `Buffer.isBuffer` and `is-buffer` (in Safari 5-7) to detect\n// Buffer instances.\nBuffer.prototype._isBuffer = true\n\nfunction swap (b, n, m) {\n var i = b[n]\n b[n] = b[m]\n b[m] = i\n}\n\nBuffer.prototype.swap16 = function swap16 () {\n var len = this.length\n if (len % 2 !== 0) {\n throw new RangeError('Buffer size must be a multiple of 16-bits')\n }\n for (var i = 0; i < len; i += 2) {\n swap(this, i, i + 1)\n }\n return this\n}\n\nBuffer.prototype.swap32 = function swap32 () {\n var len = this.length\n if (len % 4 !== 0) {\n throw new RangeError('Buffer size must be a multiple of 32-bits')\n }\n for (var i = 0; i < len; i += 4) {\n swap(this, i, i + 3)\n swap(this, i + 1, i + 2)\n }\n return this\n}\n\nBuffer.prototype.toString = function toString () {\n var length = this.length | 0\n if (length === 0) return ''\n if (arguments.length === 0) return utf8Slice(this, 0, length)\n return slowToString.apply(this, arguments)\n}\n\nBuffer.prototype.equals = function equals (b) {\n if (!Buffer.isBuffer(b)) throw new TypeError('Argument must be a Buffer')\n if (this === b) return true\n return Buffer.compare(this, b) === 0\n}\n\nBuffer.prototype.inspect = function inspect () {\n var str = ''\n var max = exports.INSPECT_MAX_BYTES\n if (this.length > 0) {\n str = this.toString('hex', 0, max).match(/.{2}/g).join(' ')\n if (this.length > max) str += ' ... '\n }\n return ''\n}\n\nBuffer.prototype.compare = function compare (target, start, end, thisStart, thisEnd) {\n if (!Buffer.isBuffer(target)) {\n throw new TypeError('Argument must be a Buffer')\n }\n\n if (start === undefined) {\n start = 0\n }\n if (end === undefined) {\n end = target ? target.length : 0\n }\n if (thisStart === undefined) {\n thisStart = 0\n }\n if (thisEnd === undefined) {\n thisEnd = this.length\n }\n\n if (start < 0 || end > target.length || thisStart < 0 || thisEnd > this.length) {\n throw new RangeError('out of range index')\n }\n\n if (thisStart >= thisEnd && start >= end) {\n return 0\n }\n if (thisStart >= thisEnd) {\n return -1\n }\n if (start >= end) {\n return 1\n }\n\n start >>>= 0\n end >>>= 0\n thisStart >>>= 0\n thisEnd >>>= 0\n\n if (this === target) return 0\n\n var x = thisEnd - thisStart\n var y = end - start\n var len = Math.min(x, y)\n\n var thisCopy = this.slice(thisStart, thisEnd)\n var targetCopy = target.slice(start, end)\n\n for (var i = 0; i < len; ++i) {\n if (thisCopy[i] !== targetCopy[i]) {\n x = thisCopy[i]\n y = targetCopy[i]\n break\n }\n }\n\n if (x < y) return -1\n if (y < x) return 1\n return 0\n}\n\nfunction arrayIndexOf (arr, val, byteOffset, encoding) {\n var indexSize = 1\n var arrLength = arr.length\n var valLength = val.length\n\n if (encoding !== undefined) {\n encoding = String(encoding).toLowerCase()\n if (encoding === 'ucs2' || encoding === 'ucs-2' ||\n encoding === 'utf16le' || encoding === 'utf-16le') {\n if (arr.length < 2 || val.length < 2) {\n return -1\n }\n indexSize = 2\n arrLength /= 2\n valLength /= 2\n byteOffset /= 2\n }\n }\n\n function read (buf, i) {\n if (indexSize === 1) {\n return buf[i]\n } else {\n return buf.readUInt16BE(i * indexSize)\n }\n }\n\n var foundIndex = -1\n for (var i = byteOffset; i < arrLength; ++i) {\n if (read(arr, i) === read(val, foundIndex === -1 ? 0 : i - foundIndex)) {\n if (foundIndex === -1) foundIndex = i\n if (i - foundIndex + 1 === valLength) return foundIndex * indexSize\n } else {\n if (foundIndex !== -1) i -= i - foundIndex\n foundIndex = -1\n }\n }\n\n return -1\n}\n\nBuffer.prototype.indexOf = function indexOf (val, byteOffset, encoding) {\n if (typeof byteOffset === 'string') {\n encoding = byteOffset\n byteOffset = 0\n } else if (byteOffset > 0x7fffffff) {\n byteOffset = 0x7fffffff\n } else if (byteOffset < -0x80000000) {\n byteOffset = -0x80000000\n }\n byteOffset >>= 0\n\n if (this.length === 0) return -1\n if (byteOffset >= this.length) return -1\n\n // Negative offsets start from the end of the buffer\n if (byteOffset < 0) byteOffset = Math.max(this.length + byteOffset, 0)\n\n if (typeof val === 'string') {\n val = Buffer.from(val, encoding)\n }\n\n if (Buffer.isBuffer(val)) {\n // special case: looking for empty string/buffer always fails\n if (val.length === 0) {\n return -1\n }\n return arrayIndexOf(this, val, byteOffset, encoding)\n }\n if (typeof val === 'number') {\n if (Buffer.TYPED_ARRAY_SUPPORT && Uint8Array.prototype.indexOf === 'function') {\n return Uint8Array.prototype.indexOf.call(this, val, byteOffset)\n }\n return arrayIndexOf(this, [ val ], byteOffset, encoding)\n }\n\n throw new TypeError('val must be string, number or Buffer')\n}\n\nBuffer.prototype.includes = function includes (val, byteOffset, encoding) {\n return this.indexOf(val, byteOffset, encoding) !== -1\n}\n\nfunction hexWrite (buf, string, offset, length) {\n offset = Number(offset) || 0\n var remaining = buf.length - offset\n if (!length) {\n length = remaining\n } else {\n length = Number(length)\n if (length > remaining) {\n length = remaining\n }\n }\n\n // must be an even number of digits\n var strLen = string.length\n if (strLen % 2 !== 0) throw new Error('Invalid hex string')\n\n if (length > strLen / 2) {\n length = strLen / 2\n }\n for (var i = 0; i < length; ++i) {\n var parsed = parseInt(string.substr(i * 2, 2), 16)\n if (isNaN(parsed)) return i\n buf[offset + i] = parsed\n }\n return i\n}\n\nfunction utf8Write (buf, string, offset, length) {\n return blitBuffer(utf8ToBytes(string, buf.length - offset), buf, offset, length)\n}\n\nfunction asciiWrite (buf, string, offset, length) {\n return blitBuffer(asciiToBytes(string), buf, offset, length)\n}\n\nfunction binaryWrite (buf, string, offset, length) {\n return asciiWrite(buf, string, offset, length)\n}\n\nfunction base64Write (buf, string, offset, length) {\n return blitBuffer(base64ToBytes(string), buf, offset, length)\n}\n\nfunction ucs2Write (buf, string, offset, length) {\n return blitBuffer(utf16leToBytes(string, buf.length - offset), buf, offset, length)\n}\n\nBuffer.prototype.write = function write (string, offset, length, encoding) {\n // Buffer#write(string)\n if (offset === undefined) {\n encoding = 'utf8'\n length = this.length\n offset = 0\n // Buffer#write(string, encoding)\n } else if (length === undefined && typeof offset === 'string') {\n encoding = offset\n length = this.length\n offset = 0\n // Buffer#write(string, offset[, length][, encoding])\n } else if (isFinite(offset)) {\n offset = offset | 0\n if (isFinite(length)) {\n length = length | 0\n if (encoding === undefined) encoding = 'utf8'\n } else {\n encoding = length\n length = undefined\n }\n // legacy write(string, encoding, offset, length) - remove in v0.13\n } else {\n throw new Error(\n 'Buffer.write(string, encoding, offset[, length]) is no longer supported'\n )\n }\n\n var remaining = this.length - offset\n if (length === undefined || length > remaining) length = remaining\n\n if ((string.length > 0 && (length < 0 || offset < 0)) || offset > this.length) {\n throw new RangeError('Attempt to write outside buffer bounds')\n }\n\n if (!encoding) encoding = 'utf8'\n\n var loweredCase = false\n for (;;) {\n switch (encoding) {\n case 'hex':\n return hexWrite(this, string, offset, length)\n\n case 'utf8':\n case 'utf-8':\n return utf8Write(this, string, offset, length)\n\n case 'ascii':\n return asciiWrite(this, string, offset, length)\n\n case 'binary':\n return binaryWrite(this, string, offset, length)\n\n case 'base64':\n // Warning: maxLength not taken into account in base64Write\n return base64Write(this, string, offset, length)\n\n case 'ucs2':\n case 'ucs-2':\n case 'utf16le':\n case 'utf-16le':\n return ucs2Write(this, string, offset, length)\n\n default:\n if (loweredCase) throw new TypeError('Unknown encoding: ' + encoding)\n encoding = ('' + encoding).toLowerCase()\n loweredCase = true\n }\n }\n}\n\nBuffer.prototype.toJSON = function toJSON () {\n return {\n type: 'Buffer',\n data: Array.prototype.slice.call(this._arr || this, 0)\n }\n}\n\nfunction base64Slice (buf, start, end) {\n if (start === 0 && end === buf.length) {\n return base64.fromByteArray(buf)\n } else {\n return base64.fromByteArray(buf.slice(start, end))\n }\n}\n\nfunction utf8Slice (buf, start, end) {\n end = Math.min(buf.length, end)\n var res = []\n\n var i = start\n while (i < end) {\n var firstByte = buf[i]\n var codePoint = null\n var bytesPerSequence = (firstByte > 0xEF) ? 4\n : (firstByte > 0xDF) ? 3\n : (firstByte > 0xBF) ? 2\n : 1\n\n if (i + bytesPerSequence <= end) {\n var secondByte, thirdByte, fourthByte, tempCodePoint\n\n switch (bytesPerSequence) {\n case 1:\n if (firstByte < 0x80) {\n codePoint = firstByte\n }\n break\n case 2:\n secondByte = buf[i + 1]\n if ((secondByte & 0xC0) === 0x80) {\n tempCodePoint = (firstByte & 0x1F) << 0x6 | (secondByte & 0x3F)\n if (tempCodePoint > 0x7F) {\n codePoint = tempCodePoint\n }\n }\n break\n case 3:\n secondByte = buf[i + 1]\n thirdByte = buf[i + 2]\n if ((secondByte & 0xC0) === 0x80 && (thirdByte & 0xC0) === 0x80) {\n tempCodePoint = (firstByte & 0xF) << 0xC | (secondByte & 0x3F) << 0x6 | (thirdByte & 0x3F)\n if (tempCodePoint > 0x7FF && (tempCodePoint < 0xD800 || tempCodePoint > 0xDFFF)) {\n codePoint = tempCodePoint\n }\n }\n break\n case 4:\n secondByte = buf[i + 1]\n thirdByte = buf[i + 2]\n fourthByte = buf[i + 3]\n if ((secondByte & 0xC0) === 0x80 && (thirdByte & 0xC0) === 0x80 && (fourthByte & 0xC0) === 0x80) {\n tempCodePoint = (firstByte & 0xF) << 0x12 | (secondByte & 0x3F) << 0xC | (thirdByte & 0x3F) << 0x6 | (fourthByte & 0x3F)\n if (tempCodePoint > 0xFFFF && tempCodePoint < 0x110000) {\n codePoint = tempCodePoint\n }\n }\n }\n }\n\n if (codePoint === null) {\n // we did not generate a valid codePoint so insert a\n // replacement char (U+FFFD) and advance only 1 byte\n codePoint = 0xFFFD\n bytesPerSequence = 1\n } else if (codePoint > 0xFFFF) {\n // encode to utf16 (surrogate pair dance)\n codePoint -= 0x10000\n res.push(codePoint >>> 10 & 0x3FF | 0xD800)\n codePoint = 0xDC00 | codePoint & 0x3FF\n }\n\n res.push(codePoint)\n i += bytesPerSequence\n }\n\n return decodeCodePointsArray(res)\n}\n\n// Based on http://stackoverflow.com/a/22747272/680742, the browser with\n// the lowest limit is Chrome, with 0x10000 args.\n// We go 1 magnitude less, for safety\nvar MAX_ARGUMENTS_LENGTH = 0x1000\n\nfunction decodeCodePointsArray (codePoints) {\n var len = codePoints.length\n if (len <= MAX_ARGUMENTS_LENGTH) {\n return String.fromCharCode.apply(String, codePoints) // avoid extra slice()\n }\n\n // Decode in chunks to avoid \"call stack size exceeded\".\n var res = ''\n var i = 0\n while (i < len) {\n res += String.fromCharCode.apply(\n String,\n codePoints.slice(i, i += MAX_ARGUMENTS_LENGTH)\n )\n }\n return res\n}\n\nfunction asciiSlice (buf, start, end) {\n var ret = ''\n end = Math.min(buf.length, end)\n\n for (var i = start; i < end; ++i) {\n ret += String.fromCharCode(buf[i] & 0x7F)\n }\n return ret\n}\n\nfunction binarySlice (buf, start, end) {\n var ret = ''\n end = Math.min(buf.length, end)\n\n for (var i = start; i < end; ++i) {\n ret += String.fromCharCode(buf[i])\n }\n return ret\n}\n\nfunction hexSlice (buf, start, end) {\n var len = buf.length\n\n if (!start || start < 0) start = 0\n if (!end || end < 0 || end > len) end = len\n\n var out = ''\n for (var i = start; i < end; ++i) {\n out += toHex(buf[i])\n }\n return out\n}\n\nfunction utf16leSlice (buf, start, end) {\n var bytes = buf.slice(start, end)\n var res = ''\n for (var i = 0; i < bytes.length; i += 2) {\n res += String.fromCharCode(bytes[i] + bytes[i + 1] * 256)\n }\n return res\n}\n\nBuffer.prototype.slice = function slice (start, end) {\n var len = this.length\n start = ~~start\n end = end === undefined ? len : ~~end\n\n if (start < 0) {\n start += len\n if (start < 0) start = 0\n } else if (start > len) {\n start = len\n }\n\n if (end < 0) {\n end += len\n if (end < 0) end = 0\n } else if (end > len) {\n end = len\n }\n\n if (end < start) end = start\n\n var newBuf\n if (Buffer.TYPED_ARRAY_SUPPORT) {\n newBuf = this.subarray(start, end)\n newBuf.__proto__ = Buffer.prototype\n } else {\n var sliceLen = end - start\n newBuf = new Buffer(sliceLen, undefined)\n for (var i = 0; i < sliceLen; ++i) {\n newBuf[i] = this[i + start]\n }\n }\n\n return newBuf\n}\n\n/*\n * Need to make sure that buffer isn't trying to write out of bounds.\n */\nfunction checkOffset (offset, ext, length) {\n if ((offset % 1) !== 0 || offset < 0) throw new RangeError('offset is not uint')\n if (offset + ext > length) throw new RangeError('Trying to access beyond buffer length')\n}\n\nBuffer.prototype.readUIntLE = function readUIntLE (offset, byteLength, noAssert) {\n offset = offset | 0\n byteLength = byteLength | 0\n if (!noAssert) checkOffset(offset, byteLength, this.length)\n\n var val = this[offset]\n var mul = 1\n var i = 0\n while (++i < byteLength && (mul *= 0x100)) {\n val += this[offset + i] * mul\n }\n\n return val\n}\n\nBuffer.prototype.readUIntBE = function readUIntBE (offset, byteLength, noAssert) {\n offset = offset | 0\n byteLength = byteLength | 0\n if (!noAssert) {\n checkOffset(offset, byteLength, this.length)\n }\n\n var val = this[offset + --byteLength]\n var mul = 1\n while (byteLength > 0 && (mul *= 0x100)) {\n val += this[offset + --byteLength] * mul\n }\n\n return val\n}\n\nBuffer.prototype.readUInt8 = function readUInt8 (offset, noAssert) {\n if (!noAssert) checkOffset(offset, 1, this.length)\n return this[offset]\n}\n\nBuffer.prototype.readUInt16LE = function readUInt16LE (offset, noAssert) {\n if (!noAssert) checkOffset(offset, 2, this.length)\n return this[offset] | (this[offset + 1] << 8)\n}\n\nBuffer.prototype.readUInt16BE = function readUInt16BE (offset, noAssert) {\n if (!noAssert) checkOffset(offset, 2, this.length)\n return (this[offset] << 8) | this[offset + 1]\n}\n\nBuffer.prototype.readUInt32LE = function readUInt32LE (offset, noAssert) {\n if (!noAssert) checkOffset(offset, 4, this.length)\n\n return ((this[offset]) |\n (this[offset + 1] << 8) |\n (this[offset + 2] << 16)) +\n (this[offset + 3] * 0x1000000)\n}\n\nBuffer.prototype.readUInt32BE = function readUInt32BE (offset, noAssert) {\n if (!noAssert) checkOffset(offset, 4, this.length)\n\n return (this[offset] * 0x1000000) +\n ((this[offset + 1] << 16) |\n (this[offset + 2] << 8) |\n this[offset + 3])\n}\n\nBuffer.prototype.readIntLE = function readIntLE (offset, byteLength, noAssert) {\n offset = offset | 0\n byteLength = byteLength | 0\n if (!noAssert) checkOffset(offset, byteLength, this.length)\n\n var val = this[offset]\n var mul = 1\n var i = 0\n while (++i < byteLength && (mul *= 0x100)) {\n val += this[offset + i] * mul\n }\n mul *= 0x80\n\n if (val >= mul) val -= Math.pow(2, 8 * byteLength)\n\n return val\n}\n\nBuffer.prototype.readIntBE = function readIntBE (offset, byteLength, noAssert) {\n offset = offset | 0\n byteLength = byteLength | 0\n if (!noAssert) checkOffset(offset, byteLength, this.length)\n\n var i = byteLength\n var mul = 1\n var val = this[offset + --i]\n while (i > 0 && (mul *= 0x100)) {\n val += this[offset + --i] * mul\n }\n mul *= 0x80\n\n if (val >= mul) val -= Math.pow(2, 8 * byteLength)\n\n return val\n}\n\nBuffer.prototype.readInt8 = function readInt8 (offset, noAssert) {\n if (!noAssert) checkOffset(offset, 1, this.length)\n if (!(this[offset] & 0x80)) return (this[offset])\n return ((0xff - this[offset] + 1) * -1)\n}\n\nBuffer.prototype.readInt16LE = function readInt16LE (offset, noAssert) {\n if (!noAssert) checkOffset(offset, 2, this.length)\n var val = this[offset] | (this[offset + 1] << 8)\n return (val & 0x8000) ? val | 0xFFFF0000 : val\n}\n\nBuffer.prototype.readInt16BE = function readInt16BE (offset, noAssert) {\n if (!noAssert) checkOffset(offset, 2, this.length)\n var val = this[offset + 1] | (this[offset] << 8)\n return (val & 0x8000) ? val | 0xFFFF0000 : val\n}\n\nBuffer.prototype.readInt32LE = function readInt32LE (offset, noAssert) {\n if (!noAssert) checkOffset(offset, 4, this.length)\n\n return (this[offset]) |\n (this[offset + 1] << 8) |\n (this[offset + 2] << 16) |\n (this[offset + 3] << 24)\n}\n\nBuffer.prototype.readInt32BE = function readInt32BE (offset, noAssert) {\n if (!noAssert) checkOffset(offset, 4, this.length)\n\n return (this[offset] << 24) |\n (this[offset + 1] << 16) |\n (this[offset + 2] << 8) |\n (this[offset + 3])\n}\n\nBuffer.prototype.readFloatLE = function readFloatLE (offset, noAssert) {\n if (!noAssert) checkOffset(offset, 4, this.length)\n return ieee754.read(this, offset, true, 23, 4)\n}\n\nBuffer.prototype.readFloatBE = function readFloatBE (offset, noAssert) {\n if (!noAssert) checkOffset(offset, 4, this.length)\n return ieee754.read(this, offset, false, 23, 4)\n}\n\nBuffer.prototype.readDoubleLE = function readDoubleLE (offset, noAssert) {\n if (!noAssert) checkOffset(offset, 8, this.length)\n return ieee754.read(this, offset, true, 52, 8)\n}\n\nBuffer.prototype.readDoubleBE = function readDoubleBE (offset, noAssert) {\n if (!noAssert) checkOffset(offset, 8, this.length)\n return ieee754.read(this, offset, false, 52, 8)\n}\n\nfunction checkInt (buf, value, offset, ext, max, min) {\n if (!Buffer.isBuffer(buf)) throw new TypeError('\"buffer\" argument must be a Buffer instance')\n if (value > max || value < min) throw new RangeError('\"value\" argument is out of bounds')\n if (offset + ext > buf.length) throw new RangeError('Index out of range')\n}\n\nBuffer.prototype.writeUIntLE = function writeUIntLE (value, offset, byteLength, noAssert) {\n value = +value\n offset = offset | 0\n byteLength = byteLength | 0\n if (!noAssert) {\n var maxBytes = Math.pow(2, 8 * byteLength) - 1\n checkInt(this, value, offset, byteLength, maxBytes, 0)\n }\n\n var mul = 1\n var i = 0\n this[offset] = value & 0xFF\n while (++i < byteLength && (mul *= 0x100)) {\n this[offset + i] = (value / mul) & 0xFF\n }\n\n return offset + byteLength\n}\n\nBuffer.prototype.writeUIntBE = function writeUIntBE (value, offset, byteLength, noAssert) {\n value = +value\n offset = offset | 0\n byteLength = byteLength | 0\n if (!noAssert) {\n var maxBytes = Math.pow(2, 8 * byteLength) - 1\n checkInt(this, value, offset, byteLength, maxBytes, 0)\n }\n\n var i = byteLength - 1\n var mul = 1\n this[offset + i] = value & 0xFF\n while (--i >= 0 && (mul *= 0x100)) {\n this[offset + i] = (value / mul) & 0xFF\n }\n\n return offset + byteLength\n}\n\nBuffer.prototype.writeUInt8 = function writeUInt8 (value, offset, noAssert) {\n value = +value\n offset = offset | 0\n if (!noAssert) checkInt(this, value, offset, 1, 0xff, 0)\n if (!Buffer.TYPED_ARRAY_SUPPORT) value = Math.floor(value)\n this[offset] = (value & 0xff)\n return offset + 1\n}\n\nfunction objectWriteUInt16 (buf, value, offset, littleEndian) {\n if (value < 0) value = 0xffff + value + 1\n for (var i = 0, j = Math.min(buf.length - offset, 2); i < j; ++i) {\n buf[offset + i] = (value & (0xff << (8 * (littleEndian ? i : 1 - i)))) >>>\n (littleEndian ? i : 1 - i) * 8\n }\n}\n\nBuffer.prototype.writeUInt16LE = function writeUInt16LE (value, offset, noAssert) {\n value = +value\n offset = offset | 0\n if (!noAssert) checkInt(this, value, offset, 2, 0xffff, 0)\n if (Buffer.TYPED_ARRAY_SUPPORT) {\n this[offset] = (value & 0xff)\n this[offset + 1] = (value >>> 8)\n } else {\n objectWriteUInt16(this, value, offset, true)\n }\n return offset + 2\n}\n\nBuffer.prototype.writeUInt16BE = function writeUInt16BE (value, offset, noAssert) {\n value = +value\n offset = offset | 0\n if (!noAssert) checkInt(this, value, offset, 2, 0xffff, 0)\n if (Buffer.TYPED_ARRAY_SUPPORT) {\n this[offset] = (value >>> 8)\n this[offset + 1] = (value & 0xff)\n } else {\n objectWriteUInt16(this, value, offset, false)\n }\n return offset + 2\n}\n\nfunction objectWriteUInt32 (buf, value, offset, littleEndian) {\n if (value < 0) value = 0xffffffff + value + 1\n for (var i = 0, j = Math.min(buf.length - offset, 4); i < j; ++i) {\n buf[offset + i] = (value >>> (littleEndian ? i : 3 - i) * 8) & 0xff\n }\n}\n\nBuffer.prototype.writeUInt32LE = function writeUInt32LE (value, offset, noAssert) {\n value = +value\n offset = offset | 0\n if (!noAssert) checkInt(this, value, offset, 4, 0xffffffff, 0)\n if (Buffer.TYPED_ARRAY_SUPPORT) {\n this[offset + 3] = (value >>> 24)\n this[offset + 2] = (value >>> 16)\n this[offset + 1] = (value >>> 8)\n this[offset] = (value & 0xff)\n } else {\n objectWriteUInt32(this, value, offset, true)\n }\n return offset + 4\n}\n\nBuffer.prototype.writeUInt32BE = function writeUInt32BE (value, offset, noAssert) {\n value = +value\n offset = offset | 0\n if (!noAssert) checkInt(this, value, offset, 4, 0xffffffff, 0)\n if (Buffer.TYPED_ARRAY_SUPPORT) {\n this[offset] = (value >>> 24)\n this[offset + 1] = (value >>> 16)\n this[offset + 2] = (value >>> 8)\n this[offset + 3] = (value & 0xff)\n } else {\n objectWriteUInt32(this, value, offset, false)\n }\n return offset + 4\n}\n\nBuffer.prototype.writeIntLE = function writeIntLE (value, offset, byteLength, noAssert) {\n value = +value\n offset = offset | 0\n if (!noAssert) {\n var limit = Math.pow(2, 8 * byteLength - 1)\n\n checkInt(this, value, offset, byteLength, limit - 1, -limit)\n }\n\n var i = 0\n var mul = 1\n var sub = 0\n this[offset] = value & 0xFF\n while (++i < byteLength && (mul *= 0x100)) {\n if (value < 0 && sub === 0 && this[offset + i - 1] !== 0) {\n sub = 1\n }\n this[offset + i] = ((value / mul) >> 0) - sub & 0xFF\n }\n\n return offset + byteLength\n}\n\nBuffer.prototype.writeIntBE = function writeIntBE (value, offset, byteLength, noAssert) {\n value = +value\n offset = offset | 0\n if (!noAssert) {\n var limit = Math.pow(2, 8 * byteLength - 1)\n\n checkInt(this, value, offset, byteLength, limit - 1, -limit)\n }\n\n var i = byteLength - 1\n var mul = 1\n var sub = 0\n this[offset + i] = value & 0xFF\n while (--i >= 0 && (mul *= 0x100)) {\n if (value < 0 && sub === 0 && this[offset + i + 1] !== 0) {\n sub = 1\n }\n this[offset + i] = ((value / mul) >> 0) - sub & 0xFF\n }\n\n return offset + byteLength\n}\n\nBuffer.prototype.writeInt8 = function writeInt8 (value, offset, noAssert) {\n value = +value\n offset = offset | 0\n if (!noAssert) checkInt(this, value, offset, 1, 0x7f, -0x80)\n if (!Buffer.TYPED_ARRAY_SUPPORT) value = Math.floor(value)\n if (value < 0) value = 0xff + value + 1\n this[offset] = (value & 0xff)\n return offset + 1\n}\n\nBuffer.prototype.writeInt16LE = function writeInt16LE (value, offset, noAssert) {\n value = +value\n offset = offset | 0\n if (!noAssert) checkInt(this, value, offset, 2, 0x7fff, -0x8000)\n if (Buffer.TYPED_ARRAY_SUPPORT) {\n this[offset] = (value & 0xff)\n this[offset + 1] = (value >>> 8)\n } else {\n objectWriteUInt16(this, value, offset, true)\n }\n return offset + 2\n}\n\nBuffer.prototype.writeInt16BE = function writeInt16BE (value, offset, noAssert) {\n value = +value\n offset = offset | 0\n if (!noAssert) checkInt(this, value, offset, 2, 0x7fff, -0x8000)\n if (Buffer.TYPED_ARRAY_SUPPORT) {\n this[offset] = (value >>> 8)\n this[offset + 1] = (value & 0xff)\n } else {\n objectWriteUInt16(this, value, offset, false)\n }\n return offset + 2\n}\n\nBuffer.prototype.writeInt32LE = function writeInt32LE (value, offset, noAssert) {\n value = +value\n offset = offset | 0\n if (!noAssert) checkInt(this, value, offset, 4, 0x7fffffff, -0x80000000)\n if (Buffer.TYPED_ARRAY_SUPPORT) {\n this[offset] = (value & 0xff)\n this[offset + 1] = (value >>> 8)\n this[offset + 2] = (value >>> 16)\n this[offset + 3] = (value >>> 24)\n } else {\n objectWriteUInt32(this, value, offset, true)\n }\n return offset + 4\n}\n\nBuffer.prototype.writeInt32BE = function writeInt32BE (value, offset, noAssert) {\n value = +value\n offset = offset | 0\n if (!noAssert) checkInt(this, value, offset, 4, 0x7fffffff, -0x80000000)\n if (value < 0) value = 0xffffffff + value + 1\n if (Buffer.TYPED_ARRAY_SUPPORT) {\n this[offset] = (value >>> 24)\n this[offset + 1] = (value >>> 16)\n this[offset + 2] = (value >>> 8)\n this[offset + 3] = (value & 0xff)\n } else {\n objectWriteUInt32(this, value, offset, false)\n }\n return offset + 4\n}\n\nfunction checkIEEE754 (buf, value, offset, ext, max, min) {\n if (offset + ext > buf.length) throw new RangeError('Index out of range')\n if (offset < 0) throw new RangeError('Index out of range')\n}\n\nfunction writeFloat (buf, value, offset, littleEndian, noAssert) {\n if (!noAssert) {\n checkIEEE754(buf, value, offset, 4, 3.4028234663852886e+38, -3.4028234663852886e+38)\n }\n ieee754.write(buf, value, offset, littleEndian, 23, 4)\n return offset + 4\n}\n\nBuffer.prototype.writeFloatLE = function writeFloatLE (value, offset, noAssert) {\n return writeFloat(this, value, offset, true, noAssert)\n}\n\nBuffer.prototype.writeFloatBE = function writeFloatBE (value, offset, noAssert) {\n return writeFloat(this, value, offset, false, noAssert)\n}\n\nfunction writeDouble (buf, value, offset, littleEndian, noAssert) {\n if (!noAssert) {\n checkIEEE754(buf, value, offset, 8, 1.7976931348623157E+308, -1.7976931348623157E+308)\n }\n ieee754.write(buf, value, offset, littleEndian, 52, 8)\n return offset + 8\n}\n\nBuffer.prototype.writeDoubleLE = function writeDoubleLE (value, offset, noAssert) {\n return writeDouble(this, value, offset, true, noAssert)\n}\n\nBuffer.prototype.writeDoubleBE = function writeDoubleBE (value, offset, noAssert) {\n return writeDouble(this, value, offset, false, noAssert)\n}\n\n// copy(targetBuffer, targetStart=0, sourceStart=0, sourceEnd=buffer.length)\nBuffer.prototype.copy = function copy (target, targetStart, start, end) {\n if (!start) start = 0\n if (!end && end !== 0) end = this.length\n if (targetStart >= target.length) targetStart = target.length\n if (!targetStart) targetStart = 0\n if (end > 0 && end < start) end = start\n\n // Copy 0 bytes; we're done\n if (end === start) return 0\n if (target.length === 0 || this.length === 0) return 0\n\n // Fatal error conditions\n if (targetStart < 0) {\n throw new RangeError('targetStart out of bounds')\n }\n if (start < 0 || start >= this.length) throw new RangeError('sourceStart out of bounds')\n if (end < 0) throw new RangeError('sourceEnd out of bounds')\n\n // Are we oob?\n if (end > this.length) end = this.length\n if (target.length - targetStart < end - start) {\n end = target.length - targetStart + start\n }\n\n var len = end - start\n var i\n\n if (this === target && start < targetStart && targetStart < end) {\n // descending copy from end\n for (i = len - 1; i >= 0; --i) {\n target[i + targetStart] = this[i + start]\n }\n } else if (len < 1000 || !Buffer.TYPED_ARRAY_SUPPORT) {\n // ascending copy from start\n for (i = 0; i < len; ++i) {\n target[i + targetStart] = this[i + start]\n }\n } else {\n Uint8Array.prototype.set.call(\n target,\n this.subarray(start, start + len),\n targetStart\n )\n }\n\n return len\n}\n\n// Usage:\n// buffer.fill(number[, offset[, end]])\n// buffer.fill(buffer[, offset[, end]])\n// buffer.fill(string[, offset[, end]][, encoding])\nBuffer.prototype.fill = function fill (val, start, end, encoding) {\n // Handle string cases:\n if (typeof val === 'string') {\n if (typeof start === 'string') {\n encoding = start\n start = 0\n end = this.length\n } else if (typeof end === 'string') {\n encoding = end\n end = this.length\n }\n if (val.length === 1) {\n var code = val.charCodeAt(0)\n if (code < 256) {\n val = code\n }\n }\n if (encoding !== undefined && typeof encoding !== 'string') {\n throw new TypeError('encoding must be a string')\n }\n if (typeof encoding === 'string' && !Buffer.isEncoding(encoding)) {\n throw new TypeError('Unknown encoding: ' + encoding)\n }\n } else if (typeof val === 'number') {\n val = val & 255\n }\n\n // Invalid ranges are not set to a default, so can range check early.\n if (start < 0 || this.length < start || this.length < end) {\n throw new RangeError('Out of range index')\n }\n\n if (end <= start) {\n return this\n }\n\n start = start >>> 0\n end = end === undefined ? this.length : end >>> 0\n\n if (!val) val = 0\n\n var i\n if (typeof val === 'number') {\n for (i = start; i < end; ++i) {\n this[i] = val\n }\n } else {\n var bytes = Buffer.isBuffer(val)\n ? val\n : utf8ToBytes(new Buffer(val, encoding).toString())\n var len = bytes.length\n for (i = 0; i < end - start; ++i) {\n this[i + start] = bytes[i % len]\n }\n }\n\n return this\n}\n\n// HELPER FUNCTIONS\n// ================\n\nvar INVALID_BASE64_RE = /[^+\\/0-9A-Za-z-_]/g\n\nfunction base64clean (str) {\n // Node strips out invalid characters like \\n and \\t from the string, base64-js does not\n str = stringtrim(str).replace(INVALID_BASE64_RE, '')\n // Node converts strings with length < 2 to ''\n if (str.length < 2) return ''\n // Node allows for non-padded base64 strings (missing trailing ===), base64-js does not\n while (str.length % 4 !== 0) {\n str = str + '='\n }\n return str\n}\n\nfunction stringtrim (str) {\n if (str.trim) return str.trim()\n return str.replace(/^\\s+|\\s+$/g, '')\n}\n\nfunction toHex (n) {\n if (n < 16) return '0' + n.toString(16)\n return n.toString(16)\n}\n\nfunction utf8ToBytes (string, units) {\n units = units || Infinity\n var codePoint\n var length = string.length\n var leadSurrogate = null\n var bytes = []\n\n for (var i = 0; i < length; ++i) {\n codePoint = string.charCodeAt(i)\n\n // is surrogate component\n if (codePoint > 0xD7FF && codePoint < 0xE000) {\n // last char was a lead\n if (!leadSurrogate) {\n // no lead yet\n if (codePoint > 0xDBFF) {\n // unexpected trail\n if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD)\n continue\n } else if (i + 1 === length) {\n // unpaired lead\n if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD)\n continue\n }\n\n // valid lead\n leadSurrogate = codePoint\n\n continue\n }\n\n // 2 leads in a row\n if (codePoint < 0xDC00) {\n if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD)\n leadSurrogate = codePoint\n continue\n }\n\n // valid surrogate pair\n codePoint = (leadSurrogate - 0xD800 << 10 | codePoint - 0xDC00) + 0x10000\n } else if (leadSurrogate) {\n // valid bmp char, but last char was a lead\n if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD)\n }\n\n leadSurrogate = null\n\n // encode utf8\n if (codePoint < 0x80) {\n if ((units -= 1) < 0) break\n bytes.push(codePoint)\n } else if (codePoint < 0x800) {\n if ((units -= 2) < 0) break\n bytes.push(\n codePoint >> 0x6 | 0xC0,\n codePoint & 0x3F | 0x80\n )\n } else if (codePoint < 0x10000) {\n if ((units -= 3) < 0) break\n bytes.push(\n codePoint >> 0xC | 0xE0,\n codePoint >> 0x6 & 0x3F | 0x80,\n codePoint & 0x3F | 0x80\n )\n } else if (codePoint < 0x110000) {\n if ((units -= 4) < 0) break\n bytes.push(\n codePoint >> 0x12 | 0xF0,\n codePoint >> 0xC & 0x3F | 0x80,\n codePoint >> 0x6 & 0x3F | 0x80,\n codePoint & 0x3F | 0x80\n )\n } else {\n throw new Error('Invalid code point')\n }\n }\n\n return bytes\n}\n\nfunction asciiToBytes (str) {\n var byteArray = []\n for (var i = 0; i < str.length; ++i) {\n // Node's code seems to be doing this and not & 0x7F..\n byteArray.push(str.charCodeAt(i) & 0xFF)\n }\n return byteArray\n}\n\nfunction utf16leToBytes (str, units) {\n var c, hi, lo\n var byteArray = []\n for (var i = 0; i < str.length; ++i) {\n if ((units -= 2) < 0) break\n\n c = str.charCodeAt(i)\n hi = c >> 8\n lo = c % 256\n byteArray.push(lo)\n byteArray.push(hi)\n }\n\n return byteArray\n}\n\nfunction base64ToBytes (str) {\n return base64.toByteArray(base64clean(str))\n}\n\nfunction blitBuffer (src, dst, offset, length) {\n for (var i = 0; i < length; ++i) {\n if ((i + offset >= dst.length) || (i >= src.length)) break\n dst[i + offset] = src[i]\n }\n return i\n}\n\nfunction isnan (val) {\n return val !== val // eslint-disable-line no-self-compare\n}\n","'use strict';\n\nvar ConfigService = require('../service/configuration-service');\n\nvar urlConfig = new ConfigService().get('server');\nvar customDefaults = {};\nvar libDefaults = {\n /**\n * The account id. In the Epicenter UI, this is the **Team ID** (for team projects) or **User ID** (for personal projects). Defaults to empty string. If left undefined, taken from the URL.\n * @type {String}\n */\n account: urlConfig.accountPath,\n /**\n * The account id. In the Epicenter UI, this is the **Team ID** (for team projects) or **User ID** (for personal projects). Defaults to empty string. If left undefined, taken from the URL.\n * @type {String}\n */\n project: urlConfig.projectPath,\n isLocal: urlConfig.isLocalhost(),\n store: {}\n};\n\nvar optionUtils = {\n /**\n * Gets the final options by overriding the global options set with\n * optionUtils#setDefaults() and the lib defaults.\n * @param {object} `options` The final options object.\n */\n getOptions: function (options) {\n return $.extend(true, {}, libDefaults, customDefaults, options);\n },\n /**\n * Sets the global defaults for the optionUtils#getOptions() method.\n * @param {object} `defaults` The defaults object.\n */\n setDefaults: function (defaults) {\n customDefaults = defaults;\n }\n};\nmodule.exports = optionUtils;\n","'use strict';\n\nvar classFrom = require('../../util/inherit');\nvar IdentityStrategy = require('./identity-strategy');\nvar StorageFactory = require('../../store/store-factory');\nvar StateApi = require('../../service/state-api-adapter');\nvar AuthManager = require('../auth-manager');\n\nvar keyNames = require('../key-names');\n\nvar defaults = {\n store: {\n synchronous: true\n }\n};\n\nvar Strategy = classFrom(IdentityStrategy, {\n constructor: function Strategy(runService, options) {\n this.run = runService;\n this.options = $.extend(true, {}, defaults, options);\n this.runOptions = this.options.run;\n this._store = new StorageFactory(this.options.store);\n this.stateApi = new StateApi();\n this._auth = new AuthManager();\n\n this._loadAndCheck = this._loadAndCheck.bind(this);\n this._restoreRun = this._restoreRun.bind(this);\n this._getAllRuns = this._getAllRuns.bind(this);\n this._loadRun = this._loadRun.bind(this);\n },\n\n reset: function (runServiceOptions) {\n var session = this._auth.getCurrentUserSessionInfo();\n var opt = $.extend({\n scope: { group: session.groupName }\n }, this.runOptions);\n\n return this.run\n .create(opt, runServiceOptions)\n .then(function (run) {\n run.freshlyCreated = true;\n return run;\n });\n },\n\n getRun: function () {\n return this._getAllRuns()\n .then(this._loadAndCheck);\n },\n\n _getAllRuns: function () {\n var session = JSON.parse(this._store.get(keyNames.EPI_SESSION_KEY) || '{}');\n return this.run.query({\n 'user.id': session.userId || '0000',\n 'scope.group': session.groupName\n });\n },\n\n _loadAndCheck: function (runs) {\n if (!runs || !runs.length) {\n return this.reset();\n }\n\n var dateComp = function (a, b) { return new Date(b.date) - new Date(a.date); };\n var latestRun = runs.sort(dateComp)[0];\n var _this = this;\n var shouldReplay = false;\n\n return this.run.load(latestRun.id, null, {\n success: function (run, msg, headers) {\n shouldReplay = headers.getResponseHeader('pragma') === 'persistent';\n }\n }).then(function (run) {\n return shouldReplay ? _this._restoreRun(run.id) : run;\n });\n },\n\n _restoreRun: function (runId) {\n var _this = this;\n return this.stateApi.replay({ runId: runId })\n .then(function (resp) {\n return _this._loadRun(resp.run);\n });\n },\n\n _loadRun: function (id, options) {\n return this.run.load(id, null, options);\n }\n\n});\n\nmodule.exports = Strategy;\n","'use strict';\n\nvar classFrom = require('../../util/inherit');\n\nvar IdentityStrategy = require('./identity-strategy');\nvar WorldApiAdapter = require('../../service/world-api-adapter');\nvar AuthManager = require('../auth-manager');\n\nvar defaults = {\n store: {\n synchronous: true\n }\n};\n\nvar Strategy = classFrom(IdentityStrategy, {\n\n constructor: function (runService, options) {\n this.runService = runService;\n this.options = $.extend(true, {}, defaults, options);\n this._auth = new AuthManager();\n this._loadRun = this._loadRun.bind(this);\n this.worldApi = new WorldApiAdapter(this.options.run);\n },\n\n reset: function () {\n var session = this._auth.getCurrentUserSessionInfo();\n var curUserId = session.userId;\n var curGroupName = session.groupName;\n\n return this.worldApi\n .getCurrentWorldForUser(curUserId, curGroupName)\n .then(function (world) {\n return this.worldApi.newRunForWorld(world.id);\n }.bind(this));\n },\n\n getRun: function () {\n var session = this._auth.getCurrentUserSessionInfo();\n var curUserId = session.userId;\n var curGroupName = session.groupName;\n var worldApi = this.worldApi;\n var model = this.options.model;\n var _this = this;\n var dtd = $.Deferred();\n\n if (!curUserId) {\n return dtd.reject({ statusCode: 400, error: 'We need an authenticated user to join a multiplayer world. (ERR: no userId in session)' }, session).promise();\n }\n\n var loadRunFromWorld = function (world) {\n if (!world) {\n return dtd.reject({ statusCode: 404, error: 'The user is not in any world.' }, { options: this.options, session: session });\n }\n\n return worldApi.getCurrentRunId({ model: model, filter: world.id })\n .then(_this._loadRun)\n .then(dtd.resolve)\n .fail(dtd.reject);\n };\n\n var serverError = function (error) {\n // is this possible?\n dtd.reject(error, session, this.options);\n };\n\n this.worldApi\n .getCurrentWorldForUser(curUserId, curGroupName)\n .then(loadRunFromWorld)\n .fail(serverError);\n\n return dtd.promise();\n },\n\n _loadRun: function (id, options) {\n return this.runService.load(id, null, options);\n }\n});\n\nmodule.exports = Strategy;\n","'use strict';\n/* eslint-disable no-unused-vars */\nvar hasOwnProperty = Object.prototype.hasOwnProperty;\nvar propIsEnumerable = Object.prototype.propertyIsEnumerable;\n\nfunction toObject(val) {\n\tif (val === null || val === undefined) {\n\t\tthrow new TypeError('Object.assign cannot be called with null or undefined');\n\t}\n\n\treturn Object(val);\n}\n\nfunction shouldUseNative() {\n\ttry {\n\t\tif (!Object.assign) {\n\t\t\treturn false;\n\t\t}\n\n\t\t// Detect buggy property enumeration order in older V8 versions.\n\n\t\t// https://bugs.chromium.org/p/v8/issues/detail?id=4118\n\t\tvar test1 = new String('abc'); // eslint-disable-line\n\t\ttest1[5] = 'de';\n\t\tif (Object.getOwnPropertyNames(test1)[0] === '5') {\n\t\t\treturn false;\n\t\t}\n\n\t\t// https://bugs.chromium.org/p/v8/issues/detail?id=3056\n\t\tvar test2 = {};\n\t\tfor (var i = 0; i < 10; i++) {\n\t\t\ttest2['_' + String.fromCharCode(i)] = i;\n\t\t}\n\t\tvar order2 = Object.getOwnPropertyNames(test2).map(function (n) {\n\t\t\treturn test2[n];\n\t\t});\n\t\tif (order2.join('') !== '0123456789') {\n\t\t\treturn false;\n\t\t}\n\n\t\t// https://bugs.chromium.org/p/v8/issues/detail?id=3056\n\t\tvar test3 = {};\n\t\t'abcdefghijklmnopqrst'.split('').forEach(function (letter) {\n\t\t\ttest3[letter] = letter;\n\t\t});\n\t\tif (Object.keys(Object.assign({}, test3)).join('') !==\n\t\t\t\t'abcdefghijklmnopqrst') {\n\t\t\treturn false;\n\t\t}\n\n\t\treturn true;\n\t} catch (e) {\n\t\t// We don't expect any of the above to throw, but better to be safe.\n\t\treturn false;\n\t}\n}\n\nmodule.exports = shouldUseNative() ? Object.assign : function (target, source) {\n\tvar from;\n\tvar to = toObject(target);\n\tvar symbols;\n\n\tfor (var s = 1; s < arguments.length; s++) {\n\t\tfrom = Object(arguments[s]);\n\n\t\tfor (var key in from) {\n\t\t\tif (hasOwnProperty.call(from, key)) {\n\t\t\t\tto[key] = from[key];\n\t\t\t}\n\t\t}\n\n\t\tif (Object.getOwnPropertySymbols) {\n\t\t\tsymbols = Object.getOwnPropertySymbols(from);\n\t\t\tfor (var i = 0; i < symbols.length; i++) {\n\t\t\t\tif (propIsEnumerable.call(from, symbols[i])) {\n\t\t\t\t\tto[symbols[i]] = from[symbols[i]];\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\treturn to;\n};\n","'use strict'\n\nexports.toByteArray = toByteArray\nexports.fromByteArray = fromByteArray\n\nvar lookup = []\nvar revLookup = []\nvar Arr = typeof Uint8Array !== 'undefined' ? Uint8Array : Array\n\nfunction init () {\n var code = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'\n for (var i = 0, len = code.length; i < len; ++i) {\n lookup[i] = code[i]\n revLookup[code.charCodeAt(i)] = i\n }\n\n revLookup['-'.charCodeAt(0)] = 62\n revLookup['_'.charCodeAt(0)] = 63\n}\n\ninit()\n\nfunction toByteArray (b64) {\n var i, j, l, tmp, placeHolders, arr\n var len = b64.length\n\n if (len % 4 > 0) {\n throw new Error('Invalid string. Length must be a multiple of 4')\n }\n\n // the number of equal signs (place holders)\n // if there are two placeholders, than the two characters before it\n // represent one byte\n // if there is only one, then the three characters before it represent 2 bytes\n // this is just a cheap hack to not do indexOf twice\n placeHolders = b64[len - 2] === '=' ? 2 : b64[len - 1] === '=' ? 1 : 0\n\n // base64 is 4/3 + up to two characters of the original data\n arr = new Arr(len * 3 / 4 - placeHolders)\n\n // if there are placeholders, only get up to the last complete 4 chars\n l = placeHolders > 0 ? len - 4 : len\n\n var L = 0\n\n for (i = 0, j = 0; i < l; i += 4, j += 3) {\n tmp = (revLookup[b64.charCodeAt(i)] << 18) | (revLookup[b64.charCodeAt(i + 1)] << 12) | (revLookup[b64.charCodeAt(i + 2)] << 6) | revLookup[b64.charCodeAt(i + 3)]\n arr[L++] = (tmp >> 16) & 0xFF\n arr[L++] = (tmp >> 8) & 0xFF\n arr[L++] = tmp & 0xFF\n }\n\n if (placeHolders === 2) {\n tmp = (revLookup[b64.charCodeAt(i)] << 2) | (revLookup[b64.charCodeAt(i + 1)] >> 4)\n arr[L++] = tmp & 0xFF\n } else if (placeHolders === 1) {\n tmp = (revLookup[b64.charCodeAt(i)] << 10) | (revLookup[b64.charCodeAt(i + 1)] << 4) | (revLookup[b64.charCodeAt(i + 2)] >> 2)\n arr[L++] = (tmp >> 8) & 0xFF\n arr[L++] = tmp & 0xFF\n }\n\n return arr\n}\n\nfunction tripletToBase64 (num) {\n return lookup[num >> 18 & 0x3F] + lookup[num >> 12 & 0x3F] + lookup[num >> 6 & 0x3F] + lookup[num & 0x3F]\n}\n\nfunction encodeChunk (uint8, start, end) {\n var tmp\n var output = []\n for (var i = start; i < end; i += 3) {\n tmp = (uint8[i] << 16) + (uint8[i + 1] << 8) + (uint8[i + 2])\n output.push(tripletToBase64(tmp))\n }\n return output.join('')\n}\n\nfunction fromByteArray (uint8) {\n var tmp\n var len = uint8.length\n var extraBytes = len % 3 // if we have 1 byte left, pad 2 bytes\n var output = ''\n var parts = []\n var maxChunkLength = 16383 // must be multiple of 3\n\n // go through the array every three bytes, we'll deal with trailing stuff later\n for (var i = 0, len2 = len - extraBytes; i < len2; i += maxChunkLength) {\n parts.push(encodeChunk(uint8, i, (i + maxChunkLength) > len2 ? len2 : (i + maxChunkLength)))\n }\n\n // pad the end with zeros, but make sure to not forget the extra bytes\n if (extraBytes === 1) {\n tmp = uint8[len - 1]\n output += lookup[tmp >> 2]\n output += lookup[(tmp << 4) & 0x3F]\n output += '=='\n } else if (extraBytes === 2) {\n tmp = (uint8[len - 2] << 8) + (uint8[len - 1])\n output += lookup[tmp >> 10]\n output += lookup[(tmp >> 4) & 0x3F]\n output += lookup[(tmp << 2) & 0x3F]\n output += '='\n }\n\n parts.push(output)\n\n return parts.join('')\n}\n","exports.read = function (buffer, offset, isLE, mLen, nBytes) {\n var e, m\n var eLen = nBytes * 8 - mLen - 1\n var eMax = (1 << eLen) - 1\n var eBias = eMax >> 1\n var nBits = -7\n var i = isLE ? (nBytes - 1) : 0\n var d = isLE ? -1 : 1\n var s = buffer[offset + i]\n\n i += d\n\n e = s & ((1 << (-nBits)) - 1)\n s >>= (-nBits)\n nBits += eLen\n for (; nBits > 0; e = e * 256 + buffer[offset + i], i += d, nBits -= 8) {}\n\n m = e & ((1 << (-nBits)) - 1)\n e >>= (-nBits)\n nBits += mLen\n for (; nBits > 0; m = m * 256 + buffer[offset + i], i += d, nBits -= 8) {}\n\n if (e === 0) {\n e = 1 - eBias\n } else if (e === eMax) {\n return m ? NaN : ((s ? -1 : 1) * Infinity)\n } else {\n m = m + Math.pow(2, mLen)\n e = e - eBias\n }\n return (s ? -1 : 1) * m * Math.pow(2, e - mLen)\n}\n\nexports.write = function (buffer, value, offset, isLE, mLen, nBytes) {\n var e, m, c\n var eLen = nBytes * 8 - mLen - 1\n var eMax = (1 << eLen) - 1\n var eBias = eMax >> 1\n var rt = (mLen === 23 ? Math.pow(2, -24) - Math.pow(2, -77) : 0)\n var i = isLE ? 0 : (nBytes - 1)\n var d = isLE ? 1 : -1\n var s = value < 0 || (value === 0 && 1 / value < 0) ? 1 : 0\n\n value = Math.abs(value)\n\n if (isNaN(value) || value === Infinity) {\n m = isNaN(value) ? 1 : 0\n e = eMax\n } else {\n e = Math.floor(Math.log(value) / Math.LN2)\n if (value * (c = Math.pow(2, -e)) < 1) {\n e--\n c *= 2\n }\n if (e + eBias >= 1) {\n value += rt / c\n } else {\n value += rt * Math.pow(2, 1 - eBias)\n }\n if (value * c >= 2) {\n e++\n c /= 2\n }\n\n if (e + eBias >= eMax) {\n m = 0\n e = eMax\n } else if (e + eBias >= 1) {\n m = (value * c - 1) * Math.pow(2, mLen)\n e = e + eBias\n } else {\n m = value * Math.pow(2, eBias - 1) * Math.pow(2, mLen)\n e = 0\n }\n }\n\n for (; mLen >= 8; buffer[offset + i] = m & 0xff, i += d, m /= 256, mLen -= 8) {}\n\n e = (e << mLen) | m\n eLen += mLen\n for (; eLen > 0; buffer[offset + i] = e & 0xff, i += d, e /= 256, eLen -= 8) {}\n\n buffer[offset + i - d] |= s * 128\n}\n","var toString = {}.toString;\n\nmodule.exports = Array.isArray || function (arr) {\n return toString.call(arr) == '[object Array]';\n};\n"]} \ No newline at end of file +<<<<<<< HEAD +{"version":3,"sources":["node_modules/browser-pack/_prelude.js","src/api-version.json","src/app.js","src/env-load.js","src/util/query-util.js","src/util/make-sequence.js","src/util/run-util.js","src/util/inherit.js","src/transport/http-transport-factory.js","src/transport/ajax-http-transport.js","src/service/url-config-service.js","src/service/configuration-service.js","src/service/run-api-service.js","src/service/admin-file-service.js","src/service/variables-api-service.js","src/service/data-api-service.js","src/service/auth-api-service.js","src/service/state-api-adapter.js","src/service/world-api-adapter.js","src/service/user-api-adapter.js","src/service/member-api-adapter.js","src/service/asset-api-adapter.js","src/service/group-api-service.js","src/store/cookie-store.js","src/store/store-factory.js","src/managers/scenario-manager.js","src/managers/run-manager.js","src/managers/auth-manager.js","src/managers/world-manager.js","src/managers/run-strategies/always-new-strategy.js","src/managers/run-strategies/conditional-creation-strategy.js","src/managers/run-strategies/identity-strategy.js","src/managers/run-strategies/new-if-missing-strategy.js","src/managers/run-strategies/new-if-persisted-strategy.js","src/managers/run-strategies/new-if-initialized-strategy.js","src/service/channel-service.js","src/managers/epicenter-channel-manager.js","src/util/object-util.js","src/store/session-manager.js","src/service/service-utils.js","src/managers/run-strategies/strategies-map.js","src/managers/special-operations.js","src/managers/channel-manager.js","src/managers/key-names.js","node_modules/buffer/index.js","src/util/option-utils.js","src/managers/run-strategies/persistent-single-player-strategy.js","src/managers/run-strategies/multiplayer-strategy.js","node_modules/object-assign/index.js","node_modules/base64-js/lib/b64.js","node_modules/ieee754/index.js","node_modules/isarray/index.js"],"names":["F","util","factory","transport","store","service","manager","strategy","load","require","query","makeSequence","run","classFrom","Transport","Ajax","URL","Config","Run","File","Variables","Data","Auth","World","State","User","Member","Asset","Group","Cookie","Store","ScenarioManager","RunManager","AuthManager","WorldManager","identity","ChannelManager","Channel","version","api","global","module","exports","urlConfigService","envLoad","callback","envPromise","host","urlService","envPath","isLocalhost","infoUrl","$","ajax","url","async","done","res","extend","fail","protocol","toMatrixFormat","qs","undefined","String","returnArray","OPERATORS","each","key","value","inArray","trim","charAt","push","mtrx","join","toQueryFormat","isArray","isPlainObject","JSON","stringify","result","qsToObject","qsArray","split","returnObj","index","qKey","qVal","indexOf","mergeQS","qs1","qs2","obj1","this","obj2","addTrailingSlash","length","_w","val","then","p","Deferred","resolve","promise","seq","next","cur","list","splice","Array","prototype","slice","apply","arguments","seed","MakeSeq","obj","__calls","original","fn","start","_this","funcMaker","bind","args","Function","concat","prop","qutil","MAX_URL_LENGTH","normalizeOperations","operations","returnList","ops","_concat","arr","_normalizePlainObjects","opn","arg","_normalizeStructuredObjects","operation","name","params","_normalizeObject","_normalizeLiterals","_normalizeArrays","splitGetFactory","httpOptions","options","http","getValue","getFinalUrl","data","replace","queryParams","questionIdx","include","encodeURI","dtd","paramsCopy","urlNoIncludes","diff","oldSuccess","success","noop","oldError","error","currIncludes","includeOpts","currLength","encodeURIComponent","variable","pop","varLenght","reqs","map","reqParams","get","when","isValid","reject","firstResponse","isObject","isRunAPI","variables","aggregateRun","idx","aggregatedRuns","runs","idxRun","id","aggregatedVariables","vars","inherit","C","P","__super","constructor","dest","call","current","j","base","props","staticProps","parent","child","hasOwnProperty","qutils","config","defaults","contentType","headers","statusCode","404","parameterParser","xhrFields","withCredentials","transportOptions","d","isFunction","connect","method","connectOptions","type","ALLOWED_TO_BE_FUNCTIONS","logLevel","console","log","oldSuccessFn","response","ajaxStatus","ajaxReq","beforeSend","xhr","settings","requestUrl","publicAPI","ajaxOptions","splitGet","post","patch","put","delete","delimiter","head","epiVersion","window","location","pathname","UrlConfigService","path","API_PROTOCOL","HOST_API_MAPPING","forio.com","foriodev.com","publicExports","appPath","accountPath","accnt","projectPath","prj","versionPath","getAPIPath","PROJECT_APIS","apiPath","envConf","serviceOptions","server","setEnv","env","property","set","ConfigService","rutil","_pick","TransportFactory","VariablesService","SessionManager","token","account","project","filter","autoRestore","sessionManager","getMergedOptions","urlConfig","getFilterURL","addAutoRestoreHeader","isFilterRunId","autorestoreOpts","X-AutoRestore","Authorization","setFilterOrThrowError","Error","publicAsyncAPI","create","createOptions","runApiParams","model","outputModifier","runID","filters","save","attributes","do","opsArgs","postOptions","prms","serial","opParams","me","$d","doSingleOp","op","shift","parallel","queue","i","publicSyncAPI","getCurrentConfig","vs","runService","folderType","getContents","filePath","writeToFile","contents","fileName","boundary","body","remove","rename","newName","getURL","attrs","root","q","saveAs","keys","userName","password","login","resp","status","statusMessage","postParams","logout","apiEndpoint","parseRunIdOrError","runId","replay","replayOptions","action","clone","apiBase","assignmentEndpoint","projectEndpoint","group","setIdFilterOrThrowError","validateModelOrThrowError","worldApiParams","validParams","update","whitelist","updateOptions","deleteOptions","updateConfig","getOptions","getWorldsForUser","userId","worldId","addUsers","users","u","updateUser","user","patchOptions","removeUser","getCurrentRunId","getCurrentWorldForUser","groupName","worlds","sort","a","b","Date","lastModified","currentWorld","deleteRun","newRunForWorld","currentRunOptions","autoAssign","opt","maxUsers","getProjectSettings","toQFilter","toIdFilters","getFilters","threshold","getById","groupId","getFinalParams","patchUserActiveField","active","getGroupsForUser","isString","objParams","getParms","getGroupDetails","makeUserActive","makeUserInactive","scope","fullUrl","processData","assetApiParams","scopeConfig","validateFilename","filename","validateUrlParams","partKeys","buildUrl","parts","upload","toLowerCase","FormData","urlOptions","getServiceOptions","files","fullPathFiles","file","assetUrl","serviceUtils","objectAssign","GroupService","getDefaultOptions","getGroups","finalOpts","finalParams","getApiUrl","document","cookie","newCookie","hostname","validHost","domain","setOptions","cookieReg","RegExp","exec","decodeURIComponent","remOptions","destroy","aKeys","nIdx","cookieKey","RunService","validFilter","saved","getRuns","loadVariables","meta","_getService","archive","getRun","patchRunService","patched","orig","reservedOps","Object","specialOperations","StrategyCtor","strategiesMap","reset","runServiceOptions","isLocal","authAdapter","AuthAdapter","MemberAdapter","Buffer","requiresGroup","_findUserInGroup","members","adapterOptions","outSuccess","outError","decodeToken","encoded","decode","atob","toString","parse","handleGroupError","message","statusText","handleSuccess","access_token","userInfo","oldGroups","getSession","groups","userGroupOpts","auth","isTeamMember","parent_account_id","sessionInfo","auth_token","user_id","saveSession","handleGroupList","groupList","userGroups","filteredGroups","grep","resGroup","isFac","role","groupData","sessionInfoWithGroup","opts","groupService","forEach","getUserGroups","removeCookieFn","removeSession","getToken","session","memberInfo","memberAdapter","getCurrentUserSessionInfo","addGroups","extendedGroup","validProps","buildStrategy","worldApi","WorldApi","world","_auth","getCurrentWorld","getCurrentRun","getAndRestoreLatestRun","currentWorldId","runOpts","rm","curUserId","curGroupName","ConditionalStrategy","Strategy","createIf","setRunInSession","sessionKey","getStore","makeSeq","Base","keyNames","STRATEGY_SESSION_KEY","condition","runOptions","runOptionsWithScope","userSession","freshlyCreated","sessionStore","runSession","_loadAndCheck","shouldCreate","msg","getResponseHeader","initialized","topicResolver","topic","channelOptions","makeName","channelName","subscribe","context","topics","subscriptionIds","batch","publish","returnObjs","warn","unsubscribe","on","event","off","trigger","validTypes","general","chat","getFromSettingsOrSessionOrError","sessionKeyName","EpicenterChannelManager","defaultCometOptions","urlOpts","handshake","userProp","ext","authorization","getChannel","channelOpts","allowAllChannels","baseParts","channelType","getGroupChannel","baseTopic","getWorldChannel","worldid","getUserChannel","userid","getPresenceChannel","channel","lastPingTime","PING_INTERVAL","notification","incomingUserId","online","valueOf","setInterval","now","getDataChannel","collection","oldsubs","callbackWithCleanData","payload","subType","date","actualData","StorageFactory","optionUtils","EPI_SESSION_KEY","synchronous","managerOptions","getBaseOptions","overrides","libOptions","finalOptions","baseOptions","storeOpts","serialized","cookieName","sessionDefaults","rest","new-if-initialized","new-if-persisted","new-if-missing","always-new","multiplayer","persistent-single-player","none","cometd","websocketEnabled","shareConnection","currentSubscriptions","_cometd","Cometd","isConnected","connectionBroken","connectionSucceeded","configure","addListener","wasConnected","successful","subs","resubscribe","subid","unsubs","removed","typedArraySupport","Uint8Array","__proto__","foo","subarray","byteLength","e","kMaxLength","TYPED_ARRAY_SUPPORT","createBuffer","that","RangeError","encodingOrOffset","allocUnsafe","from","TypeError","ArrayBuffer","fromArrayBuffer","fromString","fromObject","assertSize","size","alloc","fill","encoding","checked","string","isEncoding","write","fromArrayLike","array","byteOffset","isBuffer","len","copy","buffer","isnan","SlowBuffer","isView","loweredCase","utf8ToBytes","base64ToBytes","slowToString","end","hexSlice","utf8Slice","asciiSlice","binarySlice","base64Slice","utf16leSlice","swap","n","m","arrayIndexOf","read","buf","indexSize","readUInt16BE","arrLength","valLength","foundIndex","hexWrite","offset","Number","remaining","strLen","parsed","parseInt","substr","isNaN","utf8Write","blitBuffer","asciiWrite","asciiToBytes","binaryWrite","base64Write","ucs2Write","utf16leToBytes","base64","fromByteArray","Math","min","firstByte","codePoint","bytesPerSequence","secondByte","thirdByte","fourthByte","tempCodePoint","decodeCodePointsArray","codePoints","MAX_ARGUMENTS_LENGTH","fromCharCode","ret","out","toHex","bytes","checkOffset","checkInt","max","objectWriteUInt16","littleEndian","objectWriteUInt32","checkIEEE754","writeFloat","noAssert","ieee754","writeDouble","base64clean","str","stringtrim","INVALID_BASE64_RE","units","Infinity","leadSurrogate","charCodeAt","byteArray","c","hi","lo","toByteArray","src","dst","INSPECT_MAX_BYTES","poolSize","_augment","Symbol","species","defineProperty","configurable","allocUnsafeSlow","_isBuffer","compare","x","y","pos","swap16","swap32","equals","inspect","match","target","thisStart","thisEnd","thisCopy","targetCopy","includes","isFinite","toJSON","_arr","newBuf","sliceLen","readUIntLE","mul","readUIntBE","readUInt8","readUInt16LE","readUInt32LE","readUInt32BE","readIntLE","pow","readIntBE","readInt8","readInt16LE","readInt16BE","readInt32LE","readInt32BE","readFloatLE","readFloatBE","readDoubleLE","readDoubleBE","writeUIntLE","maxBytes","writeUIntBE","writeUInt8","floor","writeUInt16LE","writeUInt16BE","writeUInt32LE","writeUInt32BE","writeIntLE","limit","sub","writeIntBE","writeInt8","writeInt16LE","writeInt16BE","writeInt32LE","writeInt32BE","writeFloatLE","writeFloatBE","writeDoubleLE","writeDoubleBE","targetStart","code","customDefaults","libDefaults","setDefaults","IdentityStrategy","StateApi","_store","stateApi","_restoreRun","_getAllRuns","_loadRun","user.id","scope.group","dateComp","latestRun","shouldReplay","WorldApiAdapter","loadRunFromWorld","serverError","toObject","shouldUseNative","assign","test1","getOwnPropertyNames","test2","order2","test3","letter","propIsEnumerable","propertyIsEnumerable","source","to","symbols","s","getOwnPropertySymbols","init","lookup","revLookup","b64","l","tmp","placeHolders","Arr","L","tripletToBase64","num","encodeChunk","uint8","output","extraBytes","maxChunkLength","len2","isLE","mLen","nBytes","eLen","eMax","eBias","nBits","NaN","rt","abs","LN2"],"mappings":"AAAA;AiDAA,YASA,SAASi4B,QACP,GAAInC,MAAO,kEACX,KAAK,GAAI/hB,GAAI,EAAG8X,IAAMiK,KAAK7vB,OAAQ8N,EAAI8X,MAAO9X,EAC5CmkB,OAAOnkB,GAAK+hB,KAAK/hB,GACjBokB,UAAUrC,KAAK/E,WAAWhd,IAAMA,CAGlCokB,WAAU,IAAIpH,WAAW,IAAM,GAC/BoH,UAAU,IAAIpH,WAAW,IAAM,GAKjC,QAASK,aAAagH,KACpB,GAAIrkB,GAAGrH,EAAG2rB,EAAGC,IAAKC,aAAc/vB,GAChC,IAAIqjB,KAAMuM,IAAInyB,MAEd,IAAI4lB,IAAM,EAAI,EACZ,KAAM,IAAItZ,OAAM,iDAQlBgmB,cAAgC,MAAjBH,IAAIvM,IAAM,GAAa,EAAqB,MAAjBuM,IAAIvM,IAAM,GAAa,EAAI,EAGrErjB,IAAM,GAAIgwB,KAAU,EAAN3M,IAAU,EAAI0M,cAG5BF,EAAIE,aAAe,EAAI1M,IAAM,EAAIA,GAEjC,IAAI4M,GAAI,CAER,KAAK1kB,EAAI,EAAGrH,EAAI,EAAGqH,EAAIskB,EAAGtkB,GAAK,EAAGrH,GAAK,EACrC4rB,IAAOH,UAAUC,IAAIrH,WAAWhd,KAAO,GAAOokB,UAAUC,IAAIrH,WAAWhd,EAAI,KAAO,GAAOokB,UAAUC,IAAIrH,WAAWhd,EAAI,KAAO,EAAKokB,UAAUC,IAAIrH,WAAWhd,EAAI,IAC/JvL,IAAIiwB,KAAQH,KAAO,GAAM,IACzB9vB,IAAIiwB,KAAQH,KAAO,EAAK,IACxB9vB,IAAIiwB,KAAa,IAANH,GAYb,OATqB,KAAjBC,cACFD,IAAOH,UAAUC,IAAIrH,WAAWhd,KAAO,EAAMokB,UAAUC,IAAIrH,WAAWhd,EAAI,KAAO,EACjFvL,IAAIiwB,KAAa,IAANH,KACe,IAAjBC,eACTD,IAAOH,UAAUC,IAAIrH,WAAWhd,KAAO,GAAOokB,UAAUC,IAAIrH,WAAWhd,EAAI,KAAO,EAAMokB,UAAUC,IAAIrH,WAAWhd,EAAI,KAAO,EAC5HvL,IAAIiwB,KAAQH,KAAO,EAAK,IACxB9vB,IAAIiwB,KAAa,IAANH,KAGN9vB,IAGT,QAASkwB,iBAAiBC,KACxB,MAAOT,QAAOS,KAAO,GAAK,IAAQT,OAAOS,KAAO,GAAK,IAAQT,OAAOS,KAAO,EAAI,IAAQT,OAAa,GAANS,KAGhG,QAASC,aAAaC,MAAOpxB,MAAO8kB,KAClC,GAAI+L,IACJ,IAAIQ,UACJ,KAAK,GAAI/kB,GAAItM,MAAOsM,EAAIwY,IAAKxY,GAAK,EAChCukB,KAAOO,MAAM9kB,IAAM,KAAO8kB,MAAM9kB,EAAI,IAAM,GAAM8kB,MAAM9kB,EAAI,GAC1D+kB,OAAOr0B,KAAKi0B,gBAAgBJ,KAE9B,OAAOQ,QAAOn0B,KAAK,IAGrB,QAASgqB,eAAekK,OACtB,GAAIP,IACJ,IAAIzM,KAAMgN,MAAM5yB,MAChB,IAAI8yB,YAAalN,IAAM,CACvB,IAAIiN,QAAS,EACb,IAAIve,SACJ,IAAIye,gBAAiB,KAGrB,KAAK,GAAIjlB,GAAI,EAAGklB,KAAOpN,IAAMkN,WAAYhlB,EAAIklB,KAAMllB,GAAKilB,eACtDze,MAAM9V,KAAKm0B,YAAYC,MAAO9kB,EAAIA,EAAIilB,eAAkBC,KAAOA,KAAQllB,EAAIilB,gBAmB7E,OAfmB,KAAfD,YACFT,IAAMO,MAAMhN,IAAM,GAClBiN,QAAUZ,OAAOI,KAAO,GACxBQ,QAAUZ,OAAQI,KAAO,EAAK,IAC9BQ,QAAU,MACc,IAAfC,aACTT,KAAOO,MAAMhN,IAAM,IAAM,GAAMgN,MAAMhN,IAAM,GAC3CiN,QAAUZ,OAAOI,KAAO,IACxBQ,QAAUZ,OAAQI,KAAO,EAAK,IAC9BQ,QAAUZ,OAAQI,KAAO,EAAK,IAC9BQ,QAAU,KAGZve,MAAM9V,KAAKq0B,QAEJve,MAAM5V,KAAK,IAzGpBjC,QAAQ0uB,YAAcA,YACtB1uB,QAAQisB,cAAgBA,aAExB,IAAIuJ,UACJ,IAAIC,aACJ,IAAIK,KAA4B,mBAAf3O,YAA6BA,WAAa/iB,KAa3DmxB;;;ALZA,YA2CA,SAASrO,qBACP,IACE,GAAIphB,KAAM,GAAIqhB,YAAW,EAEzB,OADArhB,KAAIshB,WAAaA,UAAWD,WAAW9iB,UAAWgjB,IAAK,WAAc,MAAO,MACvD,KAAdvhB,IAAIuhB,OACiB,kBAAjBvhB,KAAIwhB,UACuB,IAAlCxhB,IAAIwhB,SAAS,EAAG,GAAGC,WACvB,MAAOC,GACP,OAAO,GAIX,QAASC,cACP,MAAOnM,QAAOoM,oBACV,WACA,WAGN,QAASC,cAAcC,KAAMrkB,QAC3B,GAAIkkB,aAAelkB,OACjB,KAAM,IAAIskB,YAAW,6BAcvB,OAZIvM,QAAOoM,qBAETE,KAAO,GAAIT,YAAW5jB,QACtBqkB,KAAKR,UAAY9L,OAAOjX,YAGX,OAATujB,OACFA,KAAO,GAAItM,QAAO/X,SAEpBqkB,KAAKrkB,OAASA,QAGTqkB,KAaT,QAAStM,QAAQrV,IAAK6hB,iBAAkBvkB,QACtC,KAAK+X,OAAOoM,qBAAyBtkB,eAAgBkY,SACnD,MAAO,IAAIA,QAAOrV,IAAK6hB,iBAAkBvkB,OAI3C,IAAmB,gBAAR0C,KAAkB,CAC3B,GAAgC,gBAArB6hB,kBACT,KAAM,IAAIjY,OACR,oEAGJ,OAAOkY,aAAY3kB,KAAM6C,KAE3B,MAAO+hB,MAAK5kB,KAAM6C,IAAK6hB,iBAAkBvkB,QAW3C,QAASykB,MAAMJ,KAAMjmB,MAAOmmB,iBAAkBvkB,QAC5C,GAAqB,gBAAV5B,OACT,KAAM,IAAIsmB,WAAU,wCAGtB,OAA2B,mBAAhBC,cAA+BvmB,gBAAiBumB,aAClDC,gBAAgBP,KAAMjmB,MAAOmmB,iBAAkBvkB,QAGnC,gBAAV5B,OACFymB,WAAWR,KAAMjmB,MAAOmmB,kBAG1BO,WAAWT,KAAMjmB,OA4B1B,QAAS2mB,YAAYC,MACnB,GAAoB,gBAATA,MACT,KAAM,IAAIN,WAAU,oCAIxB,QAASO,OAAOZ,KAAMW,KAAME,KAAMC,UAEhC,MADAJ,YAAWC,MACPA,MAAQ,EACHZ,aAAaC,KAAMW,MAEflnB,SAATonB,KAIyB,gBAAbC,UACVf,aAAaC,KAAMW,MAAME,KAAKA,KAAMC,UACpCf,aAAaC,KAAMW,MAAME,KAAKA,MAE7Bd,aAAaC,KAAMW,MAW5B,QAASR,aAAaH,KAAMW,MAG1B,GAFAD,WAAWC,MACXX,KAAOD,aAAaC,KAAMW,KAAO,EAAI,EAAoB,EAAhBI,QAAQJ,QAC5CjN,OAAOoM,oBACV,IAAK,GAAIrW,GAAI,EAAGA,EAAIkX,OAAQlX,EAC1BuW,KAAKvW,GAAK,CAGd,OAAOuW,MAgBT,QAASQ,YAAYR,KAAMgB,OAAQF,UAKjC,GAJwB,gBAAbA,WAAsC,KAAbA,WAClCA,SAAW,SAGRpN,OAAOuN,WAAWH,UACrB,KAAM,IAAIT,WAAU,6CAGtB,IAAI1kB,QAAwC,EAA/BgkB,WAAWqB,OAAQF,SAIhC,OAHAd,MAAOD,aAAaC,KAAMrkB,QAE1BqkB,KAAKkB,MAAMF,OAAQF,UACZd,KAGT,QAASmB,eAAenB,KAAMoB,OAC5B,GAAIzlB,QAAiC,EAAxBolB,QAAQK,MAAMzlB,OAC3BqkB,MAAOD,aAAaC,KAAMrkB,OAC1B,KAAK,GAAI8N,GAAI,EAAGA,EAAI9N,OAAQ8N,GAAK,EAC/BuW,KAAKvW,GAAgB,IAAX2X,MAAM3X,EAElB,OAAOuW,MAGT,QAASO,iBAAiBP,KAAMoB,MAAOC,WAAY1lB,QAGjD,GAFAylB,MAAMzB,WAEF0B,WAAa,GAAKD,MAAMzB,WAAa0B,WACvC,KAAM,IAAIpB,YAAW,4BAGvB,IAAImB,MAAMzB,WAAa0B,YAAc1lB,QAAU,GAC7C,KAAM,IAAIskB,YAAW,4BAmBvB,OAfEmB,OADiB3nB,SAAf4nB,YAAuC5nB,SAAXkC,OACtB,GAAI4jB,YAAW6B,OACH3nB,SAAXkC,OACD,GAAI4jB,YAAW6B,MAAOC,YAEtB,GAAI9B,YAAW6B,MAAOC,WAAY1lB,QAGxC+X,OAAOoM,qBAETE,KAAOoB,MACPpB,KAAKR,UAAY9L,OAAOjX,WAGxBujB,KAAOmB,cAAcnB,KAAMoB,OAEtBpB,KAGT,QAASS,YAAYT,KAAMjjB,KACzB,GAAI2W,OAAO4N,SAASvkB,KAAM,CACxB,GAAIwkB,KAA4B,EAAtBR,QAAQhkB,IAAIpB,OAGtB,OAFAqkB,MAAOD,aAAaC,KAAMuB,KAEN,IAAhBvB,KAAKrkB,OACAqkB,MAGTjjB,IAAIykB,KAAKxB,KAAM,EAAG,EAAGuB,KACdvB,MAGT,GAAIjjB,IAAK,CACP,GAA4B,mBAAhBujB,cACRvjB,IAAI0kB,iBAAkBnB,cAAgB,UAAYvjB,KACpD,MAA0B,gBAAfA,KAAIpB,QAAuB+lB,MAAM3kB,IAAIpB,QACvCokB,aAAaC,KAAM,GAErBmB,cAAcnB,KAAMjjB,IAG7B,IAAiB,WAAbA,IAAI4G,MAAqBpJ,QAAQwC,IAAIoC,MACvC,MAAOgiB,eAAcnB,KAAMjjB,IAAIoC,MAInC,KAAM,IAAIkhB,WAAU,sFAGtB,QAASU,SAASplB,QAGhB,GAAIA,QAAUkkB,aACZ,KAAM,IAAII,YAAW,0DACaJ,aAAaxL,SAAS,IAAM,SAEhE,OAAgB,GAAT1Y,OAGT,QAASgmB,YAAYhmB,QAInB,OAHKA,QAAUA,SACbA,OAAS,GAEJ+X,OAAOkN,OAAOjlB,QA+EvB,QAASgkB,YAAYqB,OAAQF,UAC3B,GAAIpN,OAAO4N,SAASN,QAClB,MAAOA,QAAOrlB,MAEhB,IAA2B,mBAAhB2kB,cAA6D,kBAAvBA,aAAYsB,SACxDtB,YAAYsB,OAAOZ,SAAWA,iBAAkBV,cACnD,MAAOU,QAAOrB,UAEM,iBAAXqB,UACTA,OAAS,GAAKA,OAGhB,IAAIO,KAAMP,OAAOrlB,MACjB,IAAY,IAAR4lB,IAAW,MAAO,EAGtB,IAAIM,cAAc,CAClB,QACE,OAAQf,UACN,IAAK,QACL,IAAK,SACL,IAAK,MACL,IAAK,OACH,MAAOS,IACT,KAAK,OACL,IAAK,QACL,IAAK9nB,QACH,MAAOqoB,aAAYd,QAAQrlB,MAC7B,KAAK,OACL,IAAK,QACL,IAAK,UACL,IAAK,WACH,MAAa,GAAN4lB,GACT,KAAK,MACH,MAAOA,OAAQ,CACjB,KAAK,SACH,MAAOQ,eAAcf,QAAQrlB,MAC/B,SACE,GAAIkmB,YAAa,MAAOC,aAAYd,QAAQrlB,MAC5CmlB,WAAY,GAAKA,UAAU3Q,cAC3B0R,aAAc,GAMtB,QAASG,cAAclB,SAAU3jB,MAAO8kB,KACtC,GAAIJ,cAAc,CAclB,KALcpoB,SAAV0D,OAAuBA,MAAQ,KACjCA,MAAQ,GAINA,MAAQ3B,KAAKG,OACf,MAAO,EAOT,KAJYlC,SAARwoB,KAAqBA,IAAMzmB,KAAKG,UAClCsmB,IAAMzmB,KAAKG,QAGTsmB,KAAO,EACT,MAAO,EAOT,IAHAA,OAAS,EACT9kB,SAAW,EAEP8kB,KAAO9kB,MACT,MAAO,EAKT,KAFK2jB,WAAUA,SAAW,UAGxB,OAAQA,UACN,IAAK,MACH,MAAOoB,UAAS1mB,KAAM2B,MAAO8kB,IAE/B,KAAK,OACL,IAAK,QACH,MAAOE,WAAU3mB,KAAM2B,MAAO8kB,IAEhC,KAAK,QACH,MAAOG,YAAW5mB,KAAM2B,MAAO8kB,IAEjC,KAAK,SACH,MAAOI,aAAY7mB,KAAM2B,MAAO8kB,IAElC,KAAK,SACH,MAAOK,aAAY9mB,KAAM2B,MAAO8kB,IAElC,KAAK,OACL,IAAK,QACL,IAAK,UACL,IAAK,WACH,MAAOM,cAAa/mB,KAAM2B,MAAO8kB,IAEnC,SACE,GAAIJ,YAAa,KAAM,IAAIxB,WAAU,qBAAuBS,SAC5DA,WAAYA,SAAW,IAAI3Q,cAC3B0R,aAAc,GAStB,QAASW,MAAM5U,EAAG6U,EAAGC,GACnB,GAAIjZ,GAAImE,EAAE6U,EACV7U,GAAE6U,GAAK7U,EAAE8U,GACT9U,EAAE8U,GAAKjZ,EA4GT,QAASkZ,cAAczkB,IAAKrC,IAAKwlB,WAAYP,UAmB3C,QAAS8B,MAAMC,IAAKpZ,GAClB,MAAkB,KAAdqZ,UACKD,IAAIpZ,GAEJoZ,IAAIE,aAAatZ,EAAIqZ,WAtBhC,GAAIA,WAAY,CAChB,IAAIE,WAAY9kB,IAAIvC,MACpB,IAAIsnB,WAAYpnB,IAAIF,MAEpB,IAAiBlC,SAAbqnB,WACFA,SAAWpnB,OAAOonB,UAAU3Q,cACX,SAAb2Q,UAAoC,UAAbA,UACV,YAAbA,UAAuC,aAAbA,UAAyB,CACrD,GAAI5iB,IAAIvC,OAAS,GAAKE,IAAIF,OAAS,EACjC,OAAO,CAETmnB,WAAY,EACZE,WAAa,EACbC,WAAa,EACb5B,YAAc,EAYlB,GAAI6B,aAAa,CACjB,KAAK,GAAIzZ,GAAI4X,WAAY5X,EAAIuZ,YAAavZ,EACxC,GAAImZ,KAAK1kB,IAAKuL,KAAOmZ,KAAK/mB,IAAKqnB,cAAe,EAAK,EAAIzZ,EAAIyZ,aAEzD,GADIA,cAAe,IAAIA,WAAazZ,GAChCA,EAAIyZ,WAAa,IAAMD,UAAW,MAAOC,YAAaJ,cAEtDI,eAAe,IAAIzZ,GAAKA,EAAIyZ,YAChCA,YAAa,CAIjB,QAAO,EA6CT,QAASC,UAAUN,IAAK7B,OAAQoC,OAAQznB,QACtCynB,OAASC,OAAOD,SAAW,CAC3B,IAAIE,WAAYT,IAAIlnB,OAASynB,MACxBznB,SAGHA,OAAS0nB,OAAO1nB,QACZA,OAAS2nB,YACX3nB,OAAS2nB,YAJX3nB,OAAS2nB,SASX,IAAIC,QAASvC,OAAOrlB,MACpB,IAAI4nB,OAAS,IAAM,EAAG,KAAM,IAAItb,OAAM,qBAElCtM,QAAS4nB,OAAS,IACpB5nB,OAAS4nB,OAAS,EAEpB,KAAK,GAAI9Z,GAAI,EAAGA,EAAI9N,SAAU8N,EAAG,CAC/B,GAAI+Z,QAASC,SAASzC,OAAO0C,OAAW,EAAJja,EAAO,GAAI,GAC/C,IAAIka,MAAMH,QAAS,MAAO/Z,EAC1BoZ,KAAIO,OAAS3Z,GAAK+Z,OAEpB,MAAO/Z,GAGT,QAASma,WAAWf,IAAK7B,OAAQoC,OAAQznB,QACvC,MAAOkoB,YAAW/B,YAAYd,OAAQ6B,IAAIlnB,OAASynB,QAASP,IAAKO,OAAQznB,QAG3E,QAASmoB,YAAYjB,IAAK7B,OAAQoC,OAAQznB,QACxC,MAAOkoB,YAAWE,aAAa/C,QAAS6B,IAAKO,OAAQznB,QAGvD,QAASqoB,aAAanB,IAAK7B,OAAQoC,OAAQznB,QACzC,MAAOmoB,YAAWjB,IAAK7B,OAAQoC,OAAQznB,QAGzC,QAASsoB,aAAapB,IAAK7B,OAAQoC,OAAQznB,QACzC,MAAOkoB,YAAW9B,cAAcf,QAAS6B,IAAKO,OAAQznB,QAGxD,QAASuoB,WAAWrB,IAAK7B,OAAQoC,OAAQznB,QACvC,MAAOkoB,YAAWM,eAAenD,OAAQ6B,IAAIlnB,OAASynB,QAASP,IAAKO,OAAQznB,QAiF9E,QAAS2mB,aAAaO,IAAK1lB,MAAO8kB,KAChC,MAAc,KAAV9kB,OAAe8kB,MAAQY,IAAIlnB,OACtByoB,OAAOC,cAAcxB,KAErBuB,OAAOC,cAAcxB,IAAInmB,MAAMS,MAAO8kB,MAIjD,QAASE,WAAWU,IAAK1lB,MAAO8kB,KAC9BA,IAAMqC,KAAKC,IAAI1B,IAAIlnB,OAAQsmB,IAC3B,IAAI9oB,OAEJ,IAAIsQ,GAAItM,KACR,MAAOsM,EAAIwY,KAAK,CACd,GAAIuC,WAAY3B,IAAIpZ,EACpB,IAAIgb,WAAY,IAChB,IAAIC,kBAAoBF,UAAY,IAAQ,EACvCA,UAAY,IAAQ,EACpBA,UAAY,IAAQ,EACrB,CAEJ,IAAI/a,EAAIib,kBAAoBzC,IAAK,CAC/B,GAAI0C,YAAYC,UAAWC,WAAYC,aAEvC,QAAQJ,kBACN,IAAK,GACCF,UAAY,MACdC,UAAYD,UAEd,MACF,KAAK,GACHG,WAAa9B,IAAIpZ,EAAI,GACO,OAAV,IAAbkb,cACHG,eAA6B,GAAZN,YAAqB,EAAoB,GAAbG,WACzCG,cAAgB,MAClBL,UAAYK,eAGhB,MACF,KAAK,GACHH,WAAa9B,IAAIpZ,EAAI,GACrBmb,UAAY/B,IAAIpZ,EAAI,GACQ,OAAV,IAAbkb,aAAsD,OAAV,IAAZC,aACnCE,eAA6B,GAAZN,YAAoB,IAAoB,GAAbG,aAAsB,EAAmB,GAAZC,UACrEE,cAAgB,OAAUA,cAAgB,OAAUA,cAAgB,SACtEL,UAAYK,eAGhB,MACF,KAAK,GACHH,WAAa9B,IAAIpZ,EAAI,GACrBmb,UAAY/B,IAAIpZ,EAAI,GACpBob,WAAahC,IAAIpZ,EAAI,GACO,OAAV,IAAbkb,aAAsD,OAAV,IAAZC,YAAsD,OAAV,IAAbC,cAClEC,eAA6B,GAAZN,YAAoB,IAAqB,GAAbG,aAAsB,IAAmB,GAAZC,YAAqB,EAAoB,GAAbC,WAClGC,cAAgB,OAAUA,cAAgB,UAC5CL,UAAYK,iBAMJ,OAAdL,WAGFA,UAAY,MACZC,iBAAmB,GACVD,UAAY,QAErBA,WAAa,MACbtrB,IAAIgB,KAAKsqB,YAAc,GAAK,KAAQ,OACpCA,UAAY,MAAqB,KAAZA,WAGvBtrB,IAAIgB,KAAKsqB,WACThb,GAAKib,iBAGP,MAAOK,uBAAsB5rB,KAQ/B,QAAS4rB,uBAAuBC,YAC9B,GAAIzD,KAAMyD,WAAWrpB,MACrB,IAAI4lB,KAAO0D,qBACT,MAAOvrB,QAAOwrB,aAAavoB,MAAMjD,OAAQsrB,WAI3C,IAAI7rB,KAAM,EACV,IAAIsQ,GAAI,CACR,MAAOA,EAAI8X,KACTpoB,KAAOO,OAAOwrB,aAAavoB,MACzBjD,OACAsrB,WAAWtoB,MAAM+M,EAAGA,GAAKwb,sBAG7B,OAAO9rB,KAGT,QAASipB,YAAYS,IAAK1lB,MAAO8kB,KAC/B,GAAIkD,KAAM,EACVlD,KAAMqC,KAAKC,IAAI1B,IAAIlnB,OAAQsmB,IAE3B,KAAK,GAAIxY,GAAItM,MAAOsM,EAAIwY,MAAOxY,EAC7B0b,KAAOzrB,OAAOwrB,aAAsB,IAATrC,IAAIpZ,GAEjC,OAAO0b,KAGT,QAAS9C,aAAaQ,IAAK1lB,MAAO8kB,KAChC,GAAIkD,KAAM,EACVlD,KAAMqC,KAAKC,IAAI1B,IAAIlnB,OAAQsmB,IAE3B,KAAK,GAAIxY,GAAItM,MAAOsM,EAAIwY,MAAOxY,EAC7B0b,KAAOzrB,OAAOwrB,aAAarC,IAAIpZ,GAEjC,OAAO0b,KAGT,QAASjD,UAAUW,IAAK1lB,MAAO8kB,KAC7B,GAAIV,KAAMsB,IAAIlnB,SAETwB,OAASA,MAAQ,KAAGA,MAAQ,KAC5B8kB,KAAOA,IAAM,GAAKA,IAAMV,OAAKU,IAAMV,IAExC,IAAI6D,KAAM,EACV,KAAK,GAAI3b,GAAItM,MAAOsM,EAAIwY,MAAOxY,EAC7B2b,KAAOC,MAAMxC,IAAIpZ,GAEnB,OAAO2b,KAGT,QAAS7C,cAAcM,IAAK1lB,MAAO8kB,KACjC,GAAIqD,OAAQzC,IAAInmB,MAAMS,MAAO8kB,IAC7B,IAAI9oB,KAAM,EACV,KAAK,GAAIsQ,GAAI,EAAGA,EAAI6b,MAAM3pB,OAAQ8N,GAAK,EACrCtQ,KAAOO,OAAOwrB,aAAaI,MAAM7b,GAAoB,IAAf6b,MAAM7b,EAAI,GAElD,OAAOtQ,KA0CT,QAASosB,aAAanC,OAAQrI,IAAKpf,QACjC,GAAKynB,OAAS,IAAO,GAAKA,OAAS,EAAG,KAAM,IAAInD,YAAW,qBAC3D,IAAImD,OAASrI,IAAMpf,OAAQ,KAAM,IAAIskB,YAAW,yCA+JlD,QAASuF,UAAU3C,IAAK9oB,MAAOqpB,OAAQrI,IAAK0K,IAAKlB,KAC/C,IAAK7Q,OAAO4N,SAASuB,KAAM,KAAM,IAAIxC,WAAU,8CAC/C,IAAItmB,MAAQ0rB,KAAO1rB,MAAQwqB,IAAK,KAAM,IAAItE,YAAW,oCACrD,IAAImD,OAASrI,IAAM8H,IAAIlnB,OAAQ,KAAM,IAAIskB,YAAW,sBAkDtD,QAASyF,mBAAmB7C,IAAK9oB,MAAOqpB,OAAQuC,cAC1C5rB,MAAQ,IAAGA,MAAQ,MAASA,MAAQ,EACxC,KAAK,GAAI0P,GAAI,EAAGrH,EAAIkiB,KAAKC,IAAI1B,IAAIlnB,OAASynB,OAAQ,GAAI3Z,EAAIrH,IAAKqH,EAC7DoZ,IAAIO,OAAS3Z,IAAM1P,MAAS,KAAS,GAAK4rB,aAAelc,EAAI,EAAIA,MAClC,GAA5Bkc,aAAelc,EAAI,EAAIA,GA8B9B,QAASmc,mBAAmB/C,IAAK9oB,MAAOqpB,OAAQuC,cAC1C5rB,MAAQ,IAAGA,MAAQ,WAAaA,MAAQ,EAC5C,KAAK,GAAI0P,GAAI,EAAGrH,EAAIkiB,KAAKC,IAAI1B,IAAIlnB,OAASynB,OAAQ,GAAI3Z,EAAIrH,IAAKqH,EAC7DoZ,IAAIO,OAAS3Z,GAAM1P,QAAuC,GAA5B4rB,aAAelc,EAAI,EAAIA,GAAU,IAmJnE,QAASoc,cAAchD,IAAK9oB,MAAOqpB,OAAQrI,IAAK0K,IAAKlB,KACnD,GAAInB,OAASrI,IAAM8H,IAAIlnB,OAAQ,KAAM,IAAIskB,YAAW,qBACpD,IAAImD,OAAS,EAAG,KAAM,IAAInD,YAAW,sBAGvC,QAAS6F,YAAYjD,IAAK9oB,MAAOqpB,OAAQuC,aAAcI,UAKrD,MAJKA,WACHF,aAAahD,IAAK9oB,MAAOqpB,OAAQ,EAAG,uBAAwB,uBAE9D4C,QAAQ9E,MAAM2B,IAAK9oB,MAAOqpB,OAAQuC,aAAc,GAAI,GAC7CvC,OAAS,EAWlB,QAAS6C,aAAapD,IAAK9oB,MAAOqpB,OAAQuC,aAAcI,UAKtD,MAJKA,WACHF,aAAahD,IAAK9oB,MAAOqpB,OAAQ,EAAG,wBAAyB,wBAE/D4C,QAAQ9E,MAAM2B,IAAK9oB,MAAOqpB,OAAQuC,aAAc,GAAI,GAC7CvC,OAAS,EAgIlB,QAAS8C,aAAaC,KAIpB,GAFAA,IAAMC,WAAWD,KAAK/mB,QAAQinB,kBAAmB,IAE7CF,IAAIxqB,OAAS,EAAG,MAAO,EAE3B,MAAOwqB,IAAIxqB,OAAS,IAAM,GACxBwqB,KAAY,GAEd,OAAOA,KAGT,QAASC,YAAYD,KACnB,MAAIA,KAAIlsB,KAAaksB,IAAIlsB,OAClBksB,IAAI/mB,QAAQ,aAAc,IAGnC,QAASimB,OAAO5C,GACd,MAAIA,GAAI,GAAW,IAAMA,EAAEpO,SAAS,IAC7BoO,EAAEpO,SAAS,IAGpB,QAASyN,aAAad,OAAQsF,OAC5BA,MAAQA,OAASC,EAAAA,CACjB,IAAI9B,UACJ,IAAI9oB,QAASqlB,OAAOrlB,MACpB,IAAI6qB,eAAgB,IACpB,IAAIlB,SAEJ,KAAK,GAAI7b,GAAI,EAAGA,EAAI9N,SAAU8N,EAAG,CAI/B,GAHAgb,UAAYzD,OAAOyF,WAAWhd,GAG1Bgb,UAAY,OAAUA,UAAY,MAAQ,CAE5C,IAAK+B,cAAe,CAElB,GAAI/B,UAAY,MAAQ,EAEjB6B,OAAS,IAAK,GAAIhB,MAAMnrB,KAAK,IAAM,IAAM,IAC9C,UACK,GAAIsP,EAAI,IAAM9N,OAAQ,EAEtB2qB,OAAS,IAAK,GAAIhB,MAAMnrB,KAAK,IAAM,IAAM,IAC9C,UAIFqsB,cAAgB/B,SAEhB,UAIF,GAAIA,UAAY,MAAQ,EACjB6B,OAAS,IAAK,GAAIhB,MAAMnrB,KAAK,IAAM,IAAM,KAC9CqsB,cAAgB/B,SAChB,UAIFA,WAAa+B,cAAgB,OAAU,GAAK/B,UAAY,OAAU,UACzD+B,iBAEJF,OAAS,IAAK,GAAIhB,MAAMnrB,KAAK,IAAM,IAAM,IAMhD,IAHAqsB,cAAgB,KAGZ/B,UAAY,IAAM,CACpB,IAAK6B,OAAS,GAAK,EAAG,KACtBhB,OAAMnrB,KAAKsqB,eACN,IAAIA,UAAY,KAAO,CAC5B,IAAK6B,OAAS,GAAK,EAAG,KACtBhB,OAAMnrB,KACJsqB,WAAa,EAAM,IACP,GAAZA,UAAmB,SAEhB,IAAIA,UAAY,MAAS,CAC9B,IAAK6B,OAAS,GAAK,EAAG,KACtBhB,OAAMnrB,KACJsqB,WAAa,GAAM,IACnBA,WAAa,EAAM,GAAO,IACd,GAAZA,UAAmB,SAEhB,CAAA,KAAIA,UAAY,SASrB,KAAM,IAAIxc,OAAM,qBARhB,KAAKqe,OAAS,GAAK,EAAG,KACtBhB,OAAMnrB,KACJsqB,WAAa,GAAO,IACpBA,WAAa,GAAM,GAAO,IAC1BA,WAAa,EAAM,GAAO,IACd,GAAZA,UAAmB,MAOzB,MAAOa,OAGT,QAASvB,cAAcoC,KACrB,GAAIO,aACJ,KAAK,GAAIjd,GAAI,EAAGA,EAAI0c,IAAIxqB,SAAU8N,EAEhCid,UAAUvsB,KAAyB,IAApBgsB,IAAIM,WAAWhd,GAEhC,OAAOid,WAGT,QAASvC,gBAAgBgC,IAAKG,OAC5B,GAAIK,GAAGC,GAAIC,EACX,IAAIH,aACJ,KAAK,GAAIjd,GAAI,EAAGA,EAAI0c,IAAIxqB,WACjB2qB,OAAS,GAAK,KADa7c,EAGhCkd,EAAIR,IAAIM,WAAWhd,GACnBmd,GAAKD,GAAK,EACVE,GAAKF,EAAI,IACTD,UAAUvsB,KAAK0sB,IACfH,UAAUvsB,KAAKysB,GAGjB,OAAOF,WAGT,QAAS3E,eAAeoE,KACtB,MAAO/B,QAAO0C,YAAYZ,YAAYC,MAGxC,QAAStC,YAAYkD,IAAKC,IAAK5D,OAAQznB,QACrC,IAAK,GAAI8N,GAAI,EAAGA,EAAI9N,UACb8N,EAAI2Z,QAAU4D,IAAIrrB,QAAY8N,GAAKsd,IAAIprB,UADhB8N,EAE5Bud,IAAIvd,EAAI2Z,QAAU2D,IAAItd,EAExB,OAAOA,GAGT,QAASiY,OAAO7lB,KACd,MAAOA,OAAQA,IArqDjB,GAAIuoB,QAASjuB,QAAQ,YACrB,IAAI6vB,SAAU7vB,QAAQ,UACtB,IAAIoE,SAAUpE,QAAQ,UAEtBiC,SAAQsb,OAASA,OACjBtb,QAAQupB,WAAaA,WACrBvpB,QAAQ6uB,kBAAoB,GA0B5BvT,OAAOoM,oBAAqDrmB,SAA/BvB,OAAO4nB,oBAChC5nB,OAAO4nB,oBACPR,oBAKJlnB,QAAQynB,WAAaA,aAkErBnM,OAAOwT,SAAW,KAGlBxT,OAAOyT,SAAW,SAAUjpB,KAE1B,MADAA,KAAIshB,UAAY9L,OAAOjX,UAChByB,KA2BTwV,OAAO0M,KAAO,SAAUrmB,MAAOmmB,iBAAkBvkB,QAC/C,MAAOykB,MAAK,KAAMrmB,MAAOmmB,iBAAkBvkB,SAGzC+X,OAAOoM,sBACTpM,OAAOjX,UAAU+iB,UAAYD,WAAW9iB,UACxCiX,OAAO8L,UAAYD,WACG,mBAAX6H,SAA0BA,OAAOC,SACxC3T,OAAO0T,OAAOC,WAAa3T,QAE7BV,OAAOsU,eAAe5T,OAAQ0T,OAAOC,SACnCttB,MAAO,KACPwtB,cAAc,KA+BpB7T,OAAOkN,MAAQ,SAAUD,KAAME,KAAMC,UACnC,MAAOF,OAAM,KAAMD,KAAME,KAAMC,WAiBjCpN,OAAOyM,YAAc,SAAUQ,MAC7B,MAAOR,aAAY,KAAMQ,OAK3BjN,OAAO8T,gBAAkB,SAAU7G,MACjC,MAAOR,aAAY,KAAMQ,OAyG3BjN,OAAO4N,SAAW,SAAmB1T,GACnC,QAAe,MAALA,IAAaA,EAAE6Z,YAG3B/T,OAAOgU,QAAU,SAAkB/Z,EAAGC,GACpC,IAAK8F,OAAO4N,SAAS3T,KAAO+F,OAAO4N,SAAS1T,GAC1C,KAAM,IAAIyS,WAAU,4BAGtB,IAAI1S,IAAMC,EAAG,MAAO,EAEpB,IAAI+Z,GAAIha,EAAEhS,MACV,IAAIisB,GAAIha,EAAEjS,MAEV,KAAK,GAAI8N,GAAI,EAAG8X,IAAM+C,KAAKC,IAAIoD,EAAGC,GAAIne,EAAI8X,MAAO9X,EAC/C,GAAIkE,EAAElE,KAAOmE,EAAEnE,GAAI,CACjBke,EAAIha,EAAElE,GACNme,EAAIha,EAAEnE,EACN,OAIJ,MAAIke,GAAIC,GAAU,EACdA,EAAID,EAAU,EACX,GAGTjU,OAAOuN,WAAa,SAAqBH,UACvC,OAAQpnB,OAAOonB,UAAU3Q,eACvB,IAAK,MACL,IAAK,OACL,IAAK,QACL,IAAK,QACL,IAAK,SACL,IAAK,SACL,IAAK,MACL,IAAK,OACL,IAAK,QACL,IAAK,UACL,IAAK,WACH,OAAO,CACT,SACE,OAAO,IAIbuD,OAAOjW,OAAS,SAAiBnB,KAAMX,QACrC,IAAKpB,QAAQ+B,MACX,KAAM,IAAI+jB,WAAU,8CAGtB,IAAoB,IAAhB/jB,KAAKX,OACP,MAAO+X,QAAOkN,MAAM,EAGtB,IAAInX,EACJ,IAAehQ,SAAXkC,OAEF,IADAA,OAAS,EACJ8N,EAAI,EAAGA,EAAInN,KAAKX,SAAU8N,EAC7B9N,QAAUW,KAAKmN,GAAG9N,MAItB,IAAI8lB,QAAS/N,OAAOyM,YAAYxkB,OAChC,IAAIksB,KAAM,CACV,KAAKpe,EAAI,EAAGA,EAAInN,KAAKX,SAAU8N,EAAG,CAChC,GAAIoZ,KAAMvmB,KAAKmN,EACf,KAAKiK,OAAO4N,SAASuB,KACnB,KAAM,IAAIxC,WAAU,8CAEtBwC,KAAIrB,KAAKC,OAAQoG,KACjBA,KAAOhF,IAAIlnB,OAEb,MAAO8lB,SA+CT/N,OAAOiM,WAAaA,WAyEpBjM,OAAOjX,UAAUgrB,WAAY,EAQ7B/T,OAAOjX,UAAUqrB,OAAS,WACxB,GAAIvG,KAAM/lB,KAAKG,MACf,IAAI4lB,IAAM,IAAM,EACd,KAAM,IAAItB,YAAW,4CAEvB,KAAK,GAAIxW,GAAI,EAAGA,EAAI8X,IAAK9X,GAAK,EAC5B+Y,KAAKhnB,KAAMiO,EAAGA,EAAI,EAEpB,OAAOjO,OAGTkY,OAAOjX,UAAUsrB,OAAS,WACxB,GAAIxG,KAAM/lB,KAAKG,MACf,IAAI4lB,IAAM,IAAM,EACd,KAAM,IAAItB,YAAW,4CAEvB,KAAK,GAAIxW,GAAI,EAAGA,EAAI8X,IAAK9X,GAAK,EAC5B+Y,KAAKhnB,KAAMiO,EAAGA,EAAI,GAClB+Y,KAAKhnB,KAAMiO,EAAI,EAAGA,EAAI,EAExB,OAAOjO,OAGTkY,OAAOjX,UAAU4X,SAAW,WAC1B,GAAI1Y,QAAuB,EAAdH,KAAKG,MAClB,OAAe,KAAXA,OAAqB,GACA,IAArBiB,UAAUjB,OAAqBwmB,UAAU3mB,KAAM,EAAGG,QAC/CqmB,aAAarlB,MAAMnB,KAAMoB,YAGlC8W,OAAOjX,UAAUurB,OAAS,SAAiBpa,GACzC,IAAK8F,OAAO4N,SAAS1T,GAAI,KAAM,IAAIyS,WAAU,4BAC7C,OAAI7kB,QAASoS,GACsB,IAA5B8F,OAAOgU,QAAQlsB,KAAMoS,IAG9B8F,OAAOjX,UAAUwrB,QAAU,WACzB,GAAI9B,KAAM,EACV,IAAIV,KAAMrtB,QAAQ6uB,iBAKlB,OAJIzrB,MAAKG,OAAS,IAChBwqB,IAAM3qB,KAAK6Y,SAAS,MAAO,EAAGoR,KAAKyC,MAAM,SAAS7tB,KAAK,KACnDmB,KAAKG,OAAS8pB,MAAKU,KAAO,UAEzB,WAAaA,IAAM,KAG5BzS,OAAOjX,UAAUirB,QAAU,SAAkBS,OAAQhrB,MAAO8kB,IAAKmG,UAAWC,SAC1E,IAAK3U,OAAO4N,SAAS6G,QACnB,KAAM,IAAI9H,WAAU,4BAgBtB,IAbc5mB,SAAV0D,QACFA,MAAQ,GAEE1D,SAARwoB,MACFA,IAAMkG,OAASA,OAAOxsB,OAAS,GAEflC,SAAd2uB,YACFA,UAAY,GAEE3uB,SAAZ4uB,UACFA,QAAU7sB,KAAKG,QAGbwB,MAAQ,GAAK8kB,IAAMkG,OAAOxsB,QAAUysB,UAAY,GAAKC,QAAU7sB,KAAKG,OACtE,KAAM,IAAIskB,YAAW,qBAGvB,IAAImI,WAAaC,SAAWlrB,OAAS8kB,IACnC,MAAO,EAET,IAAImG,WAAaC,QACf,OAAO,CAET,IAAIlrB,OAAS8kB,IACX,MAAO,EAQT,IALA9kB,SAAW,EACX8kB,OAAS,EACTmG,aAAe,EACfC,WAAa,EAET7sB,OAAS2sB,OAAQ,MAAO,EAE5B,IAAIR,GAAIU,QAAUD,SAClB,IAAIR,GAAI3F,IAAM9kB,KACd,IAAIokB,KAAM+C,KAAKC,IAAIoD,EAAGC,EAEtB,IAAIU,UAAW9sB,KAAKkB,MAAM0rB,UAAWC,QACrC,IAAIE,YAAaJ,OAAOzrB,MAAMS,MAAO8kB,IAErC,KAAK,GAAIxY,GAAI,EAAGA,EAAI8X,MAAO9X,EACzB,GAAI6e,SAAS7e,KAAO8e,WAAW9e,GAAI,CACjCke,EAAIW,SAAS7e,GACbme,EAAIW,WAAW9e,EACf,OAIJ,MAAIke,GAAIC,GAAU,EACdA,EAAID,EAAU,EACX,GA4CTjU,OAAOjX,UAAUtB,QAAU,SAAkBU,IAAKwlB,WAAYP,UAW5D,GAV0B,gBAAfO,aACTP,SAAWO,WACXA,WAAa,GACJA,WAAa,WACtBA,WAAa,WACJA,YAAa,aACtBA,YAAa,YAEfA,aAAe,EAEK,IAAhB7lB,KAAKG,OAAc,OAAO,CAC9B,IAAI0lB,YAAc7lB,KAAKG,OAAQ,OAAO,CAStC,IANI0lB,WAAa,IAAGA,WAAaiD,KAAKmB,IAAIjqB,KAAKG,OAAS0lB,WAAY,IAEjD,gBAARxlB,OACTA,IAAM6X,OAAO0M,KAAKvkB,IAAKilB,WAGrBpN,OAAO4N,SAASzlB,KAElB,MAAmB,KAAfA,IAAIF,QACC,EAEFgnB,aAAannB,KAAMK,IAAKwlB,WAAYP,SAE7C,IAAmB,gBAARjlB,KACT,MAAI6X,QAAOoM,qBAAwD,aAAjCP,WAAW9iB,UAAUtB,QAC9CokB,WAAW9iB,UAAUtB,QAAQ+G,KAAK1G,KAAMK,IAAKwlB,YAE/CsB,aAAannB,MAAQK,KAAOwlB,WAAYP,SAGjD,MAAM,IAAIT,WAAU,yCAGtB3M,OAAOjX,UAAU+rB,SAAW,SAAmB3sB,IAAKwlB,WAAYP,UAC9D,MAAOtlB,MAAKL,QAAQU,IAAKwlB,WAAYP,aAAc,GAkDrDpN,OAAOjX,UAAUykB,MAAQ,SAAgBF,OAAQoC,OAAQznB,OAAQmlB,UAE/D,GAAernB,SAAX2pB,OACFtC,SAAW,OACXnlB,OAASH,KAAKG,OACdynB,OAAS,MAEJ,IAAe3pB,SAAXkC,QAA0C,gBAAXynB,QACxCtC,SAAWsC,OACXznB,OAASH,KAAKG,OACdynB,OAAS,MAEJ,CAAA,IAAIqF,SAASrF,QAWlB,KAAM,IAAInb,OACR,0EAXFmb,QAAkB,EAATA,OACLqF,SAAS9sB,SACXA,OAAkB,EAATA,OACQlC,SAAbqnB,WAAwBA,SAAW,UAEvCA,SAAWnlB,OACXA,OAASlC,QASb,GAAI6pB,WAAY9nB,KAAKG,OAASynB,MAG9B,KAFe3pB,SAAXkC,QAAwBA,OAAS2nB,aAAW3nB,OAAS2nB,WAEpDtC,OAAOrlB,OAAS,IAAMA,OAAS,GAAKynB,OAAS,IAAOA,OAAS5nB,KAAKG,OACrE,KAAM,IAAIskB,YAAW,yCAGlBa,YAAUA,SAAW,OAE1B,IAAIe,cAAc,CAClB,QACE,OAAQf,UACN,IAAK,MACH,MAAOqC,UAAS3nB,KAAMwlB,OAAQoC,OAAQznB,OAExC,KAAK,OACL,IAAK,QACH,MAAOioB,WAAUpoB,KAAMwlB,OAAQoC,OAAQznB,OAEzC,KAAK,QACH,MAAOmoB,YAAWtoB,KAAMwlB,OAAQoC,OAAQznB,OAE1C,KAAK,SACH,MAAOqoB,aAAYxoB,KAAMwlB,OAAQoC,OAAQznB,OAE3C,KAAK,SAEH,MAAOsoB,aAAYzoB,KAAMwlB,OAAQoC,OAAQznB,OAE3C,KAAK,OACL,IAAK,QACL,IAAK,UACL,IAAK,WACH,MAAOuoB,WAAU1oB,KAAMwlB,OAAQoC,OAAQznB,OAEzC,SACE,GAAIkmB,YAAa,KAAM,IAAIxB,WAAU,qBAAuBS,SAC5DA,WAAY,GAAKA,UAAU3Q,cAC3B0R,aAAc,IAKtBnO,OAAOjX,UAAUisB,OAAS,WACxB,OACE/kB,KAAM,SACNxE,KAAM3C,MAAMC,UAAUC,MAAMwF,KAAK1G,KAAKmtB,MAAQntB,KAAM,IAwFxD,IAAIypB,sBAAuB,IA8D3BvR,QAAOjX,UAAUC,MAAQ,SAAgBS,MAAO8kB,KAC9C,GAAIV,KAAM/lB,KAAKG,MACfwB,SAAUA,MACV8kB,IAAcxoB,SAARwoB,IAAoBV,MAAQU,IAE9B9kB,MAAQ,GACVA,OAASokB,IACLpkB,MAAQ,IAAGA,MAAQ,IACdA,MAAQokB,MACjBpkB,MAAQokB,KAGNU,IAAM,GACRA,KAAOV,IACHU,IAAM,IAAGA,IAAM,IACVA,IAAMV,MACfU,IAAMV,KAGJU,IAAM9kB,QAAO8kB,IAAM9kB,MAEvB,IAAIyrB,OACJ,IAAIlV,OAAOoM,oBACT8I,OAASptB,KAAKkkB,SAASviB,MAAO8kB,KAC9B2G,OAAOpJ,UAAY9L,OAAOjX,cACrB,CACL,GAAIosB,UAAW5G,IAAM9kB,KACrByrB,QAAS,GAAIlV,QAAOmV,SAAUpvB,OAC9B,KAAK,GAAIgQ,GAAI,EAAGA,EAAIof,WAAYpf,EAC9Bmf,OAAOnf,GAAKjO,KAAKiO,EAAItM,OAIzB,MAAOyrB,SAWTlV,OAAOjX,UAAUqsB,WAAa,SAAqB1F,OAAQzD,WAAYoG,UACrE3C,OAAkB,EAATA,OACTzD,WAA0B,EAAbA,WACRoG,UAAUR,YAAYnC,OAAQzD,WAAYnkB,KAAKG,OAEpD,IAAIE,KAAML,KAAK4nB,OACf,IAAI2F,KAAM,CACV,IAAItf,GAAI,CACR,QAASA,EAAIkW,aAAeoJ,KAAO,MACjCltB,KAAOL,KAAK4nB,OAAS3Z,GAAKsf,GAG5B,OAAOltB,MAGT6X,OAAOjX,UAAUusB,WAAa,SAAqB5F,OAAQzD,WAAYoG,UACrE3C,OAAkB,EAATA,OACTzD,WAA0B,EAAbA,WACRoG,UACHR,YAAYnC,OAAQzD,WAAYnkB,KAAKG,OAGvC,IAAIE,KAAML,KAAK4nB,SAAWzD,WAC1B,IAAIoJ,KAAM,CACV,MAAOpJ,WAAa,IAAMoJ,KAAO,MAC/BltB,KAAOL,KAAK4nB,SAAWzD,YAAcoJ,GAGvC,OAAOltB,MAGT6X,OAAOjX,UAAUwsB,UAAY,SAAoB7F,OAAQ2C,UAEvD,MADKA,WAAUR,YAAYnC,OAAQ,EAAG5nB,KAAKG,QACpCH,KAAK4nB,SAGd1P,OAAOjX,UAAUysB,aAAe,SAAuB9F,OAAQ2C,UAE7D,MADKA,WAAUR,YAAYnC,OAAQ,EAAG5nB,KAAKG,QACpCH,KAAK4nB,QAAW5nB,KAAK4nB,OAAS,IAAM,GAG7C1P,OAAOjX,UAAUsmB,aAAe,SAAuBK,OAAQ2C,UAE7D,MADKA,WAAUR,YAAYnC,OAAQ,EAAG5nB,KAAKG,QACnCH,KAAK4nB,SAAW,EAAK5nB,KAAK4nB,OAAS,IAG7C1P,OAAOjX,UAAU0sB,aAAe,SAAuB/F,OAAQ2C,UAG7D,MAFKA,WAAUR,YAAYnC,OAAQ,EAAG5nB,KAAKG,SAElCH,KAAK4nB,QACT5nB,KAAK4nB,OAAS,IAAM,EACpB5nB,KAAK4nB,OAAS,IAAM,IACD,SAAnB5nB,KAAK4nB,OAAS,IAGrB1P,OAAOjX,UAAU2sB,aAAe,SAAuBhG,OAAQ2C,UAG7D,MAFKA,WAAUR,YAAYnC,OAAQ,EAAG5nB,KAAKG,QAEpB,SAAfH,KAAK4nB,SACT5nB,KAAK4nB,OAAS,IAAM,GACrB5nB,KAAK4nB,OAAS,IAAM,EACrB5nB,KAAK4nB,OAAS,KAGlB1P,OAAOjX,UAAU4sB,UAAY,SAAoBjG,OAAQzD,WAAYoG,UACnE3C,OAAkB,EAATA,OACTzD,WAA0B,EAAbA,WACRoG,UAAUR,YAAYnC,OAAQzD,WAAYnkB,KAAKG,OAEpD,IAAIE,KAAML,KAAK4nB,OACf,IAAI2F,KAAM,CACV,IAAItf,GAAI,CACR,QAASA,EAAIkW,aAAeoJ,KAAO,MACjCltB,KAAOL,KAAK4nB,OAAS3Z,GAAKsf,GAM5B,OAJAA,MAAO,IAEHltB,KAAOktB,MAAKltB,KAAOyoB,KAAKgF,IAAI,EAAG,EAAI3J,aAEhC9jB,KAGT6X,OAAOjX,UAAU8sB,UAAY,SAAoBnG,OAAQzD,WAAYoG,UACnE3C,OAAkB,EAATA,OACTzD,WAA0B,EAAbA,WACRoG,UAAUR,YAAYnC,OAAQzD,WAAYnkB,KAAKG,OAEpD,IAAI8N,GAAIkW,UACR,IAAIoJ,KAAM,CACV,IAAIltB,KAAML,KAAK4nB,SAAW3Z,EAC1B,MAAOA,EAAI,IAAMsf,KAAO,MACtBltB,KAAOL,KAAK4nB,SAAW3Z,GAAKsf,GAM9B,OAJAA,MAAO,IAEHltB,KAAOktB,MAAKltB,KAAOyoB,KAAKgF,IAAI,EAAG,EAAI3J,aAEhC9jB,KAGT6X,OAAOjX,UAAU+sB,SAAW,SAAmBpG,OAAQ2C,UAErD,MADKA,WAAUR,YAAYnC,OAAQ,EAAG5nB,KAAKG,QACtB,IAAfH,KAAK4nB,SACF,IAAO5nB,KAAK4nB,QAAU,IAAK,EADA5nB,KAAK4nB,SAI3C1P,OAAOjX,UAAUgtB,YAAc,SAAsBrG,OAAQ2C,UACtDA,UAAUR,YAAYnC,OAAQ,EAAG5nB,KAAKG,OAC3C,IAAIE,KAAML,KAAK4nB,QAAW5nB,KAAK4nB,OAAS,IAAM,CAC9C,OAAc,OAANvnB,IAAsB,WAANA,IAAmBA,KAG7C6X,OAAOjX,UAAUitB,YAAc,SAAsBtG,OAAQ2C,UACtDA,UAAUR,YAAYnC,OAAQ,EAAG5nB,KAAKG,OAC3C,IAAIE,KAAML,KAAK4nB,OAAS,GAAM5nB,KAAK4nB,SAAW,CAC9C,OAAc,OAANvnB,IAAsB,WAANA,IAAmBA,KAG7C6X,OAAOjX,UAAUktB,YAAc,SAAsBvG,OAAQ2C,UAG3D,MAFKA,WAAUR,YAAYnC,OAAQ,EAAG5nB,KAAKG,QAEnCH,KAAK4nB,QACV5nB,KAAK4nB,OAAS,IAAM,EACpB5nB,KAAK4nB,OAAS,IAAM,GACpB5nB,KAAK4nB,OAAS,IAAM,IAGzB1P,OAAOjX,UAAUmtB,YAAc,SAAsBxG,OAAQ2C,UAG3D,MAFKA,WAAUR,YAAYnC,OAAQ,EAAG5nB,KAAKG,QAEnCH,KAAK4nB,SAAW,GACrB5nB,KAAK4nB,OAAS,IAAM,GACpB5nB,KAAK4nB,OAAS,IAAM,EACpB5nB,KAAK4nB,OAAS,IAGnB1P,OAAOjX,UAAUotB,YAAc,SAAsBzG,OAAQ2C,UAE3D,MADKA,WAAUR,YAAYnC,OAAQ,EAAG5nB,KAAKG,QACpCqqB,QAAQpD,KAAKpnB,KAAM4nB,QAAQ,EAAM,GAAI,IAG9C1P,OAAOjX,UAAUqtB,YAAc,SAAsB1G,OAAQ2C,UAE3D,MADKA,WAAUR,YAAYnC,OAAQ,EAAG5nB,KAAKG,QACpCqqB,QAAQpD,KAAKpnB,KAAM4nB,QAAQ,EAAO,GAAI,IAG/C1P,OAAOjX,UAAUstB,aAAe,SAAuB3G,OAAQ2C,UAE7D,MADKA,WAAUR,YAAYnC,OAAQ,EAAG5nB,KAAKG,QACpCqqB,QAAQpD,KAAKpnB,KAAM4nB,QAAQ,EAAM,GAAI,IAG9C1P,OAAOjX,UAAUutB,aAAe,SAAuB5G,OAAQ2C,UAE7D,MADKA,WAAUR,YAAYnC,OAAQ,EAAG5nB,KAAKG,QACpCqqB,QAAQpD,KAAKpnB,KAAM4nB,QAAQ,EAAO,GAAI,IAS/C1P,OAAOjX,UAAUwtB,YAAc,SAAsBlwB,MAAOqpB,OAAQzD,WAAYoG,UAI9E,GAHAhsB,OAASA,MACTqpB,OAAkB,EAATA,OACTzD,WAA0B,EAAbA,YACRoG,SAAU,CACb,GAAImE,UAAW5F,KAAKgF,IAAI,EAAG,EAAI3J,YAAc,CAC7C6F,UAAShqB,KAAMzB,MAAOqpB,OAAQzD,WAAYuK,SAAU,GAGtD,GAAInB,KAAM,CACV,IAAItf,GAAI,CAER,KADAjO,KAAK4nB,QAAkB,IAARrpB,QACN0P,EAAIkW,aAAeoJ,KAAO,MACjCvtB,KAAK4nB,OAAS3Z,GAAM1P,MAAQgvB,IAAO,GAGrC,OAAO3F,QAASzD,YAGlBjM,OAAOjX,UAAU0tB,YAAc,SAAsBpwB,MAAOqpB,OAAQzD,WAAYoG,UAI9E,GAHAhsB,OAASA,MACTqpB,OAAkB,EAATA,OACTzD,WAA0B,EAAbA,YACRoG,SAAU,CACb,GAAImE,UAAW5F,KAAKgF,IAAI,EAAG,EAAI3J,YAAc,CAC7C6F,UAAShqB,KAAMzB,MAAOqpB,OAAQzD,WAAYuK,SAAU,GAGtD,GAAIzgB,GAAIkW,WAAa,CACrB,IAAIoJ,KAAM,CAEV,KADAvtB,KAAK4nB,OAAS3Z,GAAa,IAAR1P,QACV0P,GAAK,IAAMsf,KAAO,MACzBvtB,KAAK4nB,OAAS3Z,GAAM1P,MAAQgvB,IAAO,GAGrC,OAAO3F,QAASzD,YAGlBjM,OAAOjX,UAAU2tB,WAAa,SAAqBrwB,MAAOqpB,OAAQ2C,UAMhE,MALAhsB,QAASA,MACTqpB,OAAkB,EAATA,OACJ2C,UAAUP,SAAShqB,KAAMzB,MAAOqpB,OAAQ,EAAG,IAAM,GACjD1P,OAAOoM,sBAAqB/lB,MAAQuqB,KAAK+F,MAAMtwB,QACpDyB,KAAK4nB,QAAmB,IAARrpB,MACTqpB,OAAS,GAWlB1P,OAAOjX,UAAU6tB,cAAgB,SAAwBvwB,MAAOqpB,OAAQ2C,UAUtE,MATAhsB,QAASA,MACTqpB,OAAkB,EAATA,OACJ2C,UAAUP,SAAShqB,KAAMzB,MAAOqpB,OAAQ,EAAG,MAAQ,GACpD1P,OAAOoM,qBACTtkB,KAAK4nB,QAAmB,IAARrpB,MAChByB,KAAK4nB,OAAS,GAAMrpB,QAAU,GAE9B2rB,kBAAkBlqB,KAAMzB,MAAOqpB,QAAQ,GAElCA,OAAS,GAGlB1P,OAAOjX,UAAU8tB,cAAgB,SAAwBxwB,MAAOqpB,OAAQ2C,UAUtE,MATAhsB,QAASA,MACTqpB,OAAkB,EAATA,OACJ2C,UAAUP,SAAShqB,KAAMzB,MAAOqpB,OAAQ,EAAG,MAAQ,GACpD1P,OAAOoM,qBACTtkB,KAAK4nB,QAAWrpB,QAAU,EAC1ByB,KAAK4nB,OAAS,GAAc,IAARrpB,OAEpB2rB,kBAAkBlqB,KAAMzB,MAAOqpB,QAAQ,GAElCA,OAAS,GAUlB1P,OAAOjX,UAAU+tB,cAAgB,SAAwBzwB,MAAOqpB,OAAQ2C,UAYtE,MAXAhsB,QAASA,MACTqpB,OAAkB,EAATA,OACJ2C,UAAUP,SAAShqB,KAAMzB,MAAOqpB,OAAQ,EAAG,WAAY,GACxD1P,OAAOoM,qBACTtkB,KAAK4nB,OAAS,GAAMrpB,QAAU,GAC9ByB,KAAK4nB,OAAS,GAAMrpB,QAAU,GAC9ByB,KAAK4nB,OAAS,GAAMrpB,QAAU,EAC9ByB,KAAK4nB,QAAmB,IAARrpB,OAEhB6rB,kBAAkBpqB,KAAMzB,MAAOqpB,QAAQ,GAElCA,OAAS,GAGlB1P,OAAOjX,UAAUguB,cAAgB,SAAwB1wB,MAAOqpB,OAAQ2C,UAYtE,MAXAhsB,QAASA,MACTqpB,OAAkB,EAATA,OACJ2C,UAAUP,SAAShqB,KAAMzB,MAAOqpB,OAAQ,EAAG,WAAY,GACxD1P,OAAOoM,qBACTtkB,KAAK4nB,QAAWrpB,QAAU,GAC1ByB,KAAK4nB,OAAS,GAAMrpB,QAAU,GAC9ByB,KAAK4nB,OAAS,GAAMrpB,QAAU,EAC9ByB,KAAK4nB,OAAS,GAAc,IAARrpB,OAEpB6rB,kBAAkBpqB,KAAMzB,MAAOqpB,QAAQ,GAElCA,OAAS,GAGlB1P,OAAOjX,UAAUiuB,WAAa,SAAqB3wB,MAAOqpB,OAAQzD,WAAYoG,UAG5E,GAFAhsB,OAASA,MACTqpB,OAAkB,EAATA,QACJ2C,SAAU,CACb,GAAI4E,OAAQrG,KAAKgF,IAAI,EAAG,EAAI3J,WAAa,EAEzC6F,UAAShqB,KAAMzB,MAAOqpB,OAAQzD,WAAYgL,MAAQ,GAAIA,OAGxD,GAAIlhB,GAAI,CACR,IAAIsf,KAAM,CACV,IAAI6B,KAAM,CAEV,KADApvB,KAAK4nB,QAAkB,IAARrpB,QACN0P,EAAIkW,aAAeoJ,KAAO,MAC7BhvB,MAAQ,GAAa,IAAR6wB,KAAsC,IAAzBpvB,KAAK4nB,OAAS3Z,EAAI,KAC9CmhB,IAAM,GAERpvB,KAAK4nB,OAAS3Z,IAAO1P,MAAQgvB,KAAQ,GAAK6B,IAAM,GAGlD,OAAOxH,QAASzD,YAGlBjM,OAAOjX,UAAUouB,WAAa,SAAqB9wB,MAAOqpB,OAAQzD,WAAYoG,UAG5E,GAFAhsB,OAASA,MACTqpB,OAAkB,EAATA,QACJ2C,SAAU,CACb,GAAI4E,OAAQrG,KAAKgF,IAAI,EAAG,EAAI3J,WAAa,EAEzC6F,UAAShqB,KAAMzB,MAAOqpB,OAAQzD,WAAYgL,MAAQ,GAAIA,OAGxD,GAAIlhB,GAAIkW,WAAa,CACrB,IAAIoJ,KAAM,CACV,IAAI6B,KAAM,CAEV,KADApvB,KAAK4nB,OAAS3Z,GAAa,IAAR1P,QACV0P,GAAK,IAAMsf,KAAO,MACrBhvB,MAAQ,GAAa,IAAR6wB,KAAsC,IAAzBpvB,KAAK4nB,OAAS3Z,EAAI,KAC9CmhB,IAAM,GAERpvB,KAAK4nB,OAAS3Z,IAAO1P,MAAQgvB,KAAQ,GAAK6B,IAAM,GAGlD,OAAOxH,QAASzD,YAGlBjM,OAAOjX,UAAUquB,UAAY,SAAoB/wB,MAAOqpB,OAAQ2C,UAO9D,MANAhsB,QAASA,MACTqpB,OAAkB,EAATA,OACJ2C,UAAUP,SAAShqB,KAAMzB,MAAOqpB,OAAQ,EAAG,KAAM,KACjD1P,OAAOoM,sBAAqB/lB,MAAQuqB,KAAK+F,MAAMtwB,QAChDA,MAAQ,IAAGA,MAAQ,IAAOA,MAAQ,GACtCyB,KAAK4nB,QAAmB,IAARrpB,MACTqpB,OAAS,GAGlB1P,OAAOjX,UAAUsuB,aAAe,SAAuBhxB,MAAOqpB,OAAQ2C,UAUpE,MATAhsB,QAASA,MACTqpB,OAAkB,EAATA,OACJ2C,UAAUP,SAAShqB,KAAMzB,MAAOqpB,OAAQ,EAAG,OAAQ,OACpD1P,OAAOoM,qBACTtkB,KAAK4nB,QAAmB,IAARrpB,MAChByB,KAAK4nB,OAAS,GAAMrpB,QAAU,GAE9B2rB,kBAAkBlqB,KAAMzB,MAAOqpB,QAAQ,GAElCA,OAAS,GAGlB1P,OAAOjX,UAAUuuB,aAAe,SAAuBjxB,MAAOqpB,OAAQ2C,UAUpE,MATAhsB,QAASA,MACTqpB,OAAkB,EAATA,OACJ2C,UAAUP,SAAShqB,KAAMzB,MAAOqpB,OAAQ,EAAG,OAAQ,OACpD1P,OAAOoM,qBACTtkB,KAAK4nB,QAAWrpB,QAAU,EAC1ByB,KAAK4nB,OAAS,GAAc,IAARrpB,OAEpB2rB,kBAAkBlqB,KAAMzB,MAAOqpB,QAAQ,GAElCA,OAAS,GAGlB1P,OAAOjX,UAAUwuB,aAAe,SAAuBlxB,MAAOqpB,OAAQ2C,UAYpE,MAXAhsB,QAASA,MACTqpB,OAAkB,EAATA,OACJ2C,UAAUP,SAAShqB,KAAMzB,MAAOqpB,OAAQ,EAAG,YAAY,YACxD1P,OAAOoM,qBACTtkB,KAAK4nB,QAAmB,IAARrpB,MAChByB,KAAK4nB,OAAS,GAAMrpB,QAAU,EAC9ByB,KAAK4nB,OAAS,GAAMrpB,QAAU,GAC9ByB,KAAK4nB,OAAS,GAAMrpB,QAAU,IAE9B6rB,kBAAkBpqB,KAAMzB,MAAOqpB,QAAQ,GAElCA,OAAS,GAGlB1P,OAAOjX,UAAUyuB,aAAe,SAAuBnxB,MAAOqpB,OAAQ2C,UAapE,MAZAhsB,QAASA,MACTqpB,OAAkB,EAATA,OACJ2C,UAAUP,SAAShqB,KAAMzB,MAAOqpB,OAAQ,EAAG,YAAY,YACxDrpB,MAAQ,IAAGA,MAAQ,WAAaA,MAAQ,GACxC2Z,OAAOoM,qBACTtkB,KAAK4nB,QAAWrpB,QAAU,GAC1ByB,KAAK4nB,OAAS,GAAMrpB,QAAU,GAC9ByB,KAAK4nB,OAAS,GAAMrpB,QAAU,EAC9ByB,KAAK4nB,OAAS,GAAc,IAARrpB,OAEpB6rB,kBAAkBpqB,KAAMzB,MAAOqpB,QAAQ,GAElCA,OAAS,GAgBlB1P,OAAOjX,UAAU0uB,aAAe,SAAuBpxB,MAAOqpB,OAAQ2C,UACpE,MAAOD,YAAWtqB,KAAMzB,MAAOqpB,QAAQ,EAAM2C,WAG/CrS,OAAOjX,UAAU2uB,aAAe,SAAuBrxB,MAAOqpB,OAAQ2C,UACpE,MAAOD,YAAWtqB,KAAMzB,MAAOqpB,QAAQ,EAAO2C,WAWhDrS,OAAOjX,UAAU4uB,cAAgB,SAAwBtxB,MAAOqpB,OAAQ2C,UACtE,MAAOE,aAAYzqB,KAAMzB,MAAOqpB,QAAQ,EAAM2C,WAGhDrS,OAAOjX,UAAU6uB,cAAgB,SAAwBvxB,MAAOqpB,OAAQ2C,UACtE,MAAOE,aAAYzqB,KAAMzB,MAAOqpB,QAAQ,EAAO2C,WAIjDrS,OAAOjX,UAAU+kB,KAAO,SAAe2G,OAAQoD,YAAapuB,MAAO8kB,KAQjE,GAPK9kB,QAAOA,MAAQ,GACf8kB,KAAe,IAARA,MAAWA,IAAMzmB,KAAKG,QAC9B4vB,aAAepD,OAAOxsB,SAAQ4vB,YAAcpD,OAAOxsB,QAClD4vB,cAAaA,YAAc,GAC5BtJ,IAAM,GAAKA,IAAM9kB,QAAO8kB,IAAM9kB,OAG9B8kB,MAAQ9kB,MAAO,MAAO,EAC1B,IAAsB,IAAlBgrB,OAAOxsB,QAAgC,IAAhBH,KAAKG,OAAc,MAAO,EAGrD,IAAI4vB,YAAc,EAChB,KAAM,IAAItL,YAAW,4BAEvB,IAAI9iB,MAAQ,GAAKA,OAAS3B,KAAKG,OAAQ,KAAM,IAAIskB,YAAW,4BAC5D,IAAIgC,IAAM,EAAG,KAAM,IAAIhC,YAAW,0BAG9BgC,KAAMzmB,KAAKG,SAAQsmB,IAAMzmB,KAAKG,QAC9BwsB,OAAOxsB,OAAS4vB,YAActJ,IAAM9kB,QACtC8kB,IAAMkG,OAAOxsB,OAAS4vB,YAAcpuB,MAGtC,IAAIokB,KAAMU,IAAM9kB,KAChB,IAAIsM,EAEJ,IAAIjO,OAAS2sB,QAAUhrB,MAAQouB,aAAeA,YAActJ,IAE1D,IAAKxY,EAAI8X,IAAM,EAAG9X,GAAK,IAAKA,EAC1B0e,OAAO1e,EAAI8hB,aAAe/vB,KAAKiO,EAAItM,WAEhC,IAAIokB,IAAM,MAAS7N,OAAOoM,oBAE/B,IAAKrW,EAAI,EAAGA,EAAI8X,MAAO9X,EACrB0e,OAAO1e,EAAI8hB,aAAe/vB,KAAKiO,EAAItM,WAGrCoiB,YAAW9iB,UAAUkK,IAAIzE,KACvBimB,OACA3sB,KAAKkkB,SAASviB,MAAOA,MAAQokB,KAC7BgK,YAIJ,OAAOhK,MAOT7N,OAAOjX,UAAUokB,KAAO,SAAehlB,IAAKsB,MAAO8kB,IAAKnB,UAEtD,GAAmB,gBAARjlB,KAAkB,CAS3B,GARqB,gBAAVsB,QACT2jB,SAAW3jB,MACXA,MAAQ,EACR8kB,IAAMzmB,KAAKG,QACa,gBAARsmB,OAChBnB,SAAWmB,IACXA,IAAMzmB,KAAKG,QAEM,IAAfE,IAAIF,OAAc,CACpB,GAAI6vB,MAAO3vB,IAAI4qB,WAAW,EACtB+E,MAAO,MACT3vB,IAAM2vB,MAGV,GAAiB/xB,SAAbqnB,UAA8C,gBAAbA,UACnC,KAAM,IAAIT,WAAU,4BAEtB,IAAwB,gBAAbS,YAA0BpN,OAAOuN,WAAWH,UACrD,KAAM,IAAIT,WAAU,qBAAuBS,cAErB,gBAARjlB,OAChBA,IAAY,IAANA,IAIR,IAAIsB,MAAQ,GAAK3B,KAAKG,OAASwB,OAAS3B,KAAKG,OAASsmB,IACpD,KAAM,IAAIhC,YAAW,qBAGvB,IAAIgC,KAAO9kB,MACT,MAAO3B,KAGT2B,UAAkB,EAClB8kB,IAAcxoB,SAARwoB,IAAoBzmB,KAAKG,OAASsmB,MAAQ,EAE3CpmB,MAAKA,IAAM,EAEhB,IAAI4N,EACJ,IAAmB,gBAAR5N,KACT,IAAK4N,EAAItM,MAAOsM,EAAIwY,MAAOxY,EACzBjO,KAAKiO,GAAK5N,QAEP,CACL,GAAIypB,OAAQ5R,OAAO4N,SAASzlB,KACxBA,IACAimB,YAAY,GAAIpO,QAAO7X,IAAKilB,UAAUzM,WAC1C,IAAIkN,KAAM+D,MAAM3pB,MAChB,KAAK8N,EAAI,EAAGA,EAAIwY,IAAM9kB,QAASsM,EAC7BjO,KAAKiO,EAAItM,OAASmoB,MAAM7b,EAAI8X,KAIhC,MAAO/lB,MAMT,IAAI6qB,mBAAoB;;;;AMjiDxBjuB,QAAQwqB,KAAO,SAAUnB,OAAQ2B,OAAQwL,KAAMC,KAAMC,QACnD,GAAIlP,GAAG8C,CACP,IAAIqM,MAAgB,EAATD,OAAaD,KAAO,CAC/B,IAAIG,OAAQ,GAAKD,MAAQ,CACzB,IAAIE,OAAQD,MAAQ,CACpB,IAAIE,QAAQ,CACZ,IAAIzlB,GAAImlB,KAAQE,OAAS,EAAK,CAC9B,IAAIxrB,GAAIsrB,MAAO,EAAK,CACpB,IAAInB,GAAIhM,OAAO2B,OAAS3Z,EAOxB,KALAA,GAAKnG,EAELsc,EAAI6N,GAAM,IAAOyB,OAAU,EAC3BzB,KAAQyB,MACRA,OAASH,KACFG,MAAQ,EAAGtP,EAAQ,IAAJA,EAAU6B,OAAO2B,OAAS3Z,GAAIA,GAAKnG,EAAG4rB,OAAS,GAKrE,IAHAxM,EAAI9C,GAAM,IAAOsP,OAAU,EAC3BtP,KAAQsP,MACRA,OAASL,KACFK,MAAQ,EAAGxM,EAAQ,IAAJA,EAAUjB,OAAO2B,OAAS3Z,GAAIA,GAAKnG,EAAG4rB,OAAS,GAErE,GAAU,IAANtP,EACFA,EAAI,EAAIqP,UACH,CAAA,GAAIrP,IAAMoP,KACf,MAAOtM,GAAIyM,KAAQ1B,GAAI,EAAK,IAAKlH,EAAAA,EAEjC7D,IAAQ4B,KAAKgF,IAAI,EAAGuF,MACpBjP,GAAQqP,MAEV,OAAQxB,GAAI,EAAK,GAAK/K,EAAI4B,KAAKgF,IAAI,EAAG1J,EAAIiP,OAG5Cz2B,QAAQ8oB,MAAQ,SAAUO,OAAQ1nB,MAAOqpB,OAAQwL,KAAMC,KAAMC,QAC3D,GAAIlP,GAAG8C,EAAGiE,CACV,IAAIoI,MAAgB,EAATD,OAAaD,KAAO,CAC/B,IAAIG,OAAQ,GAAKD,MAAQ,CACzB,IAAIE,OAAQD,MAAQ,CACpB,IAAII,IAAe,KAATP,KAAcvK,KAAKgF,IAAI,GAAG,IAAOhF,KAAKgF,IAAI,GAAG,IAAO,CAC9D,IAAI7f,GAAImlB,KAAO,EAAKE,OAAS,CAC7B,IAAIxrB,GAAIsrB,KAAO,GAAI,CACnB,IAAInB,GAAI1zB,MAAQ,GAAgB,IAAVA,OAAe,EAAIA,MAAQ,EAAK,EAAI,CAmC1D,KAjCAA,MAAQuqB,KAAK+K,IAAIt1B,OAEb4pB,MAAM5pB,QAAUA,QAAUwsB,EAAAA,GAC5B7D,EAAIiB,MAAM5pB,OAAS,EAAI,EACvB6lB,EAAIoP,OAEJpP,EAAI0E,KAAK+F,MAAM/F,KAAKvgB,IAAIhK,OAASuqB,KAAKgL,KAClCv1B,OAAS4sB,EAAIrC,KAAKgF,IAAI,GAAI1J,IAAM,IAClCA,IACA+G,GAAK,GAGL5sB,OADE6lB,EAAIqP,OAAS,EACNG,GAAKzI,EAELyI,GAAK9K,KAAKgF,IAAI,EAAG,EAAI2F,OAE5Bl1B,MAAQ4sB,GAAK,IACf/G,IACA+G,GAAK,GAGH/G,EAAIqP,OAASD,MACftM,EAAI,EACJ9C,EAAIoP,MACKpP,EAAIqP,OAAS,GACtBvM,GAAK3oB,MAAQ4sB,EAAI,GAAKrC,KAAKgF,IAAI,EAAGuF,MAClCjP,GAAQqP,QAERvM,EAAI3oB,MAAQuqB,KAAKgF,IAAI,EAAG2F,MAAQ,GAAK3K,KAAKgF,IAAI,EAAGuF,MACjDjP,EAAI,IAIDiP,MAAQ,EAAGpN,OAAO2B,OAAS3Z,GAAS,IAAJiZ,EAAUjZ,GAAKnG,EAAGof,GAAK,IAAKmM,MAAQ,GAI3E,IAFAjP,EAAKA,GAAKiP,KAAQnM,EAClBqM,MAAQF,KACDE,KAAO,EAAGtN,OAAO2B,OAAS3Z,GAAS,IAAJmW,EAAUnW,GAAKnG,EAAGsc,GAAK,IAAKmP,MAAQ,GAE1EtN,OAAO2B,OAAS3Z,EAAInG,IAAU,IAAJmqB;;AClF5B,GAAIpZ,aAAcA,QAElBlc,QAAOC,QAAUoE,MAAMjC,SAAW,SAAU2D,KAC1C,MAA6B,kBAAtBmW,SAASnS,KAAKhE;;AHHvB,YAKA,SAASyuB,UAAS9wB,KACjB,GAAY,OAARA,KAAwBpC,SAARoC,IACnB,KAAM,IAAIwkB,WAAU,wDAGrB,OAAOrN,QAAOnX,KAGf,QAAS+wB,mBACR,IACC,IAAK5Z,OAAO6Z,OACX,OAAO,CAMR,IAAIC,OAAQ,GAAIpzB,QAAO,MAEvB,IADAozB,MAAM,GAAK,KACkC,MAAzC9Z,OAAO+Z,oBAAoBD,OAAO,GACrC,OAAO,CAIR,IAAIE,SACJ,KAAK,GAAIvjB,GAAI,EAAGA,EAAI,GAAIA,IACvBujB,MAAM,IAAMtzB,OAAOwrB,aAAazb,IAAMA,CAEvC,IAAIwjB,QAASja,OAAO+Z,oBAAoBC,OAAOtsB,IAAI,SAAU+hB,GAC5D,MAAOuK,OAAMvK,IAEd,IAAwB,eAApBwK,OAAO5yB,KAAK,IACf,OAAO,CAIR,IAAI6yB,SAIJ,OAHA,uBAAuBpyB,MAAM,IAAIsb,QAAQ,SAAU+W,QAClDD,MAAMC,QAAUA,SAGf,yBADEna,OAAOlI,KAAKkI,OAAO6Z,UAAWK,QAAQ7yB,KAAK,IAM9C,MAAOulB,GAER,OAAO,GAnDT,GAAIld,gBAAiBsQ,OAAOvW,UAAUiG,cACtC,IAAI0qB,kBAAmBpa,OAAOvW,UAAU4wB,oBAsDxCl1B,QAAOC,QAAUw0B,kBAAoB5Z,OAAO6Z,OAAS,SAAU1E,OAAQmF,QACtE,GAAIlN,KACJ,IAAImN,IAAKZ,SAASxE,OAClB,IAAIqF,QAEJ,KAAK,GAAIC,GAAI,EAAGA,EAAI7wB,UAAUjB,OAAQ8xB,IAAK,CAC1CrN,KAAOpN,OAAOpW,UAAU6wB,GAExB,KAAK,GAAI3zB,OAAOsmB,MACX1d,eAAeR,KAAKke,KAAMtmB,OAC7ByzB,GAAGzzB,KAAOsmB,KAAKtmB,KAIjB,IAAIkZ,OAAO0a,sBAAuB,CACjCF,QAAUxa,OAAO0a,sBAAsBtN,KACvC,KAAK,GAAI3W,GAAI,EAAGA,EAAI+jB,QAAQ7xB,OAAQ8N,IAC/B2jB,iBAAiBlrB,KAAKke,KAAMoN,QAAQ/jB,MACvC8jB,GAAGC,QAAQ/jB,IAAM2W,KAAKoN,QAAQ/jB,MAMlC,MAAO8jB;;A/CjFR;;;ACMA,GAAI73B,IACAC,QACAC,WACAC,aACAC,SACAC,WACAC,SACIC,aAKRP,GAAEQ,KAAOC,QAAQ,cACjBT,EAAEQ,OAEFR,EAAEC,KAAKS,MAAQD,QAAQ,qBACvBT,EAAEC,KAAKU,aAAeF,QAAQ,wBAC9BT,EAAEC,KAAKW,IAAMH,QAAQ,mBACrBT,EAAEC,KAAKY,UAAYJ,QAAQ,kBAE3BT,EAAEE,QAAQY,UAAYL,QAAQ,sCAC9BT,EAAEG,UAAUY,KAAON,QAAQ,mCAE3BT,EAAEK,QAAQW,IAAMP,QAAQ,gCACxBT,EAAEK,QAAQY,OAASR,QAAQ,mCAC3BT,EAAEK,QAAQa,IAAMT,QAAQ,6BACxBT,EAAEK,QAAQc,KAAOV,QAAQ,gCACzBT,EAAEK,QAAQe,UAAYX,QAAQ,mCAC9BT,EAAEK,QAAQgB,KAAOZ,QAAQ,8BACzBT,EAAEK,QAAQiB,KAAOb,QAAQ,8BACzBT,EAAEK,QAAQkB,MAAQd,QAAQ,+BAC1BT,EAAEK,QAAQmB,MAAQf,QAAQ,+BAC1BT,EAAEK,QAAQoB,KAAOhB,QAAQ,8BACzBT,EAAEK,QAAQqB,OAASjB,QAAQ,gCAC3BT,EAAEK,QAAQsB,MAAQlB,QAAQ,+BAC1BT,EAAEK,QAAQuB,MAAQnB,QAAQ,+BAE1BT,EAAEI,MAAMyB,OAASpB,QAAQ,wBACzBT,EAAEE,QAAQ4B,MAAQrB,QAAQ,yBAE1BT,EAAEM,QAAQyB,gBAAkBtB,QAAQ,+BACpCT,EAAEM,QAAQ0B,WAAavB,QAAQ,0BAC/BT,EAAEM,QAAQ2B,YAAcxB,QAAQ,2BAChCT,EAAEM,QAAQ4B,aAAezB,QAAQ,4BAEjCT,EAAEM,QAAQC,SAAS,cAAgBE,QAAQ,iDAC3CT,EAAEM,QAAQC,SAAS,wBAA0BE,QAAQ,2DACrDT,EAAEM,QAAQC,SAAS4B,SAAW1B,QAAQ,+CACtCT,EAAEM,QAAQC,SAAS,kBAAoBE,QAAQ,qDAC/CT,EAAEM,QAAQC,SAAS,kBAAoBE,QAAQ,qDAC/CT,EAAEM,QAAQC,SAAS,oBAAsBE,QAAQ,uDACjDT,EAAEM,QAAQC,SAAS,sBAAwBE,QAAQ,yDAEnDT,EAAEM,QAAQ8B,eAAiB3B,QAAQ,wCACnCT,EAAEK,QAAQgC,QAAU5B,QAAQ,6BAE5BT,EAAEsC,QAAU,iBACZtC,EAAEuC,IAAM9B,QAAQ,sBAEhB+B,OAAOxC,EAAIA,EACXyC,OAAOC,QAAU1C;;;;AClEjB,YAEA,IAAI2C,kBAAmBlC,QAAQ,+BAE/B,IAAImC,SAAU,SAAUC,UACpB,GAAIC,WACJ,IAAIC,KACJ,IAAIC,YAAaL,kBACjB,IAAIM,SAAU,sBAEVF,MADAC,WAAWE,cACJ,oBAEA,EAEX,IAAIC,SAAUJ,KAAOE,OAUrB,OATAH,YAAaM,EAAEC,MAAOC,IAAKH,QAASI,OAAO,IAC3CT,WAAWU,KAAK,SAAUC,KACtB,GAAIlB,KAAMkB,IAAIlB,GACda,GAAEM,OAAOf,iBAAkBJ,OAC5BoB,KAAK,SAAUF,KAGdL,EAAEM,OAAOf,kBAAoBiB,SAAU,QAASb,KAAM,oBAEnDD,WAAWU,KAAKX,UAAUc,KAAKd,UAG1CJ,QAAOC,QAAUE;;AwBKjB,YAaA,SAASX,aAAYoH,SACjBA,QAAUjG,EAAEM,QAAO,KAAUyJ,SAAU9D,SACvCvD,KAAK+L,eAAiB,GAAIN,gBAAelI,SACzCvD,KAAKuD,QAAUvD,KAAK+L,eAAeC,mBAEnChM,KAAK8X,QAAU9X,KAAKuD,QAAQuU,QAC5B9X,KAAK+X,YAAc,GAAIC,aAAYhY,KAAKuD,SAlB5C,GAAIyU,aAAcrd,QAAQ,8BAC1B,IAAIsd,eAAgBtd,QAAQ,gCAC5B,IAAI0a,cAAe1a,QAAQ,+BAC3B,IAAI8Q,gBAAiB9Q,QAAQ,2BAC7B,IAAIud,QAASvd,QAAQ,UAAUud,MAC/B,IAAI5M,OAAQ3Q,QAAQ,uBAAuB2Q,KAC3C,IAAI8J,cAAeza,QAAQ,gBAE3B,IAAI0M,WACA8Q,eAAe,EAYnB,IAAIC,kBAAmB,SAAUC,QAASpS,IACtC,IAAK,GAAIW,GAAI,EAAGA,EAAEyR,QAAQlY,OAAQyG,IAC9B,GAAIyR,QAAQzR,GAAGyK,SAAWpL,GACtB,MAAOoS,SAAQzR,EAKvB,OAAO,MAGXzK,aAAY8E,UAAY3D,EAAEM,OAAOzB,YAAY8E,WAoCzCwO,MAAO,SAAUlM,SACb,GAAI3B,OAAQ5B,IACZ,IAAI2N,IAAKrQ,EAAEkD,UACX,IAAIuL,gBAAiB/L,KAAK+L,cAC1B,IAAIuM,gBAAiBvM,eAAeC,kBAAmB1H,QAAShH,EAAEiH,KAAME,MAAOnH,EAAEiH,MAAQhB,QACzF,IAAIgV,YAAaD,eAAehU,OAChC,IAAIkU,UAAWF,eAAe7T,KAC9B,IAAI2O,SAAUkF,eAAelF,OAE7B,IAAIqF,aAAc,SAAU/M,OACxB,GAAIgN,SAAUhN,MAAMpM,MAAM,KAAK,EAC/B,MAAOoZ,QAAQvY,OAAS,IAAM,GAC1BuY,SAAW,GAGf,IAAIC,QAASjP,OAAOkP,KAAOlP,OAAOkP,KAAO,SAAUF,SAAW,MAAO,IAAIR,QAAOQ,QAAS,UAAUG,SAAS,SAE5G,OAAO5Z,MAAK6Z,MAAMH,OAAOD,UAG7B,IAAIK,kBAAmB,SAAUC,QAASxR,WAAY7D,MAElD/B,MAAMkO,SAASxP,KAAK,WAChB,GAAImE,OAAQnH,EAAEM,QAAO,KAAU+F,MAAQsV,WAAYD,QAASrJ,OAAQnI,YACpEmG,IAAGpI,OAAOd,SAIlB,IAAIyU,eAAgB,SAAUzQ,UAG1B,GAAIiD,OAAQjD,SAAS0Q,YACrB,IAAIC,UAAWX,YAAY/M,MAC3B,IAAI2N,WAAYtN,eAAeuN,aAAaC,UAC5C,IAAIC,eAAgBlc,EAAEM,QAAO,KAAU0a,gBAAkBhU,QAAShH,EAAEiH,MACpE,IAAIZ,OAAS8V,KAAMhR,SAAUkJ,KAAMyH,SACnC,IAAIxN,SAAU0M,eAAe1M,OAC7B,IAAI8N,cAA8C,OAA/BN,SAASO,iBAC5B,IAAIxB,eAAgBG,eAAeH,eAAiBvM,OAEpD,IAAIgO,cACAC,WAAcnO,MACdC,QAAW2M,eAAe3M,QAC1BC,QAAWA,QACXyF,OAAU+H,SAASU,QACnBP,OAAUF,UACVK,aAAgBA,aAGpB,KAAKvB,cAID,MAHApM,gBAAegO,YAAYH,aAC3BrB,WAAWpX,MAAMnB,MAAO2D,WACxBgK,IAAGlN,QAAQkD,KAIf,IAAIqW,iBAAkB,SAAUC,WAC5BtW,KAAKuW,WAAaD,SAElB,IAAIxJ,OAAQ,IACZ,IAAyB,IAArBwJ,UAAU9Z,OAEV,WADA4Y,kBAAiB,oDAAqD,IAAKpV,KAExE,IAAyB,IAArBsW,UAAU9Z,OAEjBsQ,MAAQwJ,UAAU,OACf,IAAIA,UAAU9Z,OAAS,GACtBiT,QAAS,CACT,GAAI+G,gBAAiB7c,EAAE8c,KAAKH,UAAW,SAAUI,UAC7C,MAAOA,UAASjH,UAAYA,SAEhC3C,OAAkC,IAA1B0J,eAAeha,OAAega,eAAe,GAAK,KAIlE,GAAI1J,MAAO,CAGP,GAAI6J,SAAQZ,cAAiF,gBAA3DtB,iBAAiB3H,MAAM4H,QAASe,SAASU,SAASS,IACpF,IAAIC,YACApH,QAAS3C,MAAM2C,QACfpB,UAAWvB,MAAMzN,KACjBsX,MAAOA,MAEX,IAAIG,sBAAuBrF,gBAAiBwE,YAAaY,UACzDZ,aAAYL,OAAO3N,SAAW4O,UAC9B5Y,MAAMmK,eAAegO,YAAYU,qBAAsBnC,gBACvDC,WAAWpX,MAAMnB,MAAO2D,OACxBgK,GAAGlN,QAAQkD,UAEXoV,kBAAiB,wGAAyG,IAAKpV,MAIvI,IAAK+V,aAGE,CACH,GAAIgB,MAAOtF,gBAAiBoE,eAAiB9N,MAAOA,OACpD,IAAIiP,cAAe,GAAItF,cAAaqF,KACpCC,cAAapF,WAAY5J,QAAS2M,eAAe3M,QAASC,QAASA,UAC9DtL,KAAK,SAAUiZ,QAEZA,OAAOqB,QAAQ,SAAUnK,OACrBA,MAAM2C,QAAU3C,MAAMxK,KAE1B+T,gBAAgBT,SACjB5L,GAAGpI,YAZV3D,OAAMiZ,eAAgBxJ,OAAQ+H,SAASU,QAASpO,MAAOA,OAAS8N,eAC3DlZ,KAAK0Z,gBAAiBrM,GAAGpI,QAkCtC,OAnBA+S,gBAAehU,QAAU4U,cACzBZ,eAAe7T,MAAQ,SAAUgE,UAC7B,MAAI6P,gBAAe3M,SAEf2M,eAAe3M,QAAU,KACzB2M,eAAe7T,MAAQ,WACnB+T,SAASrX,MAAMnB,KAAMoB,WACrBuM,GAAGpI,OAAOkD,eAGd7G,OAAMmW,YAAYtI,MAAM6I,kBAI5BE,SAASrX,MAAMnB,KAAMoB,eACrBuM,IAAGpI,OAAOkD,YAGdzI,KAAK+X,YAAYtI,MAAM6I,gBAChB3K,GAAGjN,WAcdoP,OAAQ,SAAUvM,SACd,GAAI3B,OAAQ5B,IACZ,IAAIsY,gBAAiBtY,KAAK+L,eAAeC,iBAAiBzI,QAE1D,IAAIuX,gBAAiB,SAAUrS,UAC3B7G,MAAMmK,eAAegP,gBAGzB,OAAO/a,MAAK+X,YAAYjI,OAAOwI,gBAAgB5a,KAAKod,iBAgBxDE,SAAU,SAAUzX,SAChB,GAAID,aAActD,KAAK+L,eAAeC,iBAAiBzI,QAEvD,IAAI0X,SAAUjb,KAAK+L,eAAeuN,YAClC,IAAI3L,IAAKrQ,EAAEkD,UAQX,OALIya,SAAQpB,WACRlM,GAAGlN,QAAQwa,QAAQpB,YAEnB7Z,KAAKyP,MAAMnM,aAAahD,KAAKqN,GAAGlN,SAE7BkN,GAAGjN,WA2Bdma,cAAe,SAAU5X,OAAQM,SAC7B,GAAI+U,gBAAiBtY,KAAK+L,eAAeC,kBAAmB1H,QAAShH,EAAEiH,MAAQhB,QAC/E,IAAIoK,IAAKrQ,EAAEkD,UACX,IAAI+X,YAAaD,eAAehU,OAEhCgU,gBAAehU,QAAU,SAAU4W,YAE3B5C,eAAe1M,UACfsP,WAAa5d,EAAE8c,KAAKc,WAAY,SAAUzK,OACtC,MAAOA,OAAM7E,UAAY0M,eAAe1M,WAIhD2M,WAAWpX,MAAMnB,MAAOkb,aACxBvN,GAAGlN,QAAQya,YAGf,IAAIC,eAAgB,GAAIlD,gBAAgBvM,MAAOzI,OAAOyI,OAEtD,OADAyP,eAAc3H,iBAAiBvQ,OAAQqV,gBAAgBza,KAAK8P,GAAGpI,QACxDoI,GAAGjN,WAiBd0a,0BAA2B,SAAU7X,SACjC,MAAOvD,MAAK+L,eAAeuN,WAAW/V,UAoB1C8X,UAAW,SAAU9B,QACjB,GAAI0B,SAAUjb,KAAKob,2BACnB,IAAIrc,SAAUiC,MAAMjC,QAAQwa,OAe5B,OAdAA,QAASxa,QAAUwa,QAAUA,QAE7Bjc,EAAEe,KAAKkb,OAAQ,SAAU/Z,MAAOiR,OAC5B,GAAI6K,eAAgBhe,EAAEM,WAAa0c,OAAO,GAAS7J,MACnD,IAAI7E,SAAU0P,cAAc1P,OAC5B,IAAI2P,aAAc,YAAa,UAAW,QAC1C,KAAK3P,UAAY0P,cAActJ,UAC3B,KAAM,IAAIvF,OAAM,qCAGpB6O,eAAgBhQ,MAAMgQ,cAAeC,YACrCN,QAAQ1B,OAAO3N,SAAW0P,gBAE9Btb,KAAK+L,eAAegO,YAAYkB,SACzBA,WAIfte,OAAOC,QAAUT;;AelYjB,YAEA,IAAII,SAAU5B,QAAQ,6BACtB,IAAI8Q,gBAAiB9Q,QAAQ,2BAiC7B,IAAI2B,gBAAiB,SAAUiH,SAC3B,IAAKjG,EAAEslB,OACH,KAAM,IAAInW,OAAM,iFAEpB,KAAKlJ,UAAYA,QAAQ/F,IACrB,KAAM,IAAIiP,OAAM,8CAGpB,IAAIpF,WAKA7J,IAAK,GAML6K,SAAU,OAMVwa,kBAAkB,EAMlBC,iBAAiB,EAMjBzC,WAWAhB,UAAWphB,OAEf+B,MAAK+L,eAAiB,GAAIN,eAC1B,IAAI0T,qBAAsBnf,KAAK+L,eAAeC,iBAAiB3E,SAAU9D,QAIzE,IAHAvD,KAAK+iB,wBACL/iB,KAAKuD,QAAU4b,oBAEXA,oBAAoB2D,iBAAmBxmB,eAAe2E,UAAU+hB,QAEhE,MADAhjB,MAAK4iB,OAAStmB,eAAe2E,UAAU+hB,QAChChjB,IAEX,IAAI4iB,QAAS,GAAItlB,GAAE2lB,MACnB3mB,gBAAe2E,UAAU+hB,QAAUJ,OAEnCA,OAAOC,iBAAmB1D,oBAAoB0D,iBAE9C7iB,KAAKkjB,aAAc,CACnB,IAAIC,kBAAmB,SAAUnK,SAC7B1b,EAAE0C,MAAM4e,QAAQ,aAAc5F,SAElC,IAAIoK,qBAAsB,SAAUpK,SAChC1b,EAAE0C,MAAM4e,QAAQ,UAAW5F,SAE/B,IAAItL,IAAK1N,IAET4iB,QAAOS,UAAUlE,qBAEjByD,OAAOU,YAAY,gBAAiB,SAAUtK,SAC1C,GAAIuK,cAAevjB,KAAKkjB,WACxBljB,MAAKkjB,YAAelK,QAAQwK,cAAe,GACtCD,cAAgBvjB,KAAKkjB,YACtBE,oBAAoB1c,KAAK1G,KAAMgZ,SACxBuK,eAAiBvjB,KAAKkjB,aAC7BC,iBAAiBzc,KAAK1G,KAAMgZ,UAElClX,KAAK9B,OAEP4iB,OAAOU,YAAY,mBAAoBH,kBAEvCP,OAAOU,YAAY,kBAAmB,SAAUtK,SACxCA,QAAQwK,YAGRZ,OAAOxE,MAAM,WACT9gB,EAAEoQ,GAAGqV,sBAAsB1kB,KAAK,SAAUmB,MAAOikB,MAC7Cb,OAAOc,YAAYD,YAOnCb,OAAOU,YAAY,kBAAmB,SAAUtK,SAC5C1b,EAAEoQ,IAAIkR,QAAQ,YAAa5F,WAE/B4J,OAAOU,YAAY,oBAAqB,SAAUtK,SAC9C1b,EAAEoQ,IAAIkR,QAAQ,cAAe5F,WAEjC4J,OAAOU,YAAY,gBAAiB,SAAUtK,SAC1C1b,EAAEoQ,IAAIkR,QAAQ,UAAW5F,WAE7B4J,OAAOU,YAAY,qBAAsB,SAAUtK,SAC/C1b,EAAEoQ,IAAIkR,QAAQ,QAAS5F,WAG3B4J,OAAOvD,UAAUF,oBAAoBE,WAErCrf,KAAK4iB,OAASA,OAIlBtmB,gBAAe2E,UAAY3D,EAAEM,OAAOtB,eAAe2E,WAgB/Cwe,WAAY,SAAUlc,SAEdA,UAAYjG,EAAE0B,cAAcuE,WAC5BA,SACIsD,KAAMtD,SAGd,IAAI8D,WACAhN,UAAW2F,KAAK4iB,OAEpB,IAAIvC,SAAU,GAAI9jB,SAAQe,EAAEM,QAAO,KAAUoC,KAAKuD,QAAQ8c,QAAShZ,SAAU9D,SAI7E,IAAIkgB,MAAOpD,QAAQrC,SACnBqC,SAAQrC,UAAY,WAChB,GAAI2F,OAAQF,KAAKtiB,MAAMkf,QAASjf,UAEhC,OADApB,MAAK+iB,qBAAwB/iB,KAAK+iB,qBAAqB9gB,OAAO0hB,OACvDA,OACT7hB,KAAK9B,KAGP,IAAI4jB,QAASvD,QAAQ7B,WAWrB,OAVA6B,SAAQ7B,YAAc,WAClB,GAAIqF,SAAUD,OAAOziB,MAAMkf,QAASjf,UACpC,KAAK,GAAI6M,GAAI,EAAGA,EAAIjO,KAAK+iB,qBAAqB5iB,OAAQ8N,IAC9CjO,KAAK+iB,qBAAqB9U,GAAGhI,KAAO4d,QAAQ5d,IAC5CjG,KAAK+iB,qBAAqBhiB,OAAOkN,EAAG,EAG5C,OAAO4V,UACT/hB,KAAK9B,MAEAqgB,SAYX5B,GAAI,SAAUC,OACVphB,EAAE0C,MAAMye,GAAGtd,MAAM7D,EAAE0C,MAAOoB,YAU9Bud,IAAK,SAAUD,OACXphB,EAAE0C,MAAM2e,IAAIxd,MAAM7D,EAAE0C,MAAOoB,YAU/Bwd,QAAS,SAAUF,OACfphB,EAAE0C,MAAM4e,QAAQzd,MAAM7D,EAAE0C,MAAOoB,cAIvCzE,OAAOC,QAAUN;;ANnPjB,YA8BA,IAAIA,gBAAiB3B,QAAQ,oBAC7B,IAAII,WAAYJ,QAAQ,kBACxB,IAAIuC,YAAavC,QAAQ,gCACzB,IAAI8Q,gBAAiB9Q,QAAQ,2BAE7B,IAAIwB,aAAcxB,QAAQ,iBAE1B,IAAIkkB,aACAjT,SAAS,EACT6E,OAAO,EACPkL,OAAO,EACPhK,MAAM,EACNhO,MAAM,EACNmb,SAAS,EACTC,MAAM,EAEV,IAAI9D,SAAU,GAAI9e,YAClB,IAAI6iB,iCAAkC,SAAUzgB,MAAO0gB,eAAgBnW,UACnE,IAAKvK,MAAO,CACR,GAAI6a,UAAW6B,QAAQG,2BACvB,IAAItS,UAAYA,SAASmW,gBACrB1gB,MAAQuK,SAASmW,oBACd,CAAA,IAAI7F,SAAS6F,gBAGhB,KAAM,IAAIxS,OAAMwS,eAAiB,+CAAiDA,eAAiB,cAFnG1gB,OAAQ6a,SAAS6F,iBAKzB,MAAO1gB,OAEX,IAAIgI,SAAUjK,eAAe2E,SAC7B,IAAIie,yBAA0BnkB,UAAUuB,gBACpCkK,YAAa,SAAUjD,SACnBvD,KAAK+L,eAAiB,GAAIN,eAC1B,IAAI0T,qBAAsBnf,KAAK+L,eAAeC,iBAAiBzI,QAE/D,IAAI6b,SAAUliB,WAAWiiB,oBAAoBpU,OAM7C,IALKoU,oBAAoB3hB,MAErB2hB,oBAAoB3hB,IAAM4hB,QAAQthB,SAAW,MAAQshB,QAAQniB,KAAO,sBAGlCgB,SAAlCkhB,oBAAoBE,UAAyB,CAC7C,GAAI9P,UAAW4P,oBAAoB5P,QACnC,IAAI8B,QAAS8N,oBAAoB9N,MACjC,IAAI3F,OAAQyT,oBAAoBzT,KAChC,KAAK6D,UAAY8B,SAAW3F,MAAO,CAC/B,GAAI4T,UAAW/P,SAAW,WAAa,QACvC,IAAIgQ,MACAC,cAAe,UAAY9T,MAE/B6T,KAAID,UAAY/P,SAAWA,SAAW8B,OAEtC8N,oBAAoBE,WAChBE,IAAKA,MAMjB,MADAvf,MAAKuD,QAAU4b,oBACR5Y,QAAQC,YAAYE,KAAK1G,KAAMmf,sBAmB1CM,WAAY,SAAUlc,SACdA,SAA8B,gBAAZA,WAClBA,SACIsD,KAAMtD,SAGd,IAAImc,aAAcpiB,EAAEM,UAAWoC,KAAKuD,QAASA,QAC7C,IAAIsD,MAAO6Y,YAAY7Y,IACvB,KAAKA,KACD,KAAM,IAAI4F,OAAM,6BAGpB,KAAKiT,YAAYC,iBAAkB,CAC/B,GAAIC,WAAY/Y,KAAKvH,MAAM,IAC3B,IAAIugB,aAAcD,UAAU,EAC5B,IAAIA,UAAUzf,OAAS,EACnB,KAAM,IAAIsM,OAAM,4FAEpB,KAAKoS,WAAWgB,aACZ,KAAM,IAAIpT,OAAM,wBAGxB,MAAOlG,SAAQkZ,WAAWte,MAAMnB,KAAMoB,YAsB1C0e,gBAAiB,SAAU9N,WACvBA,UAAYgN,gCAAgChN,UAAW,YAAahS,KAAKuD,QACzE,IAAIoI,SAAUqT,gCAAgC,GAAI,UAAWhf,KAAKuD,QAClE,IAAIqI,SAAUoT,gCAAgC,GAAI,UAAWhf,KAAKuD,QAElE,IAAIwc,YAAa,SAAUpU,QAASC,QAASoG,WAAWnT,KAAK,IAC7D,OAAO0H,SAAQkZ,WAAW/Y,KAAK1G,MAAQ6G,KAAMkZ,aAiCjDC,gBAAiB,SAAUrE,MAAO3J,WAC9B,GAAIiO,SAAW3iB,EAAE0B,cAAc2c,QAAUA,MAAM1V,GAAM0V,MAAM1V,GAAK0V,KAChE,KAAKsE,QACD,KAAM,IAAIxT,OAAM,4BAEpBuF,WAAYgN,gCAAgChN,UAAW,YAAahS,KAAKuD,QACzE,IAAIoI,SAAUqT,gCAAgC,GAAI,UAAWhf,KAAKuD,QAClE,IAAIqI,SAAUoT,gCAAgC,GAAI,UAAWhf,KAAKuD,QAElE,IAAIwc,YAAa,SAAUpU,QAASC,QAASoG,UAAWiO,SAASphB,KAAK,IACtE,OAAO0H,SAAQkZ,WAAW/Y,KAAK1G,MAAQ6G,KAAMkZ,aAmCjDG,eAAgB,SAAUvE,MAAOhK,KAAMK,WACnC,GAAIiO,SAAW3iB,EAAE0B,cAAc2c,QAAUA,MAAM1V,GAAM0V,MAAM1V,GAAK0V,KAChE,KAAKsE,QACD,KAAM,IAAIxT,OAAM,4BAEpB,IAAI0T,QAAU7iB,EAAE0B,cAAc2S,OAASA,KAAK1L,GAAM0L,KAAK1L,GAAK0L,IAC5DwO,QAASnB,gCAAgCmB,OAAQ,SAAUngB,KAAKuD,SAChEyO,UAAYgN,gCAAgChN,UAAW,YAAahS,KAAKuD,QAEzE,IAAIoI,SAAUqT,gCAAgC,GAAI,UAAWhf,KAAKuD,QAClE,IAAIqI,SAAUoT,gCAAgC,GAAI,UAAWhf,KAAKuD,QAElE,IAAIwc,YAAa,QAASpU,QAASC,QAASoG,UAAWiO,QAASE,QAAQthB,KAAK,IAC7E,OAAO0H,SAAQkZ,WAAW/Y,KAAK1G,MAAQ6G,KAAMkZ,aAgCjDK,mBAAoB,SAAUzE,MAAOwE,OAAQnO,WACzC,GAAIiO,SAAW3iB,EAAE0B,cAAc2c,QAAUA,MAAM1V,GAAM0V,MAAM1V,GAAK0V,KAChE,KAAKsE,QACD,KAAM,IAAIxT,OAAM,4BAEpB0T,QAASnB,gCAAgCmB,OAAQ,SAAUngB,KAAKuD,SAChEyO,UAAYgN,gCAAgChN,UAAW,YAAahS,KAAKuD,QAEzE,IAAIoI,SAAUqT,gCAAgC,GAAI,UAAWhf,KAAKuD,QAClE,IAAIqI,SAAUoT,gCAAgC,GAAI,UAAWhf,KAAKuD,QAElE,IAAIwc,YAAa,QAASpU,QAASC,QAASoG,UAAWiO,SAASphB,KAAK,IACrE,IAAIwhB,SAAU9Z,QAAQkZ,WAAW/Y,KAAK1G,MAAQ6G,KAAMkZ,WAEpD,IAAIO,gBAEJ,IAAIC,eAAgB,GAqBpB,OApBAF,SAAQrC,UAAU,wBAAyB,SAAUwC,cACjD,GAAIC,gBAAiBD,aAAa7c,KAAKgO,IAClC2O,cAAaG,iBAAmBA,iBAAmBN,QACpDE,QAAQzB,QAAQlY,KAAK2Z,QAAS,YAAchP,OAAQoP,eAAgBC,QAAQ,IAEhFJ,aAAaG,iBAAkB,GAAKpO,OAAQsO,YAGhDC,YAAY,WACRP,QAAQhC,QAAQ,yBAA2B1M,KAAMwO,SAEjD7iB,EAAEe,KAAKiiB,aAAc,SAAUhiB,IAAKC,OAChC,GAAIsiB,MAAM,GAAKxO,OAAQsO,SACnBpiB,QAASA,MAAyB,EAAhBgiB,cAAqBM,MACvCP,aAAahiB,KAAO,KACpB+hB,QAAQzB,QAAQlY,KAAK2Z,QAAS,YAAchP,OAAQ/S,IAAKoiB,QAAQ,QAG1EH,eAEIF,SA6BXS,eAAgB,SAAUC,YACtB,IAAKA,WACD,KAAM,IAAItU,OAAM,4CAEpB,IAAId,SAAUqT,gCAAgC,GAAI,UAAWhf,KAAKuD,QAClE,IAAIqI,SAAUoT,gCAAgC,GAAI,UAAWhf,KAAKuD,QAClE,IAAIwc,YAAa,QAASpU,QAASC,QAASmV,YAAYliB,KAAK,IAC7D,IAAIwhB,SAAU9Z,QAAQkZ,WAAW/Y,KAAK1G,MAAQ6G,KAAMkZ,WAGpD,IAAIiB,SAAUX,QAAQrC,SAkBtB,OAjBAqC,SAAQrC,UAAY,SAAUJ,MAAO7gB,SAAUkhB,QAAS1a,SACpD,GAAI0d,uBAAwB,SAAUC,SAClC,GAAIlK,OACAlN,KAAMoX,QAAQb,QACdc,QAASD,QAAQvd,KAAKwd,QACtBC,KAAMF,QAAQvd,KAAKyd,KAEvB,IAAIC,YAAaH,QAAQvd,KAAKA,IAC1B0d,YAAW1d,OACX0d,WAAaA,WAAW1d,MAG5B5G,SAAS2J,KAAKuX,QAASoD,WAAYrK,MAEvC,OAAOgK,SAAQta,KAAK2Z,QAASzC,MAAOqD,sBAAuBhD,QAAS1a,UAGjE8c,UAIf1jB,QAAOC,QAAUsiB;;AO5XjB,YAEAviB,QAAOC,SACH4kB,gBAAiB,sBACjB1E,qBAAsB;;AjB8C1B,YAMA,SAAS1F,iBAAgB7c,QAASC,SAC9B,GAAID,QAAQ8c,QACR,MAAO9c,QAGX,IAAI+c,MAAO/c,QAAQ6S,EAYnB,OAXA7S,SAAQ6S,GAAK,SAAUrK,UAAWE,OAAQM,SACtC,GAAIgU,aAAcC,OAAOlI,KAAKmI,kBAC9B,OAAIF,aAAY5X,QAAQoD,cAAe,EAC5BuU,KAAKnW,MAAM5G,QAAS6G,WAEpBqW,kBAAkB1U,WAAW2D,KAAKnM,QAAS0I,OAAQM,QAAS/I,UAI3ED,QAAQ8c,SAAU,EAEX9c,QAcX,QAAS2B,YAAWqH,SAChBvD,KAAKuD,QAAUjG,EAAEM,QAAO,KAAUyJ,SAAU9D,SAExCvD,KAAKuD,QAAQzI,cAAe6b,YAC5B3W,KAAKlF,IAAMkF,KAAKuD,QAAQzI,IAExBkF,KAAKlF,IAAM,GAAI6b,YAAW3W,KAAKuD,QAAQzI,KAG3Csc,gBAAgBpX,KAAKlF,IAAKkF,KAE1B,IAAI0X,cAAgD,kBAA1B1X,MAAKuD,QAAQ9I,SAA0BuF,KAAKuD,QAAQ9I,SAAWkd,cAAc3X,KAAKuD,QAAQ9I,SAEpH,KAAKid,aACD,KAAM,IAAIjL,OAAM,+CAAgDzM,KAAKuD,QAAQ9I,SAGjFuF,MAAKvF,SAAW,GAAIid,cAAa1X,KAAKlF,IAAKkF,KAAKuD,SArDpD,GAAIoU,eAAgBhd,QAAQ,kCAC5B,IAAI8c,mBAAoB9c,QAAQ,uBAChC,IAAIgc,YAAahc,QAAQ,6BAyBzB,IAAI0M,WAMA5M,SAAU,qBAuBdyB,YAAW+E,WAqBPkW,OAAQ,WACJ,MAAOnX,MAAKvF,SACH0c,UAmBbS,MAAO,SAAUC,mBACb,MAAO7X,MAAKvF,SAASmd,MAAMC,qBAInClb,OAAOC,QAAUV;;AG1JjB,YAEA,IAAInB,WAAYJ,QAAQ,qBACxB,IAAI0hB,qBAAsB1hB,QAAQ,kCAElC,IAAI4L,SAAU8V,oBAAoBpb,SAElC,IAAIqb,UAAWvhB,UAAUshB,qBACrB7V,YAAa,SAAU6H,WAAY9K,SAC/BgD,QAAQC,YAAYE,KAAK1G,KAAMqO,WAAYrO,KAAKuc,SAAUhZ,UAG9DgZ,SAAU,SAAUzhB,IAAKyM,SAErB,OAAO,IAIf5K,QAAOC,QAAU0f;;AClBjB,YAeA,SAASE,iBAAgBC,WAAY3hB,IAAKiR,gBACtCA,eAAe2Q,WAAWvR,IAAIsR,WAAYxd,KAAKC,WAAY+Q,MAAOnV,IAAImL,MAd1E,GAAI0W,SAAUhiB,QAAQ,2BACtB,IAAIiiB,MAAOjiB,QAAQ,sBACnB,IAAI8Q,gBAAiB9Q,QAAQ,8BAC7B,IAAII,WAAYJ,QAAQ,qBACxB,IAAIwB,aAAcxB,QAAQ,kBAE1B,IAAIkiB,UAAWliB,QAAQ,eAEvB,IAAI0M,WACAoV,WAAYI,SAASC,qBACrBhT,KAAM,GAcV,IAAIwS,UAAWvhB,UAAU6hB,MACrBpW,YAAa,SAAkB6H,WAAY0O,UAAWxZ,SAElD,GAAiB,MAAbwZ,UACA,KAAM,IAAItQ,OAAM,2DAGpBzM,MAAK4b,MAAQ,GAAIzf,aACjB6D,KAAKlF,IAAM6hB,QAAQtO,YACnBrO,KAAK+c,UAAiC,kBAAdA,WAA2B,WAAc,MAAOA,YAAeA,UACvF/c,KAAKuD,QAAUjG,EAAEM,QAAO,KAAUyJ,SAAU9D,SAC5CvD,KAAK+L,eAAiB,GAAIN,gBAAelI,SACzCvD,KAAKgd,WAAahd,KAAKuD,QAAQzI,KAGnCmiB,oBAAqB,WACjB,GAAIC,aAAcld,KAAK4b,MAAMR,2BAC7B,OAAO9d,GAAEM,QACLmW,OAAStD,MAAOyM,YAAYlL,YAC7BhS,KAAKgd,aAGZpF,MAAO,SAAUC,mBACb,GAAIjW,OAAQ5B,IACZ,IAAI4S,KAAM5S,KAAKid,qBAEf,OAAOjd,MAAKlF,IACH6R,OAAOiG,IAAKiF,mBAChBvX,KAAK,SAAUxF,KAGZ,MAFA0hB,iBAAgB5a,MAAM2B,QAAQkZ,WAAY3hB,IAAK8G,MAAMmK,gBACrDjR,IAAIqiB,gBAAiB,EACdriB,MAEV6G,SAGTwV,OAAQ,WACJ,GAAIiG,cAAepd,KAAK+L,eAAe2Q,UACvC,IAAIW,YAAape,KAAK6Z,MAAMsE,aAAahY,IAAIpF,KAAKuD,QAAQkZ,YAE1D,OAAIY,aAAcA,WAAWpN,MAClBjQ,KAAKsd,cAAcD,YAAYxf,KAAK,WACvC,MAAOmC,MAAK4X,SACd9V,KAAK9B,OAEAA,KAAK4X,SAIpB0F,cAAe,SAAUD,YACrB,GAAIE,eAAe,CACnB,IAAI3b,OAAQ5B,IAEZ,OAAOA,MAAKlF,IACPJ,KAAK2iB,WAAWpN,MAAO,MACpB3L,QAAS,SAAUxJ,IAAK0iB,IAAKjW,SACzBgW,aAAe3b,MAAMmb,UAAUrW,KAAK9E,MAAO9G,IAAKyM,YAGvDjH,KAAK,SAAUxF,KACZ,GAAIyiB,aAAc,CACd,GAAI3K,KAAMhR,MAAMqb,qBAGhB,OAAOrb,OAAM9G,IAAI2G,SAASkL,OAAOiG,KAChCtS,KAAK,SAAUxF,KAGZ,MAFA0hB,iBAAgB5a,MAAM2B,QAAQkZ,WAAY3hB,IAAK8G,MAAMmK,gBACrDjR,IAAIqiB,gBAAiB,EACdriB,MAIf,MAAOA,OAEV6G,UAIbhF,QAAOC,QAAU0f;;ACxGjB,YAEA,IAAIvhB,WAAYJ,QAAQ,qBACxB,IAAIiiB,QAGJjgB,QAAOC,QAAU7B,UAAU6hB,MACvBpW,YAAa,SAAU6H,WAAY9K,SAC/BvD,KAAKqO,WAAcA,YAGvBuJ,MAAO,WAEH,MAAOta,GAAEkD,WAAWC,UAAUC,WAGlCyW,OAAQ,WAEJ,MAAO7Z,GAAEkD,WAAWC,QAAQT,KAAKqO,YAAY3N;;AgBlBrD,YAEA,IAAI3F,WAAYJ,QAAQ,qBAExB,IAAIy1B,kBAAmBz1B,QAAQ,sBAC/B,IAAIq2B,iBAAkBr2B,QAAQ,kCAC9B,IAAIwB,aAAcxB,QAAQ,kBAE1B,IAAI0M,WACA/M,OACImnB,aAAa,GAIrB,IAAInF,UAAWvhB,UAAUq1B,kBAErB5pB,YAAa,SAAU6H,WAAY9K,SAC/BvD,KAAKqO,WAAaA,WAClBrO,KAAKuD,QAAUjG,EAAEM,QAAO,KAAUyJ,SAAU9D,SAC5CvD,KAAK4b,MAAQ,GAAIzf,aACjB6D,KAAK0wB,SAAW1wB,KAAK0wB,SAAS5uB,KAAK9B,MACnCA,KAAKyb,SAAW,GAAIuV,iBAAgBhxB,KAAKuD,QAAQzI,MAGrD8c,MAAO,WACH,GAAIqD,SAAUjb,KAAK4b,MAAMR,2BACzB,IAAIe,WAAYlB,QAAQ5J,MACxB,IAAI+K,cAAenB,QAAQjJ,SAE3B,OAAOhS,MAAKyb,SACP1J,uBAAuBoK,UAAWC,cAClC9b,KAAK,SAAUqb,OACZ,MAAO3b,MAAKyb,SAAShJ,eAAekJ,MAAM1V,KAC5CnE,KAAK9B,QAGfmX,OAAQ,WACJ,GAAI8D,SAAUjb,KAAK4b,MAAMR,2BACzB,IAAIe,WAAYlB,QAAQ5J,MACxB,IAAI+K,cAAenB,QAAQjJ,SAC3B,IAAIyJ,UAAWzb,KAAKyb,QACpB,IAAI3O,OAAQ9M,KAAKuD,QAAQuJ,KACzB,IAAIlL,OAAQ5B,IACZ,IAAIiE,KAAM3G,EAAEkD,UAEZ,KAAK2b,UACD,MAAOlY,KAAIsB,QAASiC,WAAY,IAAK/C,MAAO,0FAA4FwW,SAASva,SAGrJ,IAAIuwB,kBAAmB,SAAUtV,OAC7B,MAAKA,OAIEF,SAAS3J,iBAAkBhF,MAAOA,MAAOjB,OAAQ8P,MAAM1V,KACzD3F,KAAKsB,MAAM8uB,UACXpwB,KAAK2D,IAAIxD,SACT5C,KAAKoG,IAAIsB,QANHtB,IAAIsB,QAASiC,WAAY,IAAK/C,MAAO,kCAAqClB,QAASvD,KAAKuD,QAAS0X,QAASA,UASzH,IAAIiW,aAAc,SAAUzsB,OAExBR,IAAIsB,OAAOd,MAAOwW,QAASjb,KAAKuD,SAQpC,OALAvD,MAAKyb,SACA1J,uBAAuBoK,UAAWC,cAClC9b,KAAK2wB,kBACLpzB,KAAKqzB,aAEHjtB,IAAIvD,WAGfgwB,SAAU,SAAUzqB,GAAI1C,SACpB,MAAOvD,MAAKqO,WAAW3T,KAAKuL,GAAI,KAAM1C,WAI9C5G,QAAOC,QAAU0f;;Ab9EjB,YACA,IAAIvhB,WAAYJ,QAAQ,qBACxB,IAAI0hB,qBAAsB1hB,QAAQ,kCAElC,IAAI4L,SAAU8V,oBAAoBpb,SAElC,IAAIqb,UAAWvhB,UAAUshB,qBACrB7V,YAAa,SAAU6H,WAAY9K,SAC/BgD,QAAQC,YAAYE,KAAK1G,KAAMqO,WAAYrO,KAAKuc,SAAUhZ,UAG9DgZ,SAAU,SAAUzhB,IAAKyM,SACrB,MAA+C,eAAxCA,QAAQkW,kBAAkB,WAA8B3iB,IAAI4iB,cAI3E/gB,QAAOC,QAAU0f;;AFhBjB,YAEA,IAAIvhB,WAAYJ,QAAQ,qBACxB,IAAI0hB,qBAAsB1hB,QAAQ,kCAElC,IAAI4L,SAAU8V,oBAAoBpb,SAMlC,IAAIqb,UAAWvhB,UAAUshB,qBACrB7V,YAAa,SAAU6H,WAAY9K,SAC/BgD,QAAQC,YAAYE,KAAK1G,KAAMqO,WAAYrO,KAAKuc,SAAUhZ,UAG9DgZ,SAAU,SAAUzhB,IAAKyM,SAErB,OAAO,IAIf5K,QAAOC,QAAU0f;;ACtBjB,YACA,IAAIvhB,WAAYJ,QAAQ,qBACxB,IAAI0hB,qBAAsB1hB,QAAQ,kCAElC,IAAI4L,SAAU8V,oBAAoBpb,SAElC,IAAIqb,UAAWvhB,UAAUshB,qBACrB7V,YAAa,SAAU6H,WAAY9K,SAC/BgD,QAAQC,YAAYE,KAAK1G,KAAMqO,WAAYrO,KAAKuc,SAAUhZ,UAG9DgZ,SAAU,SAAUzhB,IAAKyM,SACrB,MAA+C,eAAxCA,QAAQkW,kBAAkB,YAIzC9gB,QAAOC,QAAU0f;;AahBjB,YAEA,IAAIvhB,WAAYJ,QAAQ,qBACxB,IAAIy1B,kBAAmBz1B,QAAQ,sBAC/B,IAAI2mB,gBAAiB3mB,QAAQ,4BAC7B,IAAI01B,UAAW11B,QAAQ,kCACvB,IAAIwB,aAAcxB,QAAQ,kBAE1B,IAAIkiB,UAAWliB,QAAQ,eAEvB,IAAI0M,WACA/M,OACImnB,aAAa,GAIrB,IAAInF,UAAWvhB,UAAUq1B,kBACrB5pB,YAAa,SAAkB6H,WAAY9K,SACvCvD,KAAKlF,IAAMuT,WACXrO,KAAKuD,QAAUjG,EAAEM,QAAO,KAAUyJ,SAAU9D,SAC5CvD,KAAKgd,WAAahd,KAAKuD,QAAQzI,IAC/BkF,KAAKswB,OAAS,GAAIhP,gBAAethB,KAAKuD,QAAQjJ,OAC9C0F,KAAKuwB,SAAW,GAAIF,UACpBrwB,KAAK4b,MAAQ,GAAIzf,aAEjB6D,KAAKsd,cAAgBtd,KAAKsd,cAAcxb,KAAK9B,MAC7CA,KAAKwwB,YAAcxwB,KAAKwwB,YAAY1uB,KAAK9B,MACzCA,KAAKywB,YAAczwB,KAAKywB,YAAY3uB,KAAK9B,MACzCA,KAAK0wB,SAAW1wB,KAAK0wB,SAAS5uB,KAAK9B,OAGvC4X,MAAO,SAAUC,mBACb,GAAIoD,SAAUjb,KAAK4b,MAAMR,2BACzB,IAAIxI,KAAMtV,EAAEM,QACRmW,OAAStD,MAAOwK,QAAQjJ,YACzBhS,KAAKgd,WAER,OAAOhd,MAAKlF,IACP6R,OAAOiG,IAAKiF,mBACZvX,KAAK,SAAUxF,KAEZ,MADAA,KAAIqiB,gBAAiB,EACdriB,OAInBqc,OAAQ,WACJ,MAAOnX,MAAKywB,cACPnwB,KAAKN,KAAKsd,gBAGnBmT,YAAa,WACT,GAAIxV,SAAUhc,KAAK6Z,MAAM9Y,KAAKswB,OAAOlrB,IAAIyX,SAAS2E,kBAAoB,KACtE,OAAOxhB,MAAKlF,IAAIF,OACZ+1B,UAAW1V,QAAQ5J,QAAU,OAC7Buf,cAAe3V,QAAQjJ,aAI/BsL,cAAe,SAAUvX,MACrB,IAAKA,OAASA,KAAK5F,OACf,MAAOH,MAAK4X,OAGhB,IAAIiZ,UAAW,SAAU1e,EAAGC,GAAK,MAAO,IAAIC,MAAKD,EAAEgP,MAAQ,GAAI/O,MAAKF,EAAEiP,MACtE,IAAI0P,WAAY/qB,KAAKmM,KAAK2e,UAAU,EACpC,IAAIjvB,OAAQ5B,IACZ,IAAI+wB,eAAe,CAEnB,OAAO/wB,MAAKlF,IAAIJ,KAAKo2B,UAAU7qB,GAAI,MAC/B3B,QAAS,SAAUxJ,IAAK0iB,IAAKjW,SACzBwpB,aAAuD,eAAxCxpB,QAAQkW,kBAAkB,aAE9Cnd,KAAK,SAAUxF,KACd,MAAOi2B,cAAenvB,MAAM4uB,YAAY11B,IAAImL,IAAMnL,OAI1D01B,YAAa,SAAUvgB,OACnB,GAAIrO,OAAQ5B,IACZ,OAAOA,MAAKuwB,SAASrgB,QAASD,MAAOA,QAChC3P,KAAK,SAAUoP,MACZ,MAAO9N,OAAM8uB,SAAShhB,KAAK5U,QAIvC41B,SAAU,SAAUzqB,GAAI1C,SACpB,MAAOvD,MAAKlF,IAAIJ,KAAKuL,GAAI,KAAM1C,WAKvC5G,QAAOC,QAAU0f;;AN3FjB3f,OAAOC,SACHylB,qBAAsB1nB,QAAQ,iCAC9B2nB,mBAAoB3nB,QAAQ,+BAC5B4nB,iBAAkB5nB,QAAQ,6BAC1B6nB,aAAc7nB,QAAQ,yBACtB8nB,YAAe9nB,QAAQ,0BACvB+nB,2BAA4B/nB,QAAQ,uCACpCgoB,KAAQhoB,QAAQ;;AfPpB,YAOA,SAASsB,iBAAgBsH,SACrBvD,KAAKuD,QAAUjG,EAAEM,QAAO,KAAUyJ,SAAU9D,SAC5CvD,KAAKqO,WAAarO,KAAKuD,QAAQzI,KAAO,GAAI6b,YAAW3W,KAAKuD,SAR9D,GAAIoT,YAAahc,QAAQ,6BAEzB,IAAI0M,WACAuP,aAAeC,OAAO,GAQ1B5a,iBAAgBgF,WACZ6V,QAAS,SAAUjL,QAEf,MADA7L,MAAK6L,OAASvO,EAAEM,QAAO,KAAUoC,KAAKuD,QAAQqT,YAAa/K,QACpD7L,KAAKqO,WAAWzT,MAAMoF,KAAK6L,SAGtCkL,cAAe,SAAU5Q,MACrB,MAAOnG,MAAKqO,WAAWzT,MAAMoF,KAAK6L,QAAU9H,QAASoC,QAGzD+G,KAAM,SAAUpS,IAAKkc,MACjB,MAAOhX,MAAKiX,YAAYnc,KAAKoS,KAAK5P,EAAEM,QAAO,MAAYiZ,OAAO,GAAQG,QAG1EE,QAAS,SAAUpc,KACf,MAAOkF,MAAKiX,YAAYnc,KAAKoS,MAAO2J,OAAO,KAG/CI,YAAa,SAAUnc,KACnB,GAAmB,gBAARA,KACP,MAAO,IAAI6b,YAAWrZ,EAAEM,QAAO,KAAWoC,KAAKuD,SAAWsI,OAAQ/Q,MAGtE,IAAmB,gBAARA,MAAoBA,cAAe6b,YAC1C,MAAO7b,IAGX,MAAM,IAAI2R,OAAM,kDAGpB0K,OAAQ,SAAUlH,OACd,MAAO,IAAI0G,YAAWrZ,EAAEM,QAAO,KAAWoC,KAAKuD,SAAWsI,OAAQoE,WAI1EtT,OAAOC,QAAUX;;AgB/CjB,YAGAU,QAAOC,SACHgb,MAAO,SAAU3U,OAAQM,QAAS/I,SAC9B,MAAOA,SAAQod,MAAMrU;;Ab8B7B,YAgBA,SAASiY,eAAclK,QAASrN,KAE5B,MAAO,UAAcoK,WAAY9K,SAC7BvD,KAAKqO,WAAaA,WAClBrO,KAAKuD,QAAUA,QAEfjG,EAAEM,OAAOoC,MACL4X,MAAO,WACH,KAAM,IAAInL,OAAM,qCAGpB0K,OAAQ,WACJ,GAAIvV,OAAQ5B,IAGZ,IAAI8M,OAAQ9M,KAAKuD,QAAQzI,IAAIgS,OAAS9M,KAAKuD,QAAQuJ,KACnD,OAAO2O,UAAS3J,iBAAkBhF,MAAOA,MAAOjB,OAAQyF,UACnDhR,KAAK,SAAU2P,OACZ,MAAOrO,OAAMyM,WAAW3T,KAAKuV,SAEhC3P,KAAK,SAAUxF,KACZmJ,IAAIxD,QAAQiG,KAAK1G,KAAMlF,IAAK8G,MAAMyM,cAErCxQ,KAAKoG,IAAIsB,YArC9B,GAAImW,UAAW/gB,QAAQ,+BACvB,IAAIuB,YAAcvB,QAAQ,gBAC1B,IAAIwB,aAAcxB,QAAQ,iBAC1B,IAAI8gB,SA0CJ9e,QAAOC,QAAU,SAAU2G,SACvBvD,KAAKuD,QAAUA,UAAazI,OAAS6gB,UAErCre,EAAEM,QAAO,EAAMoC,KAAKuD,QAASvD,KAAKuD,QAAQzI,KAC1CwC,EAAEM,QAAO,EAAMoC,KAAKuD,QAASvD,KAAKuD,QAAQoY,OAE1CF,SAAW,GAAIC,UAAS1b,KAAKuD,SAC7BvD,KAAK4b,MAAQ,GAAIzf,YACjB,IAAIyF,OAAQ5B,IAEZ,IAAIvD,MAiBAof,gBAAiB,SAAUxK,OAAQW,WAC/B,GAAIiJ,SAAUjb,KAAK4b,MAAMR,2BAOzB,OANK/J,UACDA,OAAS4J,QAAQ5J,QAEhBW,YACDA,UAAYiJ,QAAQjJ,WAEjByJ,SAAS1J,uBAAuBV,OAAQW,YAiBnD8J,cAAe,SAAUhP,OAMrB,QAASiP,wBAAuBJ,OAC5B,IAAKA,MACD,MAAO1X,KAAIsB,QAASd,MAAO,sCAG/B,IAAIuX,gBAAiBL,MAAM1V,EAC3B,IAAIgW,SAAU3e,EAAEM,QAAO,EAAMgE,MAAM2B,SAAWuJ,MAAOA,OACrD,IAAIrS,UAAW+gB,cAAcQ,eAAgB/X,IAC7C,IAAI2O,KAAMtV,EAAEM,QAAO,MACfnD,SAAUA,SACVK,IAAKmhB,SAET,IAAIC,IAAK,GAAIhgB,YAAW0W,IAExB,OAAOsJ,IAAG/E,SACL7W,KAAK,SAAUxF,KACZmJ,IAAIxD,QAAQ3F,IAAKohB,GAAG7N,WAAY6N,MArB5C,GAAIjY,KAAM3G,EAAEkD,UACZ,IAAIya,SAAUjb,KAAK4b,MAAMR,2BACzB,IAAIe,WAAYlB,QAAQ5J,MACxB,IAAI+K,cAAenB,QAAQjJ,SAyB3B,OAHAhS,MAAK6b,gBAAgBM,UAAWC,cAC3B9b,KAAKyb,wBAEH9X,IAAIvD,WAInBpD,GAAEM,OAAOoC,KAAMvD;;Af/JnB,YAEA,IAAI2O,eAAgBzQ,QAAQ,0BAC5B,IAAI4Q,kBAAmB5Q,QAAQ,sCAC/B,IAAI8Q,gBAAiB9Q,QAAQ,2BAE7BgC,QAAOC,QAAU,SAAUwK,QACvB,GAAIC,WAMAqE,MAAOzN,OAMP0N,QAAS1N,OAMT2N,QAAS3N,OAMTqQ,WAAY,SAOZjU,aAGJ2F,MAAK+L,eAAiB,GAAIN,eAC1B,IAAIX,gBAAiB9K,KAAK+L,eAAeC,iBAAiB3E,SAAUD,OACpE,IAAI6E,WAAY,GAAIb,eAAcN,gBAAgB1F,IAAI,SAClD0F,gBAAea,UACfM,UAAU5B,YAAcS,eAAea,SAEvCb,eAAec,UACfK,UAAU1B,YAAcO,eAAec,QAG3C,IAAItI,aAAchG,EAAEM,QAAO,KAAUkN,eAAezQ,WAChDmD,IAAKyO,UAAUvB,WAAW,SAG1BI,gBAAeY,QACfpI,YAAYiE,SACRgF,cAAiB,UAAYzB,eAAeY,OAGpD,IAAIlI,MAAO,GAAI+H,kBAAiBjI,YAEhC,IAAIoJ,iBAMA6B,YAAa,SAAUC,SAAUjL,SAC7B,GAAIuG,MAAOgB,eAAewD,WAAa,IAAME,QAC7C,IAAIlL,aAAchG,EAAEM,QAAO,KAAUkN,eAAgBvH,SACjD/F,IAAKyO,UAAUvB,WAAW,QAAUZ,MAExC,OAAOtG,MAAK4B,IAAI,GAAI9B,cASxBmL,YAAa,SAAUD,SAAUE,SAAUnL,SACvCiL,SAAWA,SAASlP,MAAM,IAC1B,IAAIqP,UAAWH,SAASzJ,KACxByJ,UAAWA,SAAS3P,KAAK,IACzB,IAAIiL,MAAOgB,eAAewD,WAAa,IAAME,QAC7C,IAAII,UAAW,0CAEf,IAAIC,MAAO,KAAOD,SAAW,6DAEVD,SAAW,uCAE1BD,SAAW,SACJE,SAAW,IAEtB,IAAItL,aAAchG,EAAEM,QAAO,KAAUkN,eAAgBvH,SACjD/F,IAAKyO,UAAUvB,WAAW,QAAUZ,KACpCnG,KAAMkL,KACNvH,YAAa,iCAAmCsH,UAGpD,OAAOpL,MAAK6F,IAAIwF,KAAMvL,cAQ1BwL,OAAQ,SAAUN,SAAUjL,SACxB,GAAIuG,MAAOgB,eAAewD,WAAa,IAAME,QAC7C,IAAIlL,aAAchG,EAAEM,QAAO,KAAUkN,eAAgBvH,SACjD/F,IAAKyO,UAAUvB,WAAW,QAAUZ,MAExC,OAAOtG,MAAK8F,OAAO,KAAMhG,cAS7ByL,OAAQ,SAAUP,SAAUQ,QAASzL,SACjC,GAAIuG,MAAOgB,eAAewD,WAAa,IAAME,QAC7C,IAAIlL,aAAchG,EAAEM,QAAO,KAAUkN,eAAgBvH,SACjD/F,IAAKyO,UAAUvB,WAAW,QAAUZ,MAExC,OAAOtG,MAAK4F,OAAQpG,KAAQgM,SAAW1L,cAI/ChG,GAAEM,OAAOoC,KAAM0M;;AQvFnB,YAEA,IAAItB,eAAgBzQ,QAAQ,0BAC5B,IAAI4Q,kBAAmB5Q,QAAQ,sCAC/B,IAAI2Q,OAAQ3Q,QAAQ,uBAAuB2Q,KAC3C,IAAIG,gBAAiB9Q,QAAQ,2BAE7B,IAAIoV,aAAc,OAElBpT,QAAOC,QAAU,SAAUwK,QACvB,GAAIC,WAMAqE,MAAOzN,OAKP0N,QAAS1N,OAKT2N,QAAS3N,OAKTwS,MAAOxS,OAKPoT,OAAQpT,OAKR8V,MAAO,OAKPC,SAAS,EAKT3Z,WACI4Z,aAAa,GAGrBjU,MAAK+L,eAAiB,GAAIN,eAC1B,IAAIX,gBAAiB9K,KAAK+L,eAAeC,iBAAiB3E,SAAUD,OACpE,IAAI6E,WAAY,GAAIb,eAAcN,gBAAgB1F,IAAI,SAEjD0F,gBAAea,UAChBb,eAAea,QAAUM,UAAU5B,aAGlCS,eAAec,UAChBd,eAAec,QAAUK,UAAU1B,YAGvC,IAAI1C,kBAAmBvK,EAAEM,QAAO,KAAUkN,eAAezQ,WACrDmD,IAAKyO,UAAUvB,WAAWqF,cAG1BjF,gBAAeY,QACf7D,iBAAiBN,SACbgF,cAAiB,UAAYzB,eAAeY,OAIpD,IAAIlI,MAAO,GAAI+H,kBAAiB1D,iBAEhC,IAAIqM,iBAAkB,WAAY,OAAQ,cAC1C,IAAIC,cACAxC,MAAO,QAAS,UAAW,UAAW,QAAS,UAC/ClB,OAAQ,QAAS,UAAW,UAAW,SACvC7E,SAAU,QAAS,UAAW,WAGlC,IAAIwI,kBAAmB,SAAUC,UAC7B,IAAKA,SACD,KAAM,IAAI5H,OAAM,uBAIxB,IAAI6H,mBAAoB,SAAU/Q,SAC9B,GAAIgR,UAAWJ,YAAY5Q,QAAQwQ,MACnC,KAAKQ,SACD,KAAM,IAAI9H,OAAM,6BAGpBnP,GAAEe,KAAKkW,SAAU,WACb,IAAKhR,QAAQvD,MACT,KAAM,IAAIyM,OAAMzM,KAAO,2BAKnC,IAAIwU,UAAW,SAAUH,SAAU9Q,SAC/B+Q,kBAAkB/Q,QAClB,IAAIgR,UAAWJ,YAAY5Q,QAAQwQ,MACnC,IAAIU,OAAQnX,EAAE4H,IAAIqP,SAAU,SAAUjW,KAClC,MAAOiF,SAAQjF,MAOnB,OALI+V,YAGAA,SAAW,IAAMA,UAEdpI,UAAUvB,WAAWqF,aAAe0E,MAAM5V,KAAK,KAAOwV,SAUjE,IAAIK,QAAS,SAAUzM,OAAQoM,SAAUpR,OAAQM,SAC7C6Q,iBAAiBC,UAEjBpM,OAASA,OAAO0M,aAChB,IAAIrN,aAAcrE,iBAAkB2R,YAAa,GAAe,kBAC5C,sBAAhBtN,YAEArE,OAASqI,MAAMrI,OAAQiR,gBAIvBG,SAAsB,SAAXpM,QAAgC,QAAXA,OAAmB,GAAKoM,QAE5D,IAAIQ,YAAavX,EAAEM,UAAWkN,eAAgBvH,QAC9C,IAAI/F,KAAMgX,SAASH,SAAUQ,WAC7B,IAAIjI,eAAgBtP,EAAEM,QAAO,KAAUiX,YAAcrX,IAAKA,IAAK8J,YAAaA,aAE5E,OAAO9D,MAAKyE,QAAQhF,OAAQ2J,eAGhC,IAAI5D,YAkDA2D,OAAQ,SAAU0H,SAAUpR,OAAQM,SAChC,MAAOmR,QAAO,OAAQL,SAAUpR,OAAQM,UAY5C6B,IAAK,SAAUiP,SAAU9Q,SACrB,GAAIuR,mBAAoBxJ,MAAMR,gBAAiB,QAAS,UAAW,UAAW,QAAS,UACvF,IAAI+J,YAAavX,EAAEM,UAAWkX,kBAAmBvR,QACjD,IAAI/F,KAAMgX,SAASH,SAAUQ,WAC7B,IAAI1D,YAAa7T,EAAEM,QAAO,KAAUiX,YAAcrX,IAAKA,KAEvD,OAAOgG,MAAK4B,OAAQ+L,aAkBxBrQ,KAAM,SAAUyC,SACZ,GAAIU,KAAM3G,EAAEkD,UACZ,IAAIkN,IAAK1N,IACT,IAAI6U,YAAavX,EAAEM,UAAWkN,eAAgBvH,QAC9C,IAAI/F,KAAMgX,SAAS,GAAIK,WACvB,IAAI1D,YAAa7T,EAAEM,QAAO,KAAUiX,YAAcrX,IAAKA,KACvD,IAAIwW,SAAU7C,WAAW6C,OAEzB,OAAKA,UAILxQ,KAAK4B,OAAQ+L,YACR7Q,KAAK,SAAUyU,OACZ,GAAIC,eAAgB1X,EAAE4H,IAAI6P,MAAO,SAAUE,MACvC,MAAOT,UAASS,KAAMJ,aAE1B5Q,KAAIxD,QAAQuU,cAAetH,MAE9B7P,KAAKoG,IAAIsB,QAEPtB,IAAIvD,WAZA8C,KAAK4B,OAAQ+L,aAuD5BvN,QAAS,SAAUyQ,SAAUpR,OAAQM,SACjC,MAAOmR,QAAO,MAAOL,SAAUpR,OAAQM,UAe3C+F,OAAQ,SAAU+K,SAAU9Q,SACxB,MAAOmR,QAAO,SAAUL,YAAc9Q,UAG1C2R,SAAU,SAAUb,SAAU9Q,SAC1B,GAAIsR,YAAavX,EAAEM,UAAWkN,eAAgBvH,QAC9C,OAAOiR,UAASH,SAAUQ,aAGlCvX,GAAEM,OAAOoC,KAAMgJ;;ALzWnB,YAEA,IAAIoC,eAAgBzQ,QAAQ,0BAC5B,IAAI4Q,kBAAmB5Q,QAAQ,sCAE/BgC,QAAOC,QAAU,SAAUwK,QACvB,GAAIC,WAKAkI,SAAU,GAMVC,SAAU,GAMV7D,QAAS,GAMTtR,aAEJ,IAAIyQ,gBAAiBxN,EAAEM,UAAWyJ,SAAUD,OAC5C,IAAI6E,WAAY,GAAIb,eAAcN,gBAAgB1F,IAAI,SAEtD,IAAIyC,kBAAmBvK,EAAEM,QAAO,KAAUkN,eAAezQ,WACrDmD,IAAKyO,UAAUvB,WAAW,mBAE9B,IAAIlH,MAAO,GAAI+H,kBAAiB1D,iBAEhC,IAAImB,YAoBAyG,MAAO,SAAUlM,SACb,GAAID,aAAchG,EAAEM,QAAO,GAAQ0G,QAAShH,EAAEiH,MAAQuG,eAAgBvH,QACtE,KAAKD,YAAYiM,WAAajM,YAAYkM,SAAU,CAChD,GAAIE,OAASC,OAAQ,IAAKC,cAAe,qCAKzC,OAJIrM,SAAQkB,OACRlB,QAAQkB,MAAMiC,KAAK1G,KAAM0P,MAGtBpS,EAAEkD,WAAW+E,OAAOmK,MAAMhP,UAGrC,GAAImP,aACAN,SAAUjM,YAAYiM,SACtBC,SAAUlM,YAAYkM,SAO1B,OALIlM,aAAYqI,UAEZkE,WAAWlE,QAAUrI,YAAYqI,SAG9BnI,KAAK2F,KAAK0G,WAAYvM,cAgBjCwM,OAAQ,SAAUvM,SACd,GAAIU,KAAM3G,EAAEkD,UAEZ,OADAyD,KAAIxD,UACGwD,IAAIvD,WAInBpD,GAAEM,OAAOoC,KAAMgJ;;AmBrHnB,YAyBA,IAAIzM,SAAU,SAAUgH,SACpB,GAAI8D,WAMAR,KAAM,GAeN8W,cAAe,SAAUC,OACrB,MAAOA,QAOXvjB,UAAW,KAEf2F,MAAK6d,eAAiBvgB,EAAEM,QAAO,KAAUyJ,SAAU9D,SAGvD,IAAIua,UAAW,SAAUC,YAAaH,OAElC,GAAI5O,UAAW+O,YAAeA,YAAc,IAAMH,MAASA,OAAOha,QAAQ,QAAS,KAAKA,QAAQ,MAAM,GACtG,OAAOoL,SAIXzS,SAAQ0E,UAAY3D,EAAEM,OAAOrB,QAAQ0E,WAuDjC+c,UAAW,SAAUJ,MAAO7gB,SAAUkhB,QAAS1a,SAE3C,GAAI2a,WAAYjc,OAAO2b,MACvB,IAAIlQ,IAAK1N,IACT,IAAIme,mBACJ,IAAIzD,MAAOhN,GAAGmQ,cAQd,OANAnD,MAAKrgB,UAAU+jB,MAAM,WACjB9gB,EAAEe,KAAK6f,OAAQ,SAAU1e,MAAOoe,OAC5BA,MAAQE,SAASpD,KAAK7T,KAAM6T,KAAKiD,cAAcC,QAC/CO,gBAAgBxf,KAAK+b,KAAKrgB,UAAU2jB,UAAUJ,MAAO7gB,eAGrDohB,gBAAgB,GAAKA,gBAAkBA,gBAAgB,IAoBnEE,QAAS,SAAUT,MAAOja,MACtB,GAAIua,WAAYjc,OAAO2b,MACvB,IAAIlQ,IAAK1N,IACT,IAAIse,cACJ,IAAI5D,MAAOhN,GAAGmQ,cAad,OAVAnD,MAAKrgB,UAAU+jB,MAAM,WACjB9gB,EAAEe,KAAK6f,OAAQ,SAAU1e,MAAOoe,OAC5BA,MAAQE,SAASpD,KAAK7T,KAAM6T,KAAKiD,cAAcC,QACR,MAAnCA,MAAMlf,OAAOkf,MAAMzd,OAAS,KAC5Byd,MAAQA,MAAMha,QAAQ,OAAQ,IAC9B0E,QAAQiW,KAAK,oEAAqEX,MAAO,YAE7FU,WAAW3f,KAAK+b,KAAKrgB,UAAUgkB,QAAQT,MAAOja,WAG9C2a,WAAW,GAAKA,WAAaA,WAAW,IAapDE,YAAa,SAAU9S,OAEnB,MADA1L,MAAK6d,eAAexjB,UAAUmkB,YAAY9S,OACnCA,OAYX+S,GAAI,SAAUC,OACVphB,EAAE0C,MAAMye,GAAGtd,MAAM7D,EAAE0C,MAAOoB,YAU9Bud,IAAK,SAAUD,OACXphB,EAAE0C,MAAM2e,IAAIxd,MAAM7D,EAAE0C,MAAOoB,YAU/Bwd,QAAS,SAAUF,OACfphB,EAAE0C,MAAM4e,QAAQzd,MAAM7D,EAAE0C,MAAOoB,cAKvCzE,OAAOC,QAAUL;;AxBtMjB,YACA,IAAIW,YAAavC,QAAQ,uBAEzBgC,QAAOC,QAAU,SAAUwK,QAEvB,GAAIC,WACAgB,SAAU,OAEd,IAAIyC,gBAAiBxN,EAAEM,UAAWyJ,SAAUD,OAG5C,OAFA0D,gBAAeC,OAAS7N,WAAW4N,eAAeC,SAI9CpH,KAAMmH,eAMNE,OAAQ,SAAUC,OASlB7F,IAAK,SAAU8F,UACX,MAAOJ,gBAAeI,WAQ1BC,IAAK,SAAU7M,IAAKC,OAChBuM,eAAexM,KAAOC;;AIvClC,YAEA,IAAI6M,eAAgBzQ,QAAQ,0BAC5B,IAAIwH,OAAQxH,QAAQ,qBACpB,IAAI4Q,kBAAmB5Q,QAAQ,sCAC/B,IAAI8Q,gBAAiB9Q,QAAQ,2BAE7BgC,QAAOC,QAAU,SAAUwK,QACvB,GAAIC,WAKA8H,KAAM,IAMNxD,QAAS1N,OAMT2N,QAAS3N,OAOTyN,MAAOzN,OAGP5D,aAEJ2F,MAAK+L,eAAiB,GAAIN,eAC1B,IAAIX,gBAAiB9K,KAAK+L,eAAeC,iBAAiB3E,SAAUD,OAEpE,IAAI6E,WAAY,GAAIb,eAAcN,gBAAgB1F,IAAI,SAClD0F,gBAAea,UACfM,UAAU5B,YAAcS,eAAea,SAEvCb,eAAec,UACfK,UAAU1B,YAAcO,eAAec,QAG3C,IAAIqD,QAAS,SAAU3Q,IAAK6Q,MACnBA,OACDA,KAAOrE,eAAeqE,KAE1B,IAAI3R,KAAMyO,UAAUvB,WAAW,QAAUvI,MAAMjC,iBAAiBiP,KAIhE,OAHI7Q,OACAd,KAAM2E,MAAMjC,iBAAiB5B,MAE1Bd,IAGX,IAAI8F,aAAchG,EAAEM,QAAO,KAAUkN,eAAezQ,WAChDmD,IAAKyR,QAELnE,gBAAeY,QACfpI,YAAYiE,SACRgF,cAAiB,UAAYzB,eAAeY,OAGpD,IAAIlI,MAAO,GAAI+H,kBAAiBjI,YAEhC,IAAI0F,YAsCApO,MAAO,SAAU0D,IAAK1D,MAAOmS,eAAgBxJ,SACzC,GAAIN,QAAS3F,EAAEM,QAAO,GAAQwR,EAAGxU,OAASmS,eAC1C,IAAIzJ,aAAchG,EAAEM,QAAO,KAAUkN,eAAgBvH,QAErD,OADAD,aAAY9F,IAAMyR,OAAO3Q,IAAKgF,YAAY6L,MACnC3L,KAAK4B,IAAInC,OAAQK,cAoB5B4J,KAAM,SAAU5O,IAAKC,MAAOgF,SACxB,GAAI2L,MACe,iBAAR5Q,MACP4Q,MAAQ5Q,IACRiF,QAAUhF,QAET2Q,UAAY5Q,KAAOC,KAExB,IAAI+E,aAAchG,EAAEM,QAAO,KAAUkN,eAAgBvH,QAGrD,OAFAD,aAAY9F,IAAMyR,OAAO,GAAI3L,YAAY6L,MAElC3L,KAAK2F,KAAK+F,MAAO5L,cA0B5B+L,OAAQ,SAAU/Q,IAAKC,MAAOgF,SAC1B,GAAID,aAAchG,EAAEM,QAAO,KAAUkN,eAAgBvH,QAGrD,OAFAD,aAAY9F,IAAMyR,OAAO3Q,IAAKgF,YAAY6L,MAEnC3L,KAAK6F,IAAI9K,MAAO+E,cAgB3B5I,KAAM,SAAU4D,IAAKyO,eAAgBxJ,SACjC,GAAID,aAAchG,EAAEM,QAAO,KAAUkN,eAAgBvH,QAErD,OADAD,aAAY9F,IAAMyR,OAAO3Q,IAAKgF,YAAY6L,MACnC3L,KAAK4B,IAAI2H,eAAgBzJ,cAgBpCwL,OAAQ,SAAUQ,KAAM/L,SACpB,GAAID,aAAchG,EAAEM,QAAO,KAAUkN,eAAgBvH,QACrD,IAAIN,OAOJ,OANI3F,GAAEyB,QAAQuQ,MACVrM,QAAWgD,GAAIqJ,OAEfrM,OAAS,GACTK,YAAY9F,IAAMyR,OAAOK,KAAMhM,YAAY6L,OAExC3L,KAAK8F,OAAOrG,OAAQK,cAanChG,GAAEM,OAAOoC,KAAMgJ;;AOrPnB,YAEA,IAAImM,cAAexa,QAAQ,kBAC3B,IAAI4Q,kBAAmB5Q,QAAQ,sCAC/B,IAAIya,cAAeza,QAAQ,gBAE3B,IAAIoV,aAAc,aAElB,IAAIsF,cAAe,SAAUjO,QACzB,GAAIC,WAKAsE,QAAS1N,OAMT2N,QAAS3N,OAMT5D,aAEJ,IAAIyQ,gBAAiBqK,aAAaG,kBAAkBjO,SAAUD,QAAU2I,YAAaA,aACrF,IAAIlI,kBAAmBiD,eAAezQ,gBAC/ByQ,gBAAezQ,SACtB,IAAImJ,MAAO,GAAI+H,kBAAiB1D,iBAAkBiD,eAClD,IAAI9B,YAWAuM,UAAW,SAAUtS,OAAQM,SAGzB,GAAIiS,WAAYJ,gBAAiBtK,eAAgBvH,QACjD,IAAIkS,YAMJ,OALsB,gBAAXxS,QACPuS,UAAUhY,IAAM2X,aAAaO,UAAU3F,YAAc,IAAM9M,OAAQuS,WAEnEC,YAAcxS,OAEXO,KAAK4B,IAAIqQ,YAAaD,YAGrCJ,cAAapV,KAAMgJ,WAGvBrM,QAAOC,QAAUyY;;AF1DjB,YAEA,IAAIjK,eAAgBzQ,QAAQ,0BAC5B,IAAI4Q,kBAAmB5Q,QAAQ,sCAC/B,IAAI8Q,gBAAiB9Q,QAAQ,2BAC7B,IAAI2Q,OAAQ3Q,QAAQ,uBAAuB2Q,KAC3C,IAAIyE,aAAc,cAElBpT,QAAOC,QAAU,SAAUwK,QACvB,GAAIC,WAKAgK,OAAQpT,OAMRmV,QAASnV,OAMT5D,aAEJ2F,MAAK+L,eAAiB,GAAIN,eAC1B,IAAIX,gBAAiB9K,KAAK+L,eAAeC,iBAAiB3E,SAAUD,OACpE,IAAI6E,WAAY,GAAIb,eAAcN,gBAAgB1F,IAAI,SAEtD,IAAIyC,kBAAmBvK,EAAEM,QAAO,KAAUkN,eAAezQ,WACrDmD,IAAKyO,UAAUvB,WAAWqF,cAG1BjF,gBAAeY,QACf7D,iBAAiBN,SACbgF,cAAiB,UAAYzB,eAAeY,OAGpD,IAAIlI,MAAO,GAAI+H,kBAAiB1D,iBAAkBiD,eAElD,IAAIuI,gBAAiB,SAAUpQ,QAC3B,MAAsB,gBAAXA,QACA3F,EAAEM,QAAO,EAAMkN,eAAgB7H,QAEnC6H,eAGX,IAAIwI,sBAAuB,SAAUrQ,OAAQsQ,OAAQhQ,SACjD,GAAID,aAAchG,EAAEM,QAAO,EAAMkN,eAAgBvH,SAC7C/F,IAAKyO,UAAUvB,WAAWqF,aAAe9M,OAAOmQ,QAAU,IAAMnQ,OAAOoO,QAG3E,OAAO7N,MAAK4F,OAAQmK,OAAQA,QAAUjQ,aAG1C,IAAI0F,YAwBAwK,iBAAkB,SAAUvQ,OAAQM,SAChCA,QAAUA,WACV,IAAID,aAAchG,EAAEM,QAAO,EAAMkN,eAAgBvH,QACjD,IAAIkQ,UAA6B,gBAAXxQ,OACtB,IAAIyQ,WAAYL,eAAepQ,OAC/B,KAAKwQ,WAAaC,UAAUrC,OACxB,KAAM,IAAI5E,OAAM,uBAGpB,IAAIkH,UAAWF,UAAapC,OAAQpO,QAAWqI,MAAMoI,UAAW,SAChE,OAAOlQ,MAAK4B,IAAIuO,SAAUrQ,cAsB9BsQ,gBAAiB,SAAU3Q,OAAQM,SAC/BA,QAAUA,WACV,IAAIkQ,UAA6B,gBAAXxQ,OACtB,IAAIyQ,WAAYL,eAAepQ,OAC/B,KAAKwQ,WAAaC,UAAUN,QACxB,KAAM,IAAI3G,OAAM,wBAGpB,IAAI2G,SAAUK,SAAWxQ,OAASyQ,UAAUN,OAC5C,IAAI9P,aAAchG,EAAEM,QAAO,EAAMkN,eAC7BvH,SACE/F,IAAKyO,UAAUvB,WAAWqF,aAAeqD,SAG/C,OAAO5P,MAAK4B,OAAQ9B,cAkBxBuQ,eAAgB,SAAU5Q,OAAQM,SAC9B,MAAO+P,sBAAqBrQ,QAAQ,EAAMM,UAkB9CuQ,iBAAkB,SAAU7Q,OAAQM,SAChC,MAAO+P,sBAAqBrQ,QAAQ,EAAOM,UAInDjG,GAAEM,OAAOoC,KAAMgJ;;ARvInB,YAEA,IAAIoC,eAAgBzQ,QAAQ,0BAC5B,IAAIwH,OAAQxH,QAAQ,qBACpB,IAAI0Q,OAAQ1Q,QAAQ,mBACpB,IAAI2Q,OAAQ3Q,QAAQ,uBAAuB2Q,KAC3C,IAAIC,kBAAmB5Q,QAAQ,sCAC/B,IAAI6Q,kBAAmB7Q,QAAQ,0BAC/B,IAAI8Q,gBAAiB9Q,QAAQ,2BAE7BgC,QAAOC,QAAU,SAAUwK,QACvB,GAAIC,WAMAqE,MAAOzN,OAMP0N,QAAS1N,OAMT2N,QAAS3N,OAMT4N,OAAQ,GAMR5F,GAAI,GAMJ6F,aAAa,EAMbxH,QAAShH,EAAEiH,KAMXE,MAAOnH,EAAEiH,KAMTlK,aAGJ2F,MAAK+L,eAAiB,GAAIN,eAC1B,IAAIX,gBAAiB9K,KAAK+L,eAAeC,iBAAiB3E,SAAUD,OAChE0D,gBAAe7E,KACf6E,eAAee,OAASf,eAAe7E,GAG3C,IAAIgG,WAAY,GAAIb,eAAcN,gBAAgB1F,IAAI,SAClD0F,gBAAea,UACfM,UAAU5B,YAAcS,eAAea,SAEvCb,eAAec,UACfK,UAAU1B,YAAcO,eAAec,SAG3CK,UAAUJ,OAAS,IACnBI,UAAUC,aAAe,WACrB,GAAI1O,KAAMyO,UAAUvB,WAAW,MAC/B,IAAImB,QAAS1J,MAAMpE,eAAe+M,eAAee,OAKjD,OAHIA,UACArO,KAAOqO,OAAS,KAEbrO,KAGXyO,UAAUE,qBAAuB,SAAU5I,SACvC,GAAIsI,QAASf,eAAee,MAE5B,IAAIO,eAAgBP,QAA6B,WAAnBvO,EAAE6K,KAAK0D,OACrC,IAAIf,eAAegB,aAAeM,cAAe,CAG7C,GAAIC,kBACA9E,SACI+E,iBAAiB,GAGzB,OAAOhP,GAAEM,QAAO,EAAMyO,gBAAiB9I,SAG3C,MAAOA,SAGX,IAAID,aAAchG,EAAEM,QAAO,KAAUkN,eAAezQ,WAChDmD,IAAKyO,UAAUC,cAGfpB,gBAAeY,QACfpI,YAAYiE,SACRgF,cAAiB,UAAYzB,eAAeY,OAGpD,IAAIlI,MAAO,GAAI+H,kBAAiBjI,YAChCE,MAAK0F,SAAWmC,MAAMhI,gBAAgBC,YAEtC,IAAIkJ,uBAAwB,SAAUjJ,SAOlC,GANIA,QAAQ0C,KACR6E,eAAee,OAAStI,QAAQ0C,IAEhC1C,QAAQsI,SACRf,eAAee,OAAStI,QAAQsI,SAE/Bf,eAAee,OAChB,KAAM,IAAIY,OAAM,mDAIxB,IAAIC,iBACAT,UAAWA,UAgBXU,OAAQ,SAAU1J,OAAQM,SACtB,GAAIqJ,eAAgBtP,EAAEM,QAAO,KAAUkN,eAAgBvH,SAAW/F,IAAKyO,UAAUvB,WAAW,QAC5F,IAAImC,eAAgB,QAAS,QAAS,QAGlC5J,QAFkB,gBAAXA,SAEI6J,MAAO7J,QAGTqI,MAAMrI,OAAQ4J,aAG3B,IAAIxI,YAAauI,cAActI,OAM/B,OALAsI,eAActI,QAAU,SAAUmE,UAE9B,MADAqC,gBAAee,OAASpD,SAASxC,GAC1B5B,WAAWlD,MAAMnB,KAAMoB,YAG3BoC,KAAK2F,KAAKlG,OAAQ2J,gBA2B7BhS,MAAO,SAAUoD,GAAI+O,eAAgBxJ,SACjCuH,eAAee,OAAS7N,EACxB,IAAIsF,aAAchG,EAAEM,QAAO,KAAUkN,eAAgBvH,QAGrD,OAFAD,aAAc2I,UAAUE,qBAAqB7I,aAEtCE,KAAK0F,SAAS6D,eAAgBzJ,cAazCuI,OAAQ,SAAUA,OAAQkB,eAAgBxJ,SAClCjG,EAAE0B,cAAc8L,eAAee,QAC/BvO,EAAEM,OAAOkN,eAAee,OAAQA,QAEhCf,eAAee,OAASA,MAE5B,IAAIvI,aAAchG,EAAEM,QAAO,KAAUkN,eAAgBvH,QAErD,OADAD,aAAc2I,UAAUE,qBAAqB7I,aACtCE,KAAK0F,SAAS6D,eAAgBzJ,cAiBzC5I,KAAM,SAAUsS,MAAOC,QAAS1J,SACxByJ,QACAlC,eAAee,OAASmB,MAE5B,IAAI1J,aAAchG,EAAEM,QAAO,KAAUkN,eAAgBvH,QAErD,OADAD,aAAc2I,UAAUE,qBAAqB7I,aACtCE,KAAK4B,IAAI6H,QAAS3J,cAoB7B4J,KAAM,SAAUC,WAAY5J,SACxB,GAAID,aAAchG,EAAEM,QAAO,KAAUkN,eAAgBvH,QAErD,OADAiJ,uBAAsBlJ,aACfE,KAAK4F,MAAM+D,WAAY7J,cA8BlC8J,GAAI,SAAUrK,UAAWE,OAAQM,SAE7B,GAAI8J,QACJ,IAAIC,YACA/J,UACA8J,QAAUpK,OACVqK,YAAc/J,SAEVjG,EAAE0B,cAAciE,SAChBoK,QAAU,KACVC,YAAcrK,QAEdoK,QAAUpK,MAGlB,IAAI9D,QAASkM,MAAMhJ,oBAAoBU,UAAWsK,QAClD,IAAI/J,aAAchG,EAAEM,QAAO,KAAUkN,eAAgBwC,YAErDd,uBAAsBlJ,YAEtB,IAAIiK,MAAQpO,OAAO4C,KAAK,GAAG5B,QAA8B,OAAnBhB,OAAO4C,KAAK,IAAkC9D,SAAnBkB,OAAO4C,KAAK,GAAqB5C,OAAO4C,KAAK,KAC9G,OAAOyB,MAAK2F,MAAO/H,UAAWmM,MAAQjQ,EAAEM,QAAO,KAAU0F,aACrD9F,IAAKyO,UAAUC,eAAiB,cAAgB/M,OAAOqD,IAAI,GAAK,QA0BxEgL,OAAQ,SAAUlL,WAAYW,OAAQM,SAClC,GAAIkK,UAAWpC,MAAMhJ,oBAAoBC,WAAYW,OACrD,IAAIT,KAAMiL,SAASjL,GACnB,IAAIT,MAAO0L,SAAS1L,IACpB,IAAI2L,IAAK1N,IAET,IAAI2N,IAAKrQ,EAAEkD,UACX,IAAI8M,aAAchQ,EAAEM,QAAO,KAAUkN,eAAgBvH,QAErD,IAAIqK,YAAa,WACb,GAAIC,IAAKrL,IAAIsL,OACb,IAAIjL,KAAMd,KAAK+L,OAEfJ,IAAGN,GAAGS,GAAIhL,KACNyB,QAAS,WACD9B,IAAIrC,OACJyN,cAEAD,GAAGlN,QAAQU,MAAMnB,KAAMoB,WACvBkM,YAAYhJ,QAAQnD,MAAMnB,KAAMoB,aAGxCqD,MAAO,WACHkJ,GAAGpI,OAAOpE,MAAMnB,KAAMoB,WACtBkM,YAAY7I,MAAMtD,MAAMnB,KAAMoB,cAO1C,OAFAwM,cAEOD,GAAGjN,WAuBdqN,SAAU,SAAUzL,WAAYW,OAAQM,SACpC,GAAIoK,IAAKrQ,EAAEkD,UAEX,IAAIiN,UAAWpC,MAAMhJ,oBAAoBC,WAAYW,OACrD,IAAIT,KAAMiL,SAASjL,GACnB,IAAIT,MAAO0L,SAAS1L,IACpB,IAAIuL,aAAchQ,EAAEM,QAAO,KAAUkN,eAAgBvH,QAErD,IAAIyK,SACJ,KAAK,GAAIC,GAAI,EAAGA,EAAGzL,IAAIrC,OAAQ8N,IAC3BD,MAAMrP,KACFqB,KAAKoN,GAAG5K,IAAIyL,GAAIlM,KAAKkM,IAa7B,OAVA3Q,GAAE+H,KAAKlE,MAAMnB,KAAMgO,OACdtQ,KAAK,WACFiQ,GAAGlN,QAAQU,MAAMnB,KAAMoB,WACvBkM,YAAYhJ,QAAQnD,MAAMnB,KAAKoB,aAElCvD,KAAK,WACF8P,GAAGpI,OAAOpE,MAAMnB,KAAMoB,WACtBkM,YAAY7I,MAAMtD,MAAMnB,KAAKoB,aAG9BuM,GAAGjN,WAIlB,IAAIwN,gBACAC,iBAAkB,WACd,MAAOrD,iBAaXnF,UAAW,SAAUyB,QACjB,GAAIgH,IAAK,GAAI5C,kBAAiBlO,EAAEM,QAAO,KAAUkN,eAAgB1D,QAC7DiH,WAAYrO,OAEhB,OAAOoO,KAIf9Q,GAAEM,OAAOoC,KAAM0M,gBACfpP,EAAEM,OAAOoC,KAAMkO;;A2BpfnB,YAEA,IAAI9C,eAAgBzQ,QAAQ,0BAC5B,IAAI8Q,gBAAiB9Q,QAAQ,2BAC7B,IAAIya,cAAeza,QAAQ,gBAE3B,IAAIwa,eAUAG,kBAAmB,SAAUjO,UACzB,GAAI+a,MAAOphB,MAAMC,UAAUC,MAAMwF,KAAKtF,UAAW,EACjD,IAAI2K,gBAAiB,GAAIN,eACzB,IAAIX,gBAAiBiB,eAAeC,iBAAiB7K,MAAM4K,gBAAiB1E,UAAUpF,OAAOmgB,MAW7F,OATAtX,gBAAezQ,UAAY+a,gBAAiBtK,eAAezQ,WACvDmD,IAAKwC,KAAK0V,UAAU5K,eAAeiF,YAAajF,kBAGhDA,eAAeY,QACfZ,eAAezQ,UAAUkN,SACrBgF,cAAiB,UAAYzB,eAAeY,QAG7CZ,gBAGX4K,UAAW,SAAU3F,YAAajF,gBAC9B,GAAImB,WAAY,GAAIb,eAAcN,gBAAgB1F,IAAI,SACtD,OAAO6G,WAAUvB,WAAWqF,cAIpCpT,QAAOC,QAAUuY;;AtBvCjB,YAiBA,IAAI/J,eAAgBzQ,QAAQ,0BAC5B,IAAI4Q,kBAAmB5Q,QAAQ,sCAC/B,IAAI2Q,OAAQ3Q,QAAQ,uBAAuB2Q,KAC3C,IAAIG,gBAAiB9Q,QAAQ,2BAC7B,IAAIoV,aAAc,aAElBpT,QAAOC,QAAU,SAAUwK,QAEvB,GAAIC,YAIJrH,MAAK+L,eAAiB,GAAIN,eAC1B,IAAIX,gBAAiB9K,KAAK+L,eAAeC,iBAAiB3E,SAAUD,OACpE,IAAI6E,WAAY,GAAIb,eAAcN,gBAAgB1F,IAAI,SAEtD,IAAIyC,kBAAmBvK,EAAEM,QAAO,KAAUkN,eAAezQ,WACrDmD,IAAKyO,UAAUvB,WAAWqF,cAG1BjF,gBAAeY,QACf7D,iBAAiBN,SACbgF,cAAiB,UAAYzB,eAAeY,OAIpD,IAAIlI,MAAO,GAAI+H,kBAAiB1D,iBAChC,IAAImI,mBAAoB,SAAU/M,QAC9B,GAAI3F,EAAE0B,cAAciE,SAAWA,OAAOgN,MAClC,MAAOhN,QAAOgN,KAEd,MAAM,IAAIxD,OAAM,2BAIxB,IAAIzD,YAgBAkH,OAAQ,SAAUjN,OAAQM,SACtB,GAAI0M,OAAQD,kBAAkB/M,OAE9B,IAAIkN,eAAgB7S,EAAEM,QAAO,KACzBkN,eACAvH,SACE/F,IAAKyO,UAAUvB,WAAWqF,aAAeE,OAK/C,OAFAhN,QAAS3F,EAAEM,QAAO,GAAQwS,OAAQ,UAAY9E,MAAMrI,QAAS,aAAc,aAEpEO,KAAK2F,KAAKlG,OAAQkN,gBA0B7BE,MAAO,SAAUpN,OAAQM,SACrB,GAAI0M,OAAQD,kBAAkB/M,OAE9B,IAAIkN,eAAgB7S,EAAEM,QAAO,KACzBkN,eACAvH,SACE/F,IAAKyO,UAAUvB,WAAWqF,aAAeE,OAK/C,OAFAhN,QAAS3F,EAAEM,QAAO,GAAQwS,OAAQ,SAAW9E,MAAMrI,QAAS,aAAc,aAEnEO,KAAK2F,KAAKlG,OAAQkN,gBAIjC7S,GAAEM,OAAOoC,KAAMgJ;;APxHnB,YAEA,IAAIS,YAAa9O,QAAQ,sBAGzB,IAAI0M,WACApK,KAAMyM,OAAOC,SAAS1M,KACtB2M,SAAUF,OAAOC,SAASC,SAG9B,IAAIC,kBAAmB,SAAUzC,QAE7B,QAAShK,eACL,GAAIH,MAAOsG,QAAQtG,IACnB,IAAI6M,MAAOvG,QAAQqG,QAEnB,QAAS3M,MAAkC,IAA1B6M,KAAKnK,QAAQ,SALlC,GAAI4D,SAAUjG,EAAEM,UAAWyJ,SAAUD,OAQrC,IAAI2C,cAAe,OACnB,IAAIC,mBACAC,YAAa,gBACbC,eAAgB,6BAGpB,IAAIC,gBACArM,SAAUiM,aAEVtN,IAAK,GAELQ,KAAO,WACH,GAAIA,MAAOsG,QAAQtG,IAInB,OAHIG,iBACAH,KAAO,aAEH+M,iBAAiB/M,MAAS+M,iBAAiB/M,MAAQ,OAASA,QAGxEmN,QAAU,WACN,GAAIN,MAAOvG,QAAQqG,SAAStK,MAAM,IAElC,OAAOwK,OAAQA,KAAK,IAAM,MAG9BO,YAAc,WACV,GAAIC,OAAQ,EACZ,IAAIR,MAAOvG,QAAQqG,SAAStK,MAAM,IAIlC,OAHIwK,OAAoB,QAAZA,KAAK,KACbQ,MAAQR,KAAK,IAEVQ,SAGXC,YAAc,WACV,GAAIC,KAAM,EACV,IAAIV,MAAOvG,QAAQqG,SAAStK,MAAM,IAIlC,OAHIwK,OAAoB,QAAZA,KAAK,KACbU,IAAMV,KAAK,IAERU,OAGXC,YAAc,WACV,GAAIjO,SAAUiN,WAAWjN,QAAUiN,WAAWjN,QAAU,IAAM,EAC9D,OAAOA,YAGXY,YAAaA,YAEbsN,WAAY,SAAUjO,KAClB,GAAIkO,eAAgB,MAAO,OAAQ,OAEnC,IAAIC,SAAU5K,KAAKlC,SAAW,MAAQkC,KAAK/C,KAAO,IAAM+C,KAAKyK,YAAchO,IAAM,GAKjF,OAHIa,GAAEkB,QAAQ/B,IAAKkO,iBAAkB,IACjCC,SAAW5K,KAAKqK,YAAc,IAAMrK,KAAKuK,YAAe,KAErDK,SAKf,IAAIC,UACA/M,SAAU+L,iBAAiB/L,SAC3Bb,KAAM4M,iBAAiB5M,KAI3B,OADAK,GAAEM,OAAOuM,cAAeU,QAASzD,QAC1B+C,cAGXxN,QAAOC,QAAUiN;;AS3FjB,YAoBA,IAAIuB,eAAgBzQ,QAAQ,0BAC5B,IAAI4Q,kBAAmB5Q,QAAQ,sCAC/B,IAAI8Q,gBAAiB9Q,QAAQ,2BAC7B,IAAIwH,OAAQxH,QAAQ,qBAEpBgC,QAAOC,QAAU,SAAUwK,QACvB,GAAIC,WAMAsE,QAAS1N,OAMTyN,MAAOzN,OAMP5D,aAGJ2F,MAAK+L,eAAiB,GAAIN,eAC1B,IAAIX,gBAAiB9K,KAAK+L,eAAeC,iBAAiB3E,SAAUD,OACpE,IAAI6E,WAAY,GAAIb,eAAcN,gBAAgB1F,IAAI,SACtD,IAAIyC,kBAAmBvK,EAAEM,QAAO,KAAUkN,eAAezQ,WACrDmD,IAAKyO,UAAUvB,WAAW,SAG1BI,gBAAeY,QACf7D,iBAAiBN,SACbgF,cAAiB,UAAYzB,eAAeY,OAIpD,IAAIlI,MAAO,GAAI+H,kBAAiB1D,iBAEhC,IAAImB,YAoBA5D,IAAK,SAAUyG,OAAQtI,SACnBA,QAAUA,YACVsI,OAASA,UAET,IAAIsF,YAAa7T,EAAEM,QAAO,KACtBkN,eACAvH,QAGJ,IAAIwP,WAAY,SAAUlH,QACtB,GAAIlO,OAOJ,OAJIkO,QAAO0D,WACP5R,IAAIyR,EAAIvD,OAAO0D,UAGZ5R,IAGX,IAAIqV,aAAc,SAAU/M,IACxB,MAAKA,KAILA,GAAK3I,EAAEyB,QAAQkH,IAAMA,IAAMA,IACpB,MAAQA,GAAGpH,KAAK,SAJZ,GAOf,IAAIoU,aACA,WAAa9B,WAAWxF,QACxBqH,YAAYnH,OAAO5F,IACnB9D,MAAMrD,cAAciU,UAAUlH,UAChChN,KAAK,IAIP,IAAIqU,WAAY,EAChB,OAAIrH,QAAO5F,IAAM3I,EAAEyB,QAAQ8M,OAAO5F,KAAO4F,OAAO5F,GAAG9F,QAAU+S,WACzD/B,WAAW3T,IAAMyO,UAAUvB,WAAW,QAAU,eACzClH,KAAK2F,MAAOlD,GAAI4F,OAAO5F,IAAMkL,aAE7B3N,KAAK4B,IAAI6N,WAAY9B,aAoBpCgC,QAAS,SAAU9B,OAAQ9N,SACvB,MAAOyF,WAAU5D,KAAMa,GAAIoL,QAAU9N,UAI7CjG,GAAEM,OAAOoC,KAAMgJ;;AL/HlB,YAEA,IAAIuC,kBAAmB5Q,QAAQ,sCAC/B,IAAI0Q,OAAQ1Q,QAAQ,mBAErBgC,QAAOC,QAAU,SAAUwK,QACvB,GAAIC,WAKAgH,WAAY,KAEhB,IAAIvD,gBAAiBxN,EAAEM,UAAWyJ,SAAUD,OAE5C,IAAI6H,QAAS,WACT,MAAOnE,gBAAeuD,WAAWpC,UAAUC,eAAiB,aAGhE,IAAIC,sBAAuB,SAAU5I,SACjC,MAAOuH,gBAAeuD,WAAWpC,UAAUE,qBAAqB5I,SAGpE,IAAID,cACA9F,IAAKyR,OAELnE,gBAAeY,QACfpI,YAAYiE,SACRgF,cAAiB,UAAYzB,eAAeY,OAGpD,IAAIlI,MAAO,GAAI+H,kBAAiBjI,YAChCE,MAAK0F,SAAWmC,MAAMhI,gBAAgBC,YAEtC,IAAI0F,YAiBAtO,KAAM,SAAUoK,SAAUiI,eAAgBxJ,SACtC,GAAID,aAAchG,EAAEM,QAAO,KAAUkN,eAAgBvH,QAErD,OADAD,aAAc6I,qBAAqB7I,aAC5BE,KAAK4B,IAAI2H,eAAgBzP,EAAEM,UAAW0F,aACzC9F,IAAKyR,SAAWnK,SAAW,QAsBnClK,MAAO,SAAUA,MAAOmS,eAAgBxJ,SAEpC,GAAID,aAAchG,EAAEM,QAAO,KAAUkN,eAAgBvH,QAOrD,OANAD,aAAc6I,qBAAqB7I,aAE/BhG,EAAEyB,QAAQnE,SACVA,OAAUmJ,QAASnJ,QAEvB0C,EAAEM,OAAOhD,MAAOmS,gBACTvJ,KAAK0F,SAAStO,MAAO0I,cAgBhC4J,KAAM,SAAUpI,SAAUzE,IAAKkD,SAC3B,GAAI2L,MACoB,iBAAbpK,WACPoK,MAAQpK,SACRvB,QAAUlD,MAET6O,UAAYpK,UAAYzE,GAE7B,IAAIiD,aAAchG,EAAEM,QAAO,KAAUkN,eAAgBvH,QAErD,OAAOC,MAAK4F,MAAM1C,KAAK1G,KAAMkP,MAAO5L,cA2B5ChG,GAAEM,OAAOoC,KAAMgJ;;AI5InB,YAEA,IAAIoC,eAAgBzQ,QAAQ,0BAE5B,IAAI4Q,kBAAmB5Q,QAAQ,sCAC/B,IAAI8Q,gBAAiB9Q,QAAQ,2BAC7B,IAAI2Q,OAAQ3Q,QAAQ,uBAAuB2Q,KAE3C,IAAIgF,SAAU,cACd,IAAIC,oBAAqBD,QAAU,QACnC,IAAIP,aAAcO,QAAU,OAC5B,IAAIE,iBAAkBF,QAAU,SAEhC3T,QAAOC,QAAU,SAAUwK,QACvB,GAAIC,WAMDqE,MAAOzN,OAMN2N,QAAS3N,OAMT0N,QAAS1N,OAMTwS,MAAOxS,OAMP6O,MAAO7O,OAMP4N,OAAQ,GAMR5F,GAAI,GAMJ5L,aAMAiK,QAAShH,EAAEiH,KAMXE,MAAOnH,EAAEiH,KAGbvE,MAAK+L,eAAiB,GAAIN,eAC1B,IAAIX,gBAAiB9K,KAAK+L,eAAeC,iBAAiB3E,SAAUD,OAChE0D,gBAAe7E,KACf6E,eAAee,OAASf,eAAe7E,GAG3C,IAAIgG,WAAY,GAAIb,eAAcN,gBAAgB1F,IAAI,SAEjD0F,gBAAea,UAChBb,eAAea,QAAUM,UAAU5B,aAGlCS,eAAec,UAChBd,eAAec,QAAUK,UAAU1B,YAGvC,IAAI1C,kBAAmBvK,EAAEM,QAAO,KAAUkN,eAAezQ,WACrDmD,IAAKyO,UAAUvB,WAAWqF,cAG1BjF,gBAAeY,QACf7D,iBAAiBN,SACbgF,cAAiB,UAAYzB,eAAeY,OAIpD,IAAIlI,MAAO,GAAI+H,kBAAiB1D,iBAEhC,IAAI6I,yBAA0B,SAAUnN,SAOpC,GANIA,QAAQ0C,KACR6E,eAAee,OAAStI,QAAQ0C,IAEhC1C,QAAQsI,SACRf,eAAee,OAAStI,QAAQsI,SAE/Bf,eAAee,OAChB,KAAM,IAAIY,OAAM,gKAIxB,IAAIkE,2BAA4B,SAAUpN,SACtC,IAAKA,QAAQuJ,MACT,KAAM,IAAIL,OAAM,6CAIxB,IAAIzD,YA0BA2D,OAAQ,SAAU1J,OAAQM,SACtB,GAAIqJ,eAAgBtP,EAAEM,QAAO,KAAUkN,eAAgBvH,SAAW/F,IAAKyO,UAAUvB,WAAWqF,cAC5F,IAAIa,iBAAkB,QAAS,QAAS,QAAS,gBAAiB,WAAY,QAAS,OACvF,IAAIC,aAAcvF,MAAMR,gBAAiB,UAAW,UAAW,SAE/D7H,QAASqI,MAAMrI,OAAQ2N,gBAGvB3N,OAAS3F,EAAEM,UAAWiT,YAAa5N,OAEnC,IAAIoB,YAAauI,cAActI,OAM/B,OALAsI,eAActI,QAAU,SAAUmE,UAE9B,MADAqC,gBAAee,OAASpD,SAASxC,GAC1B5B,WAAWlD,MAAMnB,KAAMoB,YAG3BoC,KAAK2F,KAAKlG,OAAQ2J,gBA4B7BkE,OAAQ,SAAU7N,OAAQM,SACtB,GAAIwN,YAAa,QAAS,gBAAiB,WAC3CxN,SAAUA,YACVmN,wBAAwBnN,QAExB,IAAIyN,eAAgB1T,EAAEM,QAAO,KACzBkN,eACAvH,SACE/F,IAAKyO,UAAUvB,WAAWqF,aAAejF,eAAee,QAK9D,OAFA5I,QAASqI,MAAMrI,WAAc8N,WAEtBvN,KAAK4F,MAAMnG,OAAQ+N,gBAuB9B1H,OAAQ,SAAU/F,SACdA,QAAWA,SAA+B,gBAAZA,UAA2BsI,OAAQtI,YACjEmN,wBAAwBnN,QAExB,IAAI0N,eAAgB3T,EAAEM,QAAO,KACzBkN,eACAvH,SACE/F,IAAKyO,UAAUvB,WAAWqF,aAAejF,eAAee,QAG9D,OAAOrI,MAAK8F,OAAO,KAAM2H,gBAa7BC,aAAc,SAAU9J,QAGpB,MAFA9J,GAAEM,OAAOkN,eAAgB1D,QAElBpH,MAyBXc,KAAM,SAAUyC,SACZA,QAAUA,WAEV,IAAI4N,YAAa7T,EAAEM,QAAO,KACtBkN,eACAvH,SACE/F,IAAKyO,UAAUvB,WAAWqF,cAGhC,IAAI9C,SAAU3B,MAAM6F,YAAa,UAAW,UAAW,SAEvD,OAAO3N,MAAK4B,IAAI6H,QAASkE,aAqB7BC,iBAAkB,SAAUC,OAAQ9N,SAChCA,QAAUA,WAEV,IAAI4N,YAAa7T,EAAEM,QAAO,KACtBkN,eACAvH,SACE/F,IAAKyO,UAAUvB,WAAWqF,cAGhC,IAAI9C,SAAU3P,EAAEM,OACZ0N,MAAM6F,YAAa,UAAW,UAAW,WACvCE,OAAQA,QAGd,OAAO7N,MAAK4B,IAAI6H,QAASkE,aAU7BzW,KAAM,SAAU4W,QAAS/N,SAIrB,GAHI+N,UACAxG,eAAee,OAASyF,UAEvBxG,eAAee,OAChB,KAAM,IAAIY,OAAM,mCAEpB,IAAInJ,aAAchG,EAAEM,QAAO,KAAUkN,eAAgBvH,SAAY/F,IAAKyO,UAAUvB,WAAWqF,aAAejF,eAAee,OAAS,KAClI,OAAOrI,MAAK4B,IAAI,GAAI9B,cAsCxBiO,SAAU,SAAUC,MAAOF,QAAS/N,SAEhC,IAAKiO,MACD,KAAM,IAAI/E,OAAM,qDAIpB+E,OAAQlU,EAAE4H,OAAOjD,OAAOuP,OAAQ,SAAUC,GACtC,GAAIhM,UAAWnI,EAAE0B,cAAcyS,EAE/B,IAAiB,gBAANA,KAAmBhM,SAC1B,KAAM,IAAIgH,OAAM,8DAAgEgF,EAGpF,OAAOhM,UAAWgM,GAAMJ,OAAQI,KAIhCnU,EAAE0B,cAAcsS,WAAa/N,UAC7BA,QAAU+N,QACVA,QAAU,MAGd/N,QAAUA,YAGa,gBAAZ+N,WACP/N,QAAQsI,OAASyF,SAGrBZ,wBAAwBnN,QAExB,IAAIyN,eAAgB1T,EAAEM,QAAO,KACzBkN,eACAvH,SACE/F,IAAKyO,UAAUvB,WAAWqF,aAAejF,eAAee,OAAS,UAGvE,OAAOrI,MAAK2F,KAAKqI,MAAOR,gBAuB5BU,WAAY,SAAUC,KAAMpO,SAGxB,GAFAA,QAAUA,aAELoO,OAASA,KAAKN,OACf,KAAM,IAAI5E,OAAM,qDAGpBiE,yBAAwBnN,QAExB,IAAIqO,cAAetU,EAAEM,QAAO,KACxBkN,eACAvH,SACE/F,IAAKyO,UAAUvB,WAAWqF,aAAejF,eAAee,OAAS,UAAY8F,KAAKN,QAGxF,OAAO7N,MAAK4F,MAAMkC,MAAMqG,KAAM,QAASC,eAuB3CC,WAAY,SAAUF,KAAMpO,SAOxB,GANAA,QAAUA,YAEU,gBAAToO,QACPA,MAASN,OAAQM,QAGhBA,KAAKN,OACN,KAAM,IAAI5E,OAAM,qDAGpBiE,yBAAwBnN,QAExB,IAAI4N,YAAa7T,EAAEM,QAAO,KACtBkN,eACAvH,SACE/F,IAAKyO,UAAUvB,WAAWqF,aAAejF,eAAee,OAAS,UAAY8F,KAAKN,QAGxF,OAAO7N,MAAK8F,OAAO,KAAM6H,aAuB7BW,gBAAiB,SAAUvO,SACvBA,QAAUA,YAEVmN,wBAAwBnN,QAExB,IAAI4N,YAAa7T,EAAEM,QAAO,KACtBkN,eACAvH,SACE/F,IAAKyO,UAAUvB,WAAWqF,aAAejF,eAAee,OAAS,QAIvE,OADA8E,2BAA0BQ,YACnB3N,KAAK2F,KAAKmC,MAAM6F,WAAY,SAAUA,aAqBjDY,uBAAwB,SAAUV,OAAQW,WACtC,GAAI/N,KAAM3G,EAAEkD,UACZ,IAAIkN,IAAK1N,IAeT,OAdAA,MAAKoR,iBAAiBC,QAAUZ,MAAOuB,YAClC1R,KAAK,SAAU2R,QAEZA,OAAOC,KAAK,SAAUC,EAAGC,GAAK,MAAO,IAAIC,MAAKD,EAAEE,cAAgB,GAAID,MAAKF,EAAEG,eAC3E,IAAIC,cAAeN,OAAO,EAEtBM,gBACAzH,eAAee,OAAU0G,aAAatM,IAG1ChC,IAAIxD,QAAQ8R,aAAc7E,MAE7B7P,KAAKoG,IAAIsB,QAEPtB,IAAIvD,WAqBf8R,UAAW,SAAUlB,QAAS/N,SAC1BA,QAAUA,YAEN+N,UACA/N,QAAQsI,OAASyF,SAGrBZ,wBAAwBnN,QAExB,IAAI0N,eAAgB3T,EAAEM,QAAO,KACzBkN,eACAvH,SACE/F,IAAKyO,UAAUvB,WAAWqF,aAAejF,eAAee,OAAS,QAGvE,OAAOrI,MAAK8F,OAAO,KAAM2H,gBAuB7BwB,eAAgB,SAAUnB,QAAS/N,SAC/B,GAAImP,mBAAoBpV,EAAEM,QAAO,KAC7B2F,SACEsI,OAAQyF,SAAWxG,eAAee,QAExC,IAAIjK,OAAQ5B,IAIZ,OAFA2Q,2BAA0B+B,mBAEnB1S,KAAKwS,UAAUlB,QAAS/N,SAC1BjD,KAAK,WACF,MAAOsB,OAAMkQ,gBAAgBY,sBAoBzCC,WAAY,SAAUpP,SAClBA,QAAUA,WAEV,IAAIqP,KAAMtV,EAAEM,QAAO,KACfkN,eACAvH,SACE/F,IAAKyO,UAAUvB,WAAW6F,qBAGhC,IAAItN,SACA0I,QAASiH,IAAIjH,QACbC,QAASgH,IAAIhH,QACb6E,MAAOmC,IAAInC,MAOf,OAJImC,KAAIC,WACJ5P,OAAO4P,SAAWD,IAAIC,UAGnBrP,KAAK2F,KAAKlG,OAAQ2P,MA0B7BE,mBAAoB,SAAUvP,SAC1BA,QAAUA,WAEV,IAAIqP,KAAMtV,EAAEM,QAAO,KACfkN,eACAvH,SACE/F,IAAKyO,UAAUvB,WAAW8F,kBAKhC,OAFAoC,KAAIpV,MAAQoV,IAAIjH,QAASiH,IAAIhH,SAAS/M,KAAK,KAEpC2E,KAAK4B,IAAI,KAAMwN,MAK9BtV,GAAEM,OAAOoC,KAAMgJ;;AK9tBnB,YAGA,IAAIjN,QAAS,WACTiE,KAAKoF,IAAM,WACP,MAAOuQ,UAASC,QAGpB5V,KAAKmL,IAAM,SAAU0K,WACjBF,SAASC,OAASC,WAI1BlZ,QAAOC,QAAU,SAAUwK,QACvB,GAAInK,MAAOyM,OAAOC,SAASmM,QAC3B,IAAIC,WAAY9Y,KAAKqC,MAAM,KAAKa,OAAS,CACzC,IAAI6V,QAASD,UAAY,IAAM9Y,KAAO,IAEtC,IAAIoK,WAKA8H,KAAM,IAEN6G,OAAQA,OACRJ,OAAQ,GAAI7Z,QAEhBiE,MAAK8K,eAAiBxN,EAAEM,UAAWyJ,SAAUD,OAE7C,IAAI4B,YA8BAmC,IAAK,SAAU7M,IAAKC,MAAOgF,SACvB,GAAI0S,YAAa3Y,EAAEM,QAAO,KAAUoC,KAAK8K,eAAgBvH,QAEzD,IAAIyS,QAASC,WAAWD,MACxB,IAAIlM,MAAOmM,WAAW9G,IACtB,IAAIyG,QAASK,WAAWL,MAQxB,OANAA,QAAOzK,IAAItG,mBAAmBvG,KAAO,IACjBuG,mBAAmBtG,QAClByX,OAAS,YAAcA,OAAS,KAChClM,KAAO,UAAYA,KAAO,KAGxCvL,OAWX6G,IAAK,SAAU9G,KACX,GAAIsX,QAAS5V,KAAK8K,eAAe8K,MACjC,IAAIM,WAAY,GAAIC,QAAO,cAAgBtR,mBAAmBvG,KAAKsF,QAAQ,cAAe,QAAU,wBACpG,IAAIjG,KAAMuY,UAAUE,KAAKR,OAAOxQ,MAChC,IAAI/E,KAAM1C,IAAM0Y,mBAAmB1Y,IAAI,IAAM,IAC7C,OAAO0C,MAWXyO,OAAQ,SAAUxQ,IAAKiF,SACnB,GAAI+S,YAAahZ,EAAEM,QAAO,KAAUoC,KAAK8K,eAAgBvH,QAEzD,IAAIyS,QAASM,WAAWN,MACxB,IAAIlM,MAAOwM,WAAWnH,IACtB,IAAIyG,QAASU,WAAWV,MAOxB,OALAA,QAAOzK,IAAItG,mBAAmBvG,KACd,4CACC0X,OAAS,YAAcA,OAAS,KAChClM,KAAO,UAAYA,KAAO,KAEpCxL,KAOXiY,QAAS,WACL,GAAIX,QAAS5V,KAAK8K,eAAe8K,MACjC,IAAIY,OAAQZ,OAAOxQ,MAAMxB,QAAQ,0DAA2D,IAAItE,MAAM,sBACtG,KAAK,GAAImX,MAAO,EAAGA,KAAOD,MAAMrW,OAAQsW,OAAQ,CAC5C,GAAIC,WAAYL,mBAAmBG,MAAMC,MACzCzW,MAAK8O,OAAO4H,WAEhB,MAAOF,QAIflZ,GAAEM,OAAOoC,KAAMgJ;;Ae7InB,YAEA,IAAI6T,UAAWliB,QAAQ,wBACvB,IAAI2mB,gBAAiB3mB,QAAQ,kBAC7B,IAAI4mB,aAAc5mB,QAAQ,uBAE1B,IAAI6mB,iBAAkB3E,SAAS2E,eAC/B,IAAIna,WAKA/M,OAASmnB,aAAa,GAG1B,IAAIhW,gBAAiB,SAAUiW,gBAE3B,QAASC,gBAAeC,WACpBA,UAAYA,aACZ,IAAIC,YAAaN,YAAYpQ,YAC7B,IAAI2Q,cAAexkB,EAAEM,QAAO,KAAUyJ,SAAUwa,WAAYH,eAAgBE,UAC5E,OAAOE,cAGX,QAASpF,UAASkF,WACd,GAAIG,aAAcJ,eAAeC,UACjC,IAAII,WAAYD,YAAYznB,SAI5B,OAHuB2D,UAAnB+jB,UAAU7S,MAAsB4S,YAAYpW,SAAWoW,YAAYnW,UAAYmW,YAAYjK,UAC3FkK,UAAU7S,KAAO,QAAU4S,YAAYpW,QAAU,IAAMoW,YAAYnW,SAEhE,GAAI0V,gBAAeU,WAd9BN,eAAiBA,kBAiBjB,IAAI1Y,YACA+Q,YAAa,SAAUX,SAAU7V,SAC7B,GAAI0e,YAAahjB,KAAKC,UAAUka,SAChCsD,UAASnZ,SAAS4H,IAAIqW,gBAAiBS,aAE3C3I,WAAY,SAAU/V,SAGlB,GAAIjJ,OAAQoiB,SAASnZ,QACrB,IAAIiS,WAAYlb,MAAMwQ,cACtB,IAAImX,YAAa3nB,MAAM8K,IAAIoc,kBAAoB,IAC/C,IAAIvG,SAAUhc,KAAK6Z,MAAMmJ,WAKzB,IAAItW,SAAU6J,UAAU7J,OACxB,IAAIC,SAAU4J,UAAU5J,OACxB,IAAID,SAAWsP,QAAQtP,UAAYA,QAE/B,QAEJ,IAAIsP,QAAQ1B,QAAU5N,SAAWC,QAAS,CACtC,GAAI6E,OAAQwK,QAAQ1B,OAAO3N,WAAcwH,QAAS,GAAIpB,UAAW,GAAIsI,OAAO,EAC5Ehd,GAAEM,OAAOqd,SAAWrP,QAASA,SAAW6E,OAE5C,MAAOwK,UAEXF,cAAe,SAAUxX,SACrB,GAAIjJ,OAAQoiB,SAASnZ,QAKrB,OAJAiU,QAAOlI,KAAKuN,UAAUjC,QAAQ,SAAUlE,WACpC,GAAIwL,YAAarF,SAASnG,UAC1Bpc,OAAMwU,OAAOoT,eAEV,GAEXxF,SAAU,SAAUnZ,SAChB,MAAOmZ,UAASnZ,UAGpByI,iBAAkB,WACd,GAAIjK,MAAOf,MAAMC,UAAUC,MAAMwF,KAAKtF,UACtC,IAAIwgB,WAAYtkB,EAAEM,OAAOuD,MAAM7D,IAAI,MAAU2E,OAAOF,MACpD,IAAIggB,aAAcJ,eAAeC,UACjC,IAAI3G,SAAUjb,KAAKsZ,WAAWsI,UAE9B,IAAIO,kBAQAzW,MAAOuP,QAAQpB,WAKfpJ,MAAOwK,QAAQjJ,UAKfoB,QAAS6H,QAAQ7H,QACjB/B,OAAQ4J,QAAQ5J,OAEpB,OAAO/T,GAAEM,QAAO,EAAMukB,gBAAiBJ,cAG/CzkB,GAAEM,OAAOoC,KAAMgJ,WAGnBrM,QAAOC,QAAU6O;;AdtGjB,YAGA,IAAInR,OAAQK,QAAQ,iBAEpBgC,QAAOC,QAAUtC;;AfTjB,YAEA,IAAI6M,QAASxM,QAAQ,qBAErBgC,QAAOC,QAAU,SAAUwK,QAEvB,GAAIC,WACA7J,IAAK,GAEL8J,YAAa,mBACbC,WACAC,YACIC,IAAKnK,EAAEiH,MAOXmD,gBAAiBP,OAAOrI,cAIxB6I,WACIC,iBAAiB,GAIzB,IAAIC,kBAAmBvK,EAAEM,UAAWyJ,SAAUD,OAE9C,IAAIjI,QAAS,SAAU2I,GACnB,MAAQxK,GAAEyK,WAAWD,GAAMA,IAAMA,EAGrC,IAAIE,SAAU,SAAUC,OAAQhF,OAAQiF,gBACpCjF,OAAS9D,OAAO8D,QAChBA,OAAU3F,EAAE0B,cAAciE,SAAW3F,EAAEyB,QAAQkE,QAAWhE,KAAKC,UAAU+D,QAAUA,MAEnF,IAAIM,SAAUjG,EAAEM,QAAO,KAAUiK,iBAAkBK,gBAC/CC,KAAMF,OACNtE,KAAMV,QAEV,IAAImF,0BAA2B,OAAQ,MAOvC,IANA9K,EAAEe,KAAKkF,QAAS,SAAUjF,IAAKC,OACvBjB,EAAEyK,WAAWxJ,QAAUjB,EAAEkB,QAAQF,IAAK8J,4BAA6B,IACnE7E,QAAQjF,KAAOC,WAInBgF,QAAQ8E,UAAiC,UAArB9E,QAAQ8E,SAAsB,CAClDC,QAAQC,IAAIhF,QAAQ/F,IACpB,IAAIgL,cAAejF,QAAQe,SAAWhH,EAAEiH,IACxChB,SAAQe,QAAU,SAAUmE,SAAUC,WAAYC,SAC9CL,QAAQC,IAAIE,UACZD,aAAarH,MAAMnB,KAAMoB,YAIjC,GAAIwH,YAAarF,QAAQqF,UAQzB,OAPArF,SAAQqF,WAAa,SAAUC,IAAKC,UAChCD,IAAIE,YAAcb,oBAAsB1K,IACpCoL,YACAA,WAAWzH,MAAMnB,KAAMoB,YAIxB9D,EAAEC,KAAKgG,SAGlB,IAAIyF,YACA5D,IAAI,SAAUnC,OAAQgG,aAClB,GAAI1F,SAAUjG,EAAEM,UAAWiK,iBAAkBoB,YAE7C,OADAhG,QAASM,QAAQmE,gBAAgBvI,OAAO8D,SACjC+E,QAAQtB,KAAK1G,KAAM,MAAOiD,OAAQM,UAE7C2F,SAAU,aAGVC,KAAM,WACF,MAAOnB,SAAQ7G,MAAMnB,MAAO,QAAQiC,UAAUf,MAAMwF,KAAKtF,cAE7DgI,MAAO,WACH,MAAOpB,SAAQ7G,MAAMnB,MAAO,SAASiC,UAAUf,MAAMwF,KAAKtF,cAE9DiI,IAAK,WACD,MAAOrB,SAAQ7G,MAAMnB,MAAO,OAAOiC,UAAUf,MAAMwF,KAAKtF,cAE5DkI,OAAQ,SAAUrG,OAAQgG,aAEtB,GAAI1F,SAAUjG,EAAEM,UAAWiK,iBAAkBoB,YAE7C,IADAhG,OAASM,QAAQmE,gBAAgBvI,OAAO8D,SACpC3F,EAAEmB,KAAKwE,QAAS,CAChB,GAAIsG,WAAapK,OAAOoE,QAAQ/F,KAAKmC,QAAQ,QAAS,EAAM,IAAM,GAClE4D,SAAQ/F,IAAM2B,OAAOoE,QAAQ/F,KAAO+L,UAAYtG,OAEpD,MAAO+E,SAAQtB,KAAK1G,KAAM,SAAU,KAAMuD,UAE9CiG,KAAM,WACF,MAAOxB,SAAQ7G,MAAMnB,MAAO,QAAQiC,UAAUf,MAAMwF,KAAKtF,cAE7DmC,QAAS,WACL,MAAOyE,SAAQ7G,MAAMnB,MAAO,WAAWiC,UAAUf,MAAMwF,KAAKtF,cAIpE,OAAO9D,GAAEM,OAAOoC,KAAMgJ;;ADzG1B,YAIA,IAAI3O,WAAYM,QAAQ,wBACxBgC,QAAOC,QAAUvC;;ADFjB,YAEA,SAAS+L,SAAQC,EAAGC,GAChB,GAAIpM,GAAI,YACRA,GAAE+G,UAAYqF,EAAErF,UAChBoF,EAAEpF,UAAY,GAAI/G,GAClBmM,EAAEE,QAAUD,EAAErF,UACdoF,EAAEpF,UAAUuF,YAAcH,EAM9B,GAAIzI,QAAS,SAAU6I,MACnB,GAAIlF,KAAMP,MAAMC,UAAUC,MAAMwF,KAAKtF,UAAW,EAChD,IAAIuF,QACJ,KAAK,GAAIC,GAAI,EAAGA,EAAErF,IAAIpB,OAAQyG,IAC1B,GAAMD,QAAUpF,IAAIqF,GAMpB,IAAK,GAAItI,OAAOqI,SACZF,KAAKnI,KAAOqI,QAAQrI,IAI5B,OAAOmI,MAGX9J,QAAOC,QAAU,SAAUiK,KAAMC,MAAOC,aACpC,GAAIC,QAASH,IACb,IAAII,MAgBJ,OAdAA,OAAQH,OAASA,MAAMI,eAAe,eAAiBJ,MAAMN,YAAc,WAAc,MAAOQ,QAAO7F,MAAMnB,KAAMoB,YAGnHxD,OAAOqJ,MAAOD,OAAQD,aAGtBX,QAAQa,MAAOD,QAGXF,OACAlJ,OAAOqJ,MAAMhG,UAAW6F,OAIrBG;;AFpDX,YAGA,SAAS7G,IAAGC,KACR,GAAIA,KAAOA,IAAIC,KACX,MAAOD,IAEX,IAAIE,GAAIjD,EAAEkD,UAGV,OAFAD,GAAEE,QAAQJ,KAEHE,EAAEG,UAGb,QAASC,OAGL,QAASC,MAAKL,GACV,GAAIM,KAAMC,KAAKC,OAAO,EAAE,GAAG,EAE3B,OAAKF,KAIET,GAAGS,IAAIN,IAAID,KAAKM,MAHZL,EANf,GAAIO,MAAOE,MAAMC,UAAUC,MAAMC,MAAMC,UAYvC,OAAO,UAAUC,MACb,MAAOT,MAAKS,MAAMxD,KAAK8C,IAAI9C,OAInC,QAASyD,SAAQC,KACb,GAAI5D,MACA6D,WAEAC,SAAUF,IAEVjB,KAAM,SAAUoB,IAEZ,MADA1B,MAAKwB,QAAQ7C,KAAK+C,IACX1B,MAGX2B,MAAO,WACH,GAAIC,OAAQ5B,IAQZ,OALAA,MAAKM,KAAK,SAAUxF,KAEhB,MADA8G,OAAMJ,QAAQrB,OAAS,EAChBrF,MAGJ6F,IAAIQ,MAAM,KAAMnB,KAAKwB,YAGhC3D,KAAM,SAAU6D,IAEZ,MADAf,KAAI9C,KAAO6D,GACJ1B,MAIf,IAAI6B,WAAY,SAAUtB,EAAGgB,KACzB,GAAIG,IAAKH,IAAIhB,GAAGuB,KAAKP,IACrB,OAAO,YACH,GAAIQ,MAAOf,MAAMC,UAAUC,MAAMC,MAAMC,UAEvC,OADApB,MAAKwB,QAAQ7C,KAAKqD,SAASF,KAAKX,MAAMO,IAAK,MAAMO,OAAOF,QACjD/B,MAIf,KAAK,GAAIkC,QAAQX,KACY,kBAAdA,KAAIW,MACXvE,IAAIuE,MAAQL,UAAUK,KAAMX,KAE5B5D,IAAIuE,MAAQX,IAAIW,KAIxB,OAAOvE,KAGXhB,OAAOC,QAAU0E;;AgChFjB,YAEA3E,QAAOC,SACH0O,MAAO,SAAU/J,IAAKuF,OAClB,GAAInJ,OACJ,KAAK,GAAI4C,KAAKgB,KACNuF,MAAMnH,QAAQY,MAAO,IACrB5C,IAAI4C,GAAKgB,IAAIhB,GAIrB,OAAO5C;;AQXf,YAEA,IAAIyN,eAAgBzQ,QAAQ,mCAE5B,IAAIsR,YAAY,GAAIb,gBAAgBhG,IAAI,SACxC,IAAI6qB,kBACJ,IAAIC,cAKAvkB,QAASM,UAAU5B,YAKnBuB,QAASK,UAAU1B,YACnBuN,QAAS7L,UAAU7O,cACnB9C,SAGJ,IAAIinB,cAMApQ,WAAY,SAAU5N,SAClB,MAAOjG,GAAEM,QAAO,KAAUsyB,YAAaD,eAAgB1sB,UAM3D4sB,YAAa,SAAU9oB,UACnB4oB,eAAiB5oB,UAGzB1K,QAAOC,QAAU2kB;;AzCnCjB,YAEA5kB,QAAOC,QAAW,WAEd,OAMImB,eAAgB,SAAUC,IACtB,GAAW,OAAPA,IAAsBC,SAAPD,IAA2B,KAAPA,GACnC,MAAO,GAEX,IAAkB,gBAAPA,KAAmBA,aAAcE,QACxC,MAAOF,GAGX,IAAIG,eACJ,IAAIC,YAAa,IAAK,IAAK,IAC3Bd,GAAEe,KAAKL,GAAI,SAAUM,IAAKC,OACD,gBAAVA,QAAsBjB,EAAEkB,QAAQlB,EAAEmB,KAAKF,OAAOG,OAAO,GAAIN,cAAe,IAC/EG,MAAQ,IAAMA,OAElBJ,YAAYQ,KAAKL,IAAMC,QAG3B,IAAIK,MAAO,IAAMT,YAAYU,KAAK,IAClC,OAAOD,OAQXE,cAAe,SAAUd,IACrB,GAAW,OAAPA,IAAsBC,SAAPD,GACf,MAAO,EAEX,IAAkB,gBAAPA,KAAmBA,aAAcE,QACxC,MAAOF,GAGX,IAAIG,eACJb,GAAEe,KAAKL,GAAI,SAAUM,IAAKC,OAClBjB,EAAEyB,QAAQR,SACVA,MAAQA,MAAMM,KAAK,MAEnBvB,EAAE0B,cAAcT,SAEhBA,MAAQU,KAAKC,UAAUX,QAE3BJ,YAAYQ,KAAKL,IAAM,IAAMC,QAGjC,IAAIY,QAAShB,YAAYU,KAAK,IAC9B,OAAOM,SAQXC,WAAY,SAAUpB,IAClB,GAAW,OAAPA,IAAsBC,SAAPD,IAA2B,KAAPA,GACnC,QAGJ,IAAIqB,SAAUrB,GAAGsB,MAAM,IACvB,IAAIC,aAYJ,OAXAjC,GAAEe,KAAKgB,QAAS,SAAUG,MAAOjB,OAC7B,GAAIkB,MAAOlB,MAAMe,MAAM,KAAK,EAC5B,IAAII,MAAOnB,MAAMe,MAAM,KAAK,EAExBI,MAAKC,QAAQ,QAAS,IACtBD,KAAOA,KAAKJ,MAAM,MAGtBC,UAAUE,MAAQC,OAGfH,WASXK,QAAS,SAAUC,IAAKC,KACpB,GAAIC,MAAOC,KAAKZ,WAAWY,KAAKlB,cAAce,KAC9C,IAAII,MAAOD,KAAKZ,WAAWY,KAAKlB,cAAcgB,KAC9C,OAAOxC,GAAEM,QAAO,KAAUmC,KAAME,OAGpCC,iBAAkB,SAAU1C,KACxB,MAAKA,KAGkC,MAA/BA,IAAIkB,OAAOlB,IAAI2C,OAAS,GAAc3C,IAAOA,IAAM,IAFhD;;AEpGvB,YACA,IAAI2E,OAAQxH,QAAQ,eACpB,IAAIyH,gBAAiB,IAErBzF,QAAOC,QAAW,WACd,OAOIyF,oBAAqB,SAAUC,WAAYP,MAClCA,OACDA,QAEJ,IAAIQ,aACAC,OACAT,QAGJ,IAAIU,SAAU,SAAUC,KACpB,MAAgB,QAARA,KAAwBzE,SAARyE,OAAwBT,OAAOS,QAI3D,IAAIC,wBAAyB,SAAUL,WAAYC,YAQ/C,MAPKA,cACDA,YAAeC,OAAST,UAE5BzE,EAAEe,KAAKiE,WAAY,SAAUM,IAAKC,KAC9BN,WAAWC,IAAI7D,KAAKiE,KACpBL,WAAWR,KAAKpD,KAAK8D,QAAQI,QAE1BN,WAGX,IAAIO,6BAA8B,SAAUC,UAAWR,YAMnD,MALKA,cACDA,YAAeC,OAAST,UAE5BQ,WAAWC,IAAI7D,KAAKoE,UAAUC,MAC9BT,WAAWR,KAAKpD,KAAK8D,QAAQM,UAAUE,SAChCV,WAGX,IAAIW,kBAAmB,SAAUH,UAAWR,YACxC,OAASQ,UAAc,KAAID,4BAA8BH,wBAAwBI,UAAWR,YAGhG,IAAIY,oBAAqB,SAAUJ,UAAWhB,KAAMQ,YAMhD,MALKA,cACDA,YAAeC,OAAST,UAE5BQ,WAAWC,IAAI7D,KAAKoE,WACpBR,WAAWR,KAAKpD,KAAK8D,QAAQV,OACtBQ,WAIX,IAAIa,kBAAmB,SAAUd,WAAYO,IAAKN,YAW9C,MAVKA,cACDA,YAAeC,OAAST,UAE5BzE,EAAEe,KAAKiE,WAAY,SAAU9C,MAAOoD,KAC5BtF,EAAE0B,cAAc4D,KAChBM,iBAAiBN,IAAKL,YAEtBY,mBAAmBP,IAAKb,KAAKvC,OAAQ+C,cAGtCA,WAWX,OARIjF,GAAE0B,cAAcsD,YAChBY,iBAAiBZ,WAAYC,YACtBjF,EAAEyB,QAAQuD,YACjBc,iBAAiBd,WAAYP,KAAMQ,YAEnCY,mBAAmBb,WAAYP,KAAMQ,YAGlCA,YAGXc,gBAAiB,SAAUC,aACvB,MAAO,UAAUL,OAAQM,SACrB,GAAIC,MAAOxD,IACX,IAAIyD,UAAW,SAAUT,MACrB,GAAIzE,OAAQgF,QAAQP,OAASM,YAAYN,KAIzC,OAHqB,kBAAVzE,SACPA,MAAQA,SAELA,MAEX,IAAImF,aAAc,SAAUT,QACxB,GAAIzF,KAAMiG,SAAS,MAAOF,QAC1B,IAAII,MAAOV,MAIXzF,KAAMA,IAAIoG,QAAQ,OAAQ,GAE1B,IAAIC,aAAc1B,MAAMrD,cAAc6E,KACtC,IAAIG,aAActG,IAAImC,QAAQ,IAC9B,OAAIkE,cAAeC,aAAc,EACtBtG,IAAM,IAAMqG,YACZA,YACArG,IAAM,IAAMqG,YAEhBrG,IAEX,IAAIA,KAAMkG,YAAYT,OAGtB,IAAIA,QAAUA,OAAOc,SAAWC,UAAUxG,KAAK2C,OAASiC,eAAgB,CACpE,GAAI6B,KAAM3G,EAAEkD,UACZ,IAAI0D,YAAa5G,EAAEM,QAAO,KAAUqF,cAC7BiB,YAAWH,OAClB,IAAII,eAAgBT,YAAYQ,WAChC,IAAIE,MAAOhC,eAAiB+B,cAAchE,MAC1C,IAAIkE,YAAad,QAAQe,SAAWhB,YAAYgB,SAAWhH,EAAEiH,IAC7D,IAAIC,UAAWjB,QAAQkB,OAASnB,YAAYmB,OAASnH,EAAEiH,IAEvDhB,SAAQe,QAAUhH,EAAEiH,KACpBhB,QAAQkB,MAAQnH,EAAEiH,IAElB,IAAIR,SAAUd,OAAOc,OACrB,IAAIW,gBACJ,IAAIC,cAAeD,aACnB,IAAIE,YAAaC,mBAAmB,aAAa1E,MACjD,IAAI2E,UAAWf,QAAQgB,KACvB,MAAOD,UAAU,CACb,GAAIE,WAAYH,mBAAmBC,UAAU3E,MAIzCyE,YAAaI,UAAY,EAAIZ,MAC7BM,aAAa/F,KAAKmG,UAClBF,YAAcI,UAAY,IAE1BN,cAAgBI,UAChBH,YAAYhG,KAAK+F,cACjBE,WAAa,YAAYzE,OAAS6E,WAEtCF,SAAWf,QAAQgB,MAEvB,GAAIE,MAAO3H,EAAE4H,IAAIP,YAAa,SAAUZ,SACpC,GAAIoB,WAAY7H,EAAEM,UAAWqF,QAAUc,QAASA,SAChD,OAAOP,MAAK4B,IAAID,UAAW5B,UA8D/B,OA5DAjG,GAAE+H,KAAKlE,MAAM7D,EAAG2H,MAAM3E,KAAK,WAGvB,GAAIgF,SAAUlE,UAAU,IAAMA,UAAU,GAAG,EAC3C,KAAKkE,QAGD,MADAd,YACOP,IAAIsB,QAEf,IAAIC,eAAgBpE,UAAU,GAAG,EACjC,IAAIqE,UAAWnI,EAAE0B,cAAcwG,cAC/B,IAAIE,UAAYD,UAAYnI,EAAE0B,cAAcwG,cAAcG,aAAgBF,QAC1E,IAAIC,SACA,GAAID,SAAU,CAEV,GAAIG,cAAexE,UAAU,GAAG,EAChC9D,GAAEe,KAAK+C,UAAW,SAAUyE,IAAK9D,MAC7B,GAAIjH,KAAMiH,KAAK,EACfzE,GAAEM,QAAO,EAAMgI,aAAaD,UAAW7K,IAAI6K,aAE/CtB,WAAWuB,aAAcxE,UAAU,GAAG,GAAIA,UAAU,GAAG,IACvD6C,IAAIxD,QAAQmF,aAAcxE,UAAU,GAAG,GAAIA,UAAU,GAAG,QACrD,CAGH,GAAI0E,kBACJxI,GAAEe,KAAK+C,UAAW,SAAUyE,IAAK9D,MAC7B,GAAIgE,MAAOhE,KAAK,EACXzE,GAAEyB,QAAQgH,OAGfzI,EAAEe,KAAK0H,KAAM,SAAUC,OAAQlL,KACvBA,IAAImL,KAAOH,eAAehL,IAAImL,KAC9BnL,IAAI6K,UAAY7K,IAAI6K,cACpBG,eAAehL,IAAImL,IAAMnL,KAClBA,IAAImL,IACX3I,EAAEM,QAAO,EAAMkI,eAAehL,IAAImL,IAAIN,UAAW7K,IAAI6K,eAKjEG,eAAiBxI,EAAE4H,IAAIY,eAAgB,SAAUhL,KAAO,MAAOA,OAC/DuJ,WAAWyB,eAAgB1E,UAAU,GAAG,GAAIA,UAAU,GAAG,IACzD6C,IAAIxD,QAAQqF,eAAgB1E,UAAU,GAAG,GAAIA,UAAU,GAAG,QAE3D,CAGH,GAAI8E,uBACJ5I,GAAEe,KAAK+C,UAAW,SAAUyE,IAAK9D,MAC7B,GAAIoE,MAAOpE,KAAK,EAChBzE,GAAEM,QAAO,EAAMsI,oBAAqBC,QAExC9B,WAAW6B,oBAAqB9E,UAAU,GAAG,GAAIA,UAAU,GAAG,IAC9D6C,IAAIxD,QAAQyF,oBAAqB9E,UAAU,GAAG,GAAIA,UAAU,GAAG,MAEpE,WACCoD,SAASrD,MAAMqC,KAAMpC,WACrB6C,IAAIsB,OAAOpE,MAAM8C,IAAK7C,aAEnB6C,IAAIvD,UAEX,MAAO8C,MAAK4B,IAAInC,OAAQM","file":"bundle.js","sourcesContent":["(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require==\"function\"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error(\"Cannot find module '\"+o+\"'\");throw f.code=\"MODULE_NOT_FOUND\",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require==\"function\"&&require;for(var o=0;o\n * https://github.com/forio/epicenter-js-libs\n */\n\nvar F = {\n util: {},\n factory: {},\n transport: {},\n store: {},\n service: {},\n manager: {\n strategy: {}\n },\n\n};\n\nF.load = require('./env-load');\nF.load();\n\nF.util.query = require('./util/query-util');\nF.util.makeSequence = require('./util/make-sequence');\nF.util.run = require('./util/run-util');\nF.util.classFrom = require('./util/inherit');\n\nF.factory.Transport = require('./transport/http-transport-factory');\nF.transport.Ajax = require('./transport/ajax-http-transport');\n\nF.service.URL = require('./service/url-config-service');\nF.service.Config = require('./service/configuration-service');\nF.service.Run = require('./service/run-api-service');\nF.service.File = require('./service/admin-file-service');\nF.service.Variables = require('./service/variables-api-service');\nF.service.Data = require('./service/data-api-service');\nF.service.Auth = require('./service/auth-api-service');\nF.service.World = require('./service/world-api-adapter');\nF.service.State = require('./service/state-api-adapter');\nF.service.User = require('./service/user-api-adapter');\nF.service.Member = require('./service/member-api-adapter');\nF.service.Asset = require('./service/asset-api-adapter');\nF.service.Group = require('./service/group-api-service');\n\nF.store.Cookie = require('./store/cookie-store');\nF.factory.Store = require('./store/store-factory');\n\nF.manager.ScenarioManager = require('./managers/scenario-manager');\nF.manager.RunManager = require('./managers/run-manager');\nF.manager.AuthManager = require('./managers/auth-manager');\nF.manager.WorldManager = require('./managers/world-manager');\n\nF.manager.strategy['always-new'] = require('./managers/run-strategies/always-new-strategy');\nF.manager.strategy['conditional-creation'] = require('./managers/run-strategies/conditional-creation-strategy');\nF.manager.strategy.identity = require('./managers/run-strategies/identity-strategy');\nF.manager.strategy['new-if-missing'] = require('./managers/run-strategies/new-if-missing-strategy');\nF.manager.strategy['new-if-missing'] = require('./managers/run-strategies/new-if-missing-strategy');\nF.manager.strategy['new-if-persisted'] = require('./managers/run-strategies/new-if-persisted-strategy');\nF.manager.strategy['new-if-initialized'] = require('./managers/run-strategies/new-if-initialized-strategy');\n\nF.manager.ChannelManager = require('./managers/epicenter-channel-manager');\nF.service.Channel = require('./service/channel-service');\n\nF.version = '<%= version %>';\nF.api = require('./api-version.json');\n\nglobal.F = F;\nmodule.exports = F;\n","'use strict';\n\nvar urlConfigService = require('./service/url-config-service');\n\nvar envLoad = function (callback) {\n var envPromise;\n var host;\n var urlService = urlConfigService();\n var envPath = '/epicenter/v1/config';\n if (urlService.isLocalhost()) {\n host = 'https://forio.com';\n } else {\n host = '';\n }\n var infoUrl = host + envPath;\n envPromise = $.ajax({ url: infoUrl, async: false });\n envPromise.done(function (res) {\n var api = res.api;\n $.extend(urlConfigService, api);\n }).fail(function (res) {\n // Epicenter/webserver not properly configured\n // fallback to api.forio.com\n $.extend(urlConfigService, { protocol: 'https', host: 'api.forio.com' });\n });\n return envPromise.done(callback).fail(callback);\n};\n\nmodule.exports = envLoad;\n","/**\n * Utilities for working with query strings\n*/\n'use strict';\n\nmodule.exports = (function () {\n\n return {\n /**\n * Converts to matrix format\n * @param {Object} qs Object to convert to query string\n * @return { string} Matrix-format query parameters\n */\n toMatrixFormat: function (qs) {\n if (qs === null || qs === undefined || qs === '') {\n return ';';\n }\n if (typeof qs === 'string' || qs instanceof String) {\n return qs;\n }\n\n var returnArray = [];\n var OPERATORS = ['<', '>', '!'];\n $.each(qs, function (key, value) {\n if (typeof value !== 'string' || $.inArray($.trim(value).charAt(0), OPERATORS) === -1) {\n value = '=' + value;\n }\n returnArray.push(key + value);\n });\n\n var mtrx = ';' + returnArray.join(';');\n return mtrx;\n },\n\n /**\n * Converts strings/arrays/objects to type 'a=b&b=c'\n * @param { string|Array|Object} qs\n * @return { string}\n */\n toQueryFormat: function (qs) {\n if (qs === null || qs === undefined) {\n return '';\n }\n if (typeof qs === 'string' || qs instanceof String) {\n return qs;\n }\n\n var returnArray = [];\n $.each(qs, function (key, value) {\n if ($.isArray(value)) {\n value = value.join(',');\n }\n if ($.isPlainObject(value)) {\n //Mostly for data api\n value = JSON.stringify(value);\n }\n returnArray.push(key + '=' + value);\n });\n\n var result = returnArray.join('&');\n return result;\n },\n\n /**\n * Converts strings of type 'a=b&b=c' to { a:b, b:c}\n * @param { string} qs\n * @return {object}\n */\n qsToObject: function (qs) {\n if (qs === null || qs === undefined || qs === '') {\n return {};\n }\n\n var qsArray = qs.split('&');\n var returnObj = {};\n $.each(qsArray, function (index, value) {\n var qKey = value.split('=')[0];\n var qVal = value.split('=')[1];\n\n if (qVal.indexOf(',') !== -1) {\n qVal = qVal.split(',');\n }\n\n returnObj[qKey] = qVal;\n });\n\n return returnObj;\n },\n\n /**\n * Normalizes and merges strings of type 'a=b', { b:c} to { a:b, b:c}\n * @param { string|Array|Object} qs1\n * @param { string|Array|Object} qs2\n * @return {Object}\n */\n mergeQS: function (qs1, qs2) {\n var obj1 = this.qsToObject(this.toQueryFormat(qs1));\n var obj2 = this.qsToObject(this.toQueryFormat(qs2));\n return $.extend(true, {}, obj1, obj2);\n },\n\n addTrailingSlash: function (url) {\n if (!url) {\n return '';\n }\n return (url.charAt(url.length - 1) === '/') ? url : (url + '/');\n }\n };\n}());\n\n\n\n","'use strict';\n/*jshint loopfunc:false */\n\nfunction _w(val) {\n if (val && val.then) {\n return val;\n }\n var p = $.Deferred();\n p.resolve(val);\n\n return p.promise();\n}\n\nfunction seq() {\n var list = Array.prototype.slice.apply(arguments);\n\n function next(p) {\n var cur = list.splice(0,1)[0];\n\n if (!cur) {\n return p;\n }\n\n return _w(cur(p)).then(next);\n }\n\n return function (seed) {\n return next(seed).fail(seq.fail);\n };\n}\n\nfunction MakeSeq(obj) {\n var res = {\n __calls: [],\n\n original: obj,\n\n then: function (fn) {\n this.__calls.push(fn);\n return this;\n },\n\n start: function () {\n var _this = this;\n\n // clean up\n this.then(function (run) {\n _this.__calls.length = 0;\n return run;\n });\n\n return seq.apply(null, this.__calls)();\n },\n\n fail: function (fn) {\n seq.fail = fn;\n return this;\n }\n };\n\n var funcMaker = function (p, obj) {\n var fn = obj[p].bind(obj);\n return function () {\n var args = Array.prototype.slice.apply(arguments);\n this.__calls.push(Function.bind.apply(fn, [null].concat(args)));\n return this;\n };\n };\n\n for (var prop in obj) {\n if (typeof obj[prop] === 'function') {\n res[prop] = funcMaker(prop, obj);\n } else {\n res[prop] = obj[prop];\n }\n }\n\n return res;\n}\n\nmodule.exports = MakeSeq;\n","/**\n * Utilities for working with the run service\n*/\n'use strict';\nvar qutil = require('./query-util');\nvar MAX_URL_LENGTH = 2048;\n\nmodule.exports = (function () {\n return {\n /**\n * returns operations of the form `[[op1,op2], [arg1, arg2]]`\n * @param {Object|Array|String} `operations` operations to perform\n * @param {Array} `args` arguments for operation\n * @return {String} Matrix-format query parameters\n */\n normalizeOperations: function (operations, args) {\n if (!args) {\n args = [];\n }\n var returnList = {\n ops: [],\n args: []\n };\n\n var _concat = function (arr) {\n return (arr !== null && arr !== undefined) ? [].concat(arr) : [];\n };\n\n //{ add: [1,2], subtract: [2,4] }\n var _normalizePlainObjects = function (operations, returnList) {\n if (!returnList) {\n returnList = { ops: [], args: [] };\n }\n $.each(operations, function (opn, arg) {\n returnList.ops.push(opn);\n returnList.args.push(_concat(arg));\n });\n return returnList;\n };\n //{ name: 'add', params: [1] }\n var _normalizeStructuredObjects = function (operation, returnList) {\n if (!returnList) {\n returnList = { ops: [], args: [] };\n }\n returnList.ops.push(operation.name);\n returnList.args.push(_concat(operation.params));\n return returnList;\n };\n\n var _normalizeObject = function (operation, returnList) {\n return ((operation.name) ? _normalizeStructuredObjects : _normalizePlainObjects)(operation, returnList);\n };\n\n var _normalizeLiterals = function (operation, args, returnList) {\n if (!returnList) {\n returnList = { ops: [], args: [] };\n }\n returnList.ops.push(operation);\n returnList.args.push(_concat(args));\n return returnList;\n };\n\n\n var _normalizeArrays = function (operations, arg, returnList) {\n if (!returnList) {\n returnList = { ops: [], args: [] };\n }\n $.each(operations, function (index, opn) {\n if ($.isPlainObject(opn)) {\n _normalizeObject(opn, returnList);\n } else {\n _normalizeLiterals(opn, args[index], returnList);\n }\n });\n return returnList;\n };\n\n if ($.isPlainObject(operations)) {\n _normalizeObject(operations, returnList);\n } else if ($.isArray(operations)) {\n _normalizeArrays(operations, args, returnList);\n } else {\n _normalizeLiterals(operations, args, returnList);\n }\n\n return returnList;\n },\n\n splitGetFactory: function (httpOptions) {\n return function (params, options) {\n var http = this;\n var getValue = function (name) {\n var value = options[name] || httpOptions[name];\n if (typeof value === 'function') {\n value = value();\n }\n return value;\n };\n var getFinalUrl = function (params) {\n var url = getValue('url', options);\n var data = params;\n // There is easy (or known) way to get the final URL jquery is going to send so\n // we're replicating it. The process might change at some point but it probably will not.\n // 1. Remove hash\n url = url.replace(/#.*$/, '');\n // 1. Append query string\n var queryParams = qutil.toQueryFormat(data);\n var questionIdx = url.indexOf('?');\n if (queryParams && questionIdx > -1) {\n return url + '&' + queryParams;\n } else if (queryParams) {\n return url + '?' + queryParams;\n }\n return url;\n };\n var url = getFinalUrl(params);\n // We must split the GET in multiple short URL's\n // The only property allowed to be split is \"include\"\n if (params && params.include && encodeURI(url).length > MAX_URL_LENGTH) {\n var dtd = $.Deferred();\n var paramsCopy = $.extend(true, {}, params);\n delete paramsCopy.include;\n var urlNoIncludes = getFinalUrl(paramsCopy);\n var diff = MAX_URL_LENGTH - urlNoIncludes.length;\n var oldSuccess = options.success || httpOptions.success || $.noop;\n var oldError = options.error || httpOptions.error || $.noop;\n // remove the original success and error callbacks\n options.success = $.noop;\n options.error = $.noop;\n\n var include = params.include;\n var currIncludes = [];\n var includeOpts = [currIncludes];\n var currLength = encodeURIComponent('?include=').length;\n var variable = include.pop();\n while (variable) {\n var varLenght = encodeURIComponent(variable).length;\n // Use a greedy approach for now, can be optimized to be solved in a more\n // efficient way\n // + 1 is the comma\n if (currLength + varLenght + 1 < diff) {\n currIncludes.push(variable);\n currLength += varLenght + 1;\n } else {\n currIncludes = [variable];\n includeOpts.push(currIncludes);\n currLength = '?include='.length + varLenght;\n }\n variable = include.pop();\n }\n var reqs = $.map(includeOpts, function (include) {\n var reqParams = $.extend({}, params, { include: include });\n return http.get(reqParams, options);\n });\n $.when.apply($, reqs).then(function () {\n // Each argument are arrays of the arguments of each done request\n // So the first argument of the first array of arguments is the data\n var isValid = arguments[0] && arguments[0][0];\n if (!isValid) {\n // Should never happen...\n oldError();\n return dtd.reject();\n }\n var firstResponse = arguments[0][0];\n var isObject = $.isPlainObject(firstResponse);\n var isRunAPI = (isObject && $.isPlainObject(firstResponse.variables)) || !isObject;\n if (isRunAPI) {\n if (isObject) {\n // aggregate the variables property only\n var aggregateRun = arguments[0][0];\n $.each(arguments, function (idx, args) {\n var run = args[0];\n $.extend(true, aggregateRun.variables, run.variables);\n });\n oldSuccess(aggregateRun, arguments[0][1], arguments[0][2]);\n dtd.resolve(aggregateRun, arguments[0][1], arguments[0][2]);\n } else {\n // array of runs\n // Agregate variables in each run\n var aggregatedRuns = {};\n $.each(arguments, function (idx, args) {\n var runs = args[0];\n if (!$.isArray(runs)) {\n return;\n }\n $.each(runs, function (idxRun, run) {\n if (run.id && !aggregatedRuns[run.id]) {\n run.variables = run.variables || {};\n aggregatedRuns[run.id] = run;\n } else if (run.id) {\n $.extend(true, aggregatedRuns[run.id].variables, run.variables);\n }\n });\n });\n // turn it into an array\n aggregatedRuns = $.map(aggregatedRuns, function (run) { return run; });\n oldSuccess(aggregatedRuns, arguments[0][1], arguments[0][2]);\n dtd.resolve(aggregatedRuns, arguments[0][1], arguments[0][2]);\n }\n } else {\n // is variables API\n // aggregate the response\n var aggregatedVariables = {};\n $.each(arguments, function (idx, args) {\n var vars = args[0];\n $.extend(true, aggregatedVariables, vars);\n });\n oldSuccess(aggregatedVariables, arguments[0][1], arguments[0][2]);\n dtd.resolve(aggregatedVariables, arguments[0][1], arguments[0][2]);\n }\n }, function () {\n oldError.apply(http, arguments);\n dtd.reject.apply(dtd, arguments);\n });\n return dtd.promise();\n } else {\n return http.get(params, options);\n }\n };\n }\n };\n}());\n","/**\n/* Inherit from a class (using prototype borrowing)\n*/\n'use strict';\n\nfunction inherit(C, P) {\n var F = function () {};\n F.prototype = P.prototype;\n C.prototype = new F();\n C.__super = P.prototype;\n C.prototype.constructor = C;\n}\n\n/**\n* Shallow copy of an object\n*/\nvar extend = function (dest /*, var_args*/) {\n var obj = Array.prototype.slice.call(arguments, 1);\n var current;\n for (var j = 0; j 1,\n * // where variables.price has been persisted (recorded)\n * // in the model.\n * rs.query({\n * 'saved': 'true',\n * '.price': '>1'\n * },\n * {\n * startrecord: 2,\n * endrecord: 5\n * });\n *\n * **Parameters**\n * @param {Object} `qs` Query object. Each key can be a property of the run or the name of variable that has been saved in the run (prefaced by `variables.`). Each value can be a literal value, or a comparison operator and value. (See [more on filtering](../../../rest_apis/aggregate_run_api/#filters) allowed in the underlying Run API.) Querying for variables is available for runs [in memory](../../../run_persistence/#runs-in-memory) and for runs [in the database](../../../run_persistence/#runs-in-memory) if the variables are persisted (e.g. that have been `record`ed in your Julia model).\n * @param {Object} `outputModifier` (Optional) Available fields include: `startrecord`, `endrecord`, `sort`, and `direction` (`asc` or `desc`).\n * @param {Object} `options` (Optional) Overrides for configuration options.\n */\n query: function (qs, outputModifier, options) {\n serviceOptions.filter = qs; //shouldn't be able to over-ride\n var httpOptions = $.extend(true, {}, serviceOptions, options);\n httpOptions = urlConfig.addAutoRestoreHeader(httpOptions);\n\n return http.splitGet(outputModifier, httpOptions);\n },\n\n /**\n * Returns particular runs, based on conditions specified in the `qs` object.\n *\n * Similar to `.query()`.\n *\n * **Parameters**\n * @param {Object} `filter` Filter object. Each key can be a property of the run or the name of variable that has been saved in the run (prefaced by `variables.`). Each value can be a literal value, or a comparison operator and value. (See [more on filtering](../../../rest_apis/aggregate_run_api/#filters) allowed in the underlying Run API.) Filtering for variables is available for runs [in memory](../../../run_persistence/#runs-in-memory) and for runs [in the database](../../../run_persistence/#runs-in-memory) if the variables are persisted (e.g. that have been `record`ed in your Julia model).\n * @param {Object} `outputModifier` (Optional) Available fields include: `startrecord`, `endrecord`, `sort`, and `direction` (`asc` or `desc`).\n * @param {Object} `options` (Optional) Overrides for configuration options.\n */\n filter: function (filter, outputModifier, options) {\n if ($.isPlainObject(serviceOptions.filter)) {\n $.extend(serviceOptions.filter, filter);\n } else {\n serviceOptions.filter = filter;\n }\n var httpOptions = $.extend(true, {}, serviceOptions, options);\n httpOptions = urlConfig.addAutoRestoreHeader(httpOptions);\n return http.splitGet(outputModifier, httpOptions);\n },\n\n /**\n * Get data for a specific run. This includes standard run data such as the account, model, project, and created and last modified dates. To request specific model variables, pass them as part of the `filters` parameter.\n *\n * Note that if the run is [in memory](../../../run_persistence/#runs-in-memory), any model variables are available; if the run is [in the database](../../../run_persistence/#runs-in-db), only model variables that have been persisted — that is, `record`ed in your Julia model — are available.\n *\n * **Example**\n *\n * rs.load('bb589677-d476-4971-a68e-0c58d191e450', { include: ['.price', '.sales'] });\n *\n * **Parameters**\n * @param {String} `runID` The run id.\n * @param {Object} `filters` (Optional) Object containing filters and operation modifiers. Use key `include` to list model variables that you want to include in the response. Other available fields include: `startrecord`, `endrecord`, `sort`, and `direction` (`asc` or `desc`).\n * @param {Object} `options` (Optional) Overrides for configuration options.\n */\n load: function (runID, filters, options) {\n if (runID) {\n serviceOptions.filter = runID; //shouldn't be able to over-ride\n }\n var httpOptions = $.extend(true, {}, serviceOptions, options);\n httpOptions = urlConfig.addAutoRestoreHeader(httpOptions);\n return http.get(filters, httpOptions);\n },\n\n\n /**\n * Save attributes (data, model variables) of the run.\n *\n * **Examples**\n *\n * // add 'completed' field to run record\n * rs.save({ completed: true });\n *\n * // update 'saved' field of run record, and update values of model variables for this run\n * rs.save({ saved: true, variables: { a: 23, b: 23 } });\n *\n * **Parameters**\n * @param {Object} `attributes` The run data and variables to save.\n * @param {Object} `attributes.variables` Model variables must be included in a `variables` field within the `attributes` object. (Otherwise they are treated as run data and added to the run record directly.)\n * @param {Object} `options` (Optional) Overrides for configuration options.\n */\n save: function (attributes, options) {\n var httpOptions = $.extend(true, {}, serviceOptions, options);\n setFilterOrThrowError(httpOptions);\n return http.patch(attributes, httpOptions);\n },\n\n /**\n * Call a method from the model.\n *\n * Depending on the language in which you have written your model, the method may need to be exposed (e.g. `export` for a Julia model) in the model file in order to be called through the API. See [Writing your Model](../../../writing_your_model/)).\n *\n * The `params` argument is normally an array of arguments to the `operation`. In the special case where `operation` only takes one argument, you are not required to put that argument into an array.\n *\n * Note that you can combine the `operation` and `params` arguments into a single object if you prefer, as in the last example.\n *\n * **Examples**\n *\n * // method \"solve\" takes no arguments\n * rs.do('solve');\n * // method \"echo\" takes one argument, a string\n * rs.do('echo', ['hello']);\n * // method \"echo\" takes one argument, a string\n * rs.do('echo', 'hello');\n * // method \"sumArray\" takes one argument, an array\n * rs.do('sumArray', [[4,2,1]]);\n * // method \"add\" takes two arguments, both integers\n * rs.do({ name:'add', params:[2,4] });\n *\n * **Parameters**\n * @param {String} `operation` Name of method.\n * @param {Array} `params` (Optional) Any parameters the operation takes, passed as an array. In the special case where `operation` only takes one argument, you are not required to put that argument into an array, and can just pass it directly.\n * @param {Object} `options` (Optional) Overrides for configuration options.\n */\n do: function (operation, params, options) {\n // console.log('do', operation, params);\n var opsArgs;\n var postOptions;\n if (options) {\n opsArgs = params;\n postOptions = options;\n } else {\n if ($.isPlainObject(params)) {\n opsArgs = null;\n postOptions = params;\n } else {\n opsArgs = params;\n }\n }\n var result = rutil.normalizeOperations(operation, opsArgs);\n var httpOptions = $.extend(true, {}, serviceOptions, postOptions);\n\n setFilterOrThrowError(httpOptions);\n\n var prms = (result.args[0].length && (result.args[0] !== null && result.args[0] !== undefined)) ? result.args[0] : [];\n return http.post({ arguments: prms }, $.extend(true, {}, httpOptions, {\n url: urlConfig.getFilterURL() + 'operations/' + result.ops[0] + '/'\n }));\n },\n\n /**\n * Call several methods from the model, sequentially.\n *\n * Depending on the language in which you have written your model, the methods may need to be exposed (e.g. `export` for a Julia model) in the model file in order to be called through the API. See [Writing your Model](../../../writing_your_model/)).\n *\n * **Examples**\n *\n * // methods \"initialize\" and \"solve\" do not take any arguments\n * rs.serial(['initialize', 'solve']);\n * // methods \"init\" and \"reset\" take two arguments each\n * rs.serial([ { name: 'init', params: [1,2] },\n * { name: 'reset', params: [2,3] }]);\n * // method \"init\" takes two arguments,\n * // method \"runmodel\" takes none\n * rs.serial([ { name: 'init', params: [1,2] },\n * { name: 'runmodel', params: [] }]);\n *\n * **Parameters**\n * @param {Array} `operations` If none of the methods take parameters, pass an array of the method names (strings). If any of the methods do take parameters, pass an array of objects, each of which contains a method name and its own (possibly empty) array of parameters.\n * @param {*} `params` Parameters to pass to operations.\n * @param {Object} `options` (Optional) Overrides for configuration options.\n */\n serial: function (operations, params, options) {\n var opParams = rutil.normalizeOperations(operations, params);\n var ops = opParams.ops;\n var args = opParams.args;\n var me = this;\n\n var $d = $.Deferred();\n var postOptions = $.extend(true, {}, serviceOptions, options);\n\n var doSingleOp = function () {\n var op = ops.shift();\n var arg = args.shift();\n\n me.do(op, arg, {\n success: function () {\n if (ops.length) {\n doSingleOp();\n } else {\n $d.resolve.apply(this, arguments);\n postOptions.success.apply(this, arguments);\n }\n },\n error: function () {\n $d.reject.apply(this, arguments);\n postOptions.error.apply(this, arguments);\n }\n });\n };\n\n doSingleOp();\n\n return $d.promise();\n },\n\n /**\n * Call several methods from the model, executing them in parallel.\n *\n * Depending on the language in which you have written your model, the methods may need to be exposed (e.g. `export` for a Julia model) in the model file in order to be called through the API. See [Writing your Model](../../../writing_your_model/)).\n *\n * **Example**\n *\n * // methods \"solve\" and \"reset\" do not take any arguments\n * rs.parallel(['solve', 'reset']);\n * // methods \"add\" and \"subtract\" take two arguments each\n * rs.parallel([ { name: 'add', params: [1,2] },\n * { name: 'subtract', params:[2,3] }]);\n * // methods \"add\" and \"subtract\" take two arguments each\n * rs.parallel({ add: [1,2], subtract: [2,4] });\n *\n * **Parameters**\n * @param {Array|Object} `operations` If none of the methods take parameters, pass an array of the method names (as strings). If any of the methods do take parameters, you have two options. You can pass an array of objects, each of which contains a method name and its own (possibly empty) array of parameters. Alternatively, you can pass a single object with the method name and a (possibly empty) array of parameters.\n * @param {*} `params` Parameters to pass to operations.\n * @param {Object} `options` (Optional) Overrides for configuration options.\n */\n parallel: function (operations, params, options) {\n var $d = $.Deferred();\n\n var opParams = rutil.normalizeOperations(operations, params);\n var ops = opParams.ops;\n var args = opParams.args;\n var postOptions = $.extend(true, {}, serviceOptions, options);\n\n var queue = [];\n for (var i = 0; i< ops.length; i++) {\n queue.push(\n this.do(ops[i], args[i])\n );\n }\n $.when.apply(this, queue)\n .done(function () {\n $d.resolve.apply(this, arguments);\n postOptions.success.apply(this.arguments);\n })\n .fail(function () {\n $d.reject.apply(this, arguments);\n postOptions.error.apply(this.arguments);\n });\n\n return $d.promise();\n }\n };\n\n var publicSyncAPI = {\n getCurrentConfig: function () {\n return serviceOptions;\n },\n /**\n * Returns a Variables Service instance. Use the variables instance to load, save, and query for specific model variables. See the [Variable API Service](../variables-api-service/) for more information.\n *\n * **Example**\n *\n * var vs = rs.variables();\n * vs.save({ sample_int: 4 });\n *\n * **Parameters**\n * @param {Object} `config` (Optional) Overrides for configuration options.\n */\n variables: function (config) {\n var vs = new VariablesService($.extend(true, {}, serviceOptions, config, {\n runService: this\n }));\n return vs;\n }\n };\n\n $.extend(this, publicAsyncAPI);\n $.extend(this, publicSyncAPI);\n};\n","/**\n * ## File API Service\n *\n * This is used to upload/download files directly onto Epicenter, analogous to using the File Manager UI in Epicenter directly or SFTPing files in. The Asset API is typically used for all project use-cases, and it's unlikely this File Service will be used directly except by Admin tools (e.g. Flow Inspector).\n *\n * Partially implemented.\n */\n\n'use strict';\n\nvar ConfigService = require('./configuration-service');\nvar TransportFactory = require('../transport/http-transport-factory');\nvar SessionManager = require('../store/session-manager');\n\nmodule.exports = function (config) {\n var defaults = {\n /**\n * For projects that require authentication, pass in the user access token (defaults to empty string). If the user is already logged in to Epicenter, the user access token is already set in a cookie and automatically loaded from there. (See [more background on access tokens](../../../project_access/)).\n * @see [Authentication API Service](../auth-api-service/) for getting tokens.\n * @type {String}\n */\n token: undefined,\n\n /**\n * The account id. In the Epicenter UI, this is the **Team ID** (for team projects) or **User ID** (for personal projects). Defaults to empty string.\n * @type {String}\n */\n account: undefined,\n\n /**\n * The project id. Defaults to empty string.\n * @type {String}\n */\n project: undefined,\n\n /**\n * The folder type. One of Model|Static|Node\n * @type {String}\n */\n folderType: 'static',\n\n\n /**\n * Options to pass on to the underlying transport layer. All jquery.ajax options at http://api.jquery.com/jQuery.ajax/ are available. Defaults to empty object.\n * @type {Object}\n */\n transport: {}\n };\n\n this.sessionManager = new SessionManager();\n var serviceOptions = this.sessionManager.getMergedOptions(defaults, config);\n var urlConfig = new ConfigService(serviceOptions).get('server');\n if (serviceOptions.account) {\n urlConfig.accountPath = serviceOptions.account;\n }\n if (serviceOptions.project) {\n urlConfig.projectPath = serviceOptions.project;\n }\n\n var httpOptions = $.extend(true, {}, serviceOptions.transport, {\n url: urlConfig.getAPIPath('file')\n });\n\n if (serviceOptions.token) {\n httpOptions.headers = {\n 'Authorization': 'Bearer ' + serviceOptions.token\n };\n }\n var http = new TransportFactory(httpOptions);\n\n var publicAsyncAPI = {\n /**\n * Get a directory listing, or contents of a file\n * @param {String} `filePath` Path to the file\n * @param {Object} `options` (Optional) Overrides for configuration options.\n */\n getContents: function (filePath, options) {\n var path = serviceOptions.folderType + '/' + filePath;\n var httpOptions = $.extend(true, {}, serviceOptions, options, {\n url: urlConfig.getAPIPath('file') + path\n });\n return http.get('', httpOptions);\n },\n\n /**\n * Writes to the given file path; replaces the existing file if it exists\n * @param {String} `filePath` Path to the file\n * @param {String} `contents` Contents to write to file\n * @param {Object} `options` (Optional) Overrides for configuration options\n */\n writeToFile: function (filePath, contents, options) {\n filePath = filePath.split('/');\n var fileName = filePath.pop();\n filePath = filePath.join('/');\n var path = serviceOptions.folderType + '/' + filePath;\n var boundary = '---------------------------7da24f2e50046';\n\n var body = '--' + boundary + '\\r\\n' +\n 'Content-Disposition: form-data; name=\"file\";' +\n 'filename=\"' + fileName + '\"\\r\\n' +\n 'Content-type: text/html\\r\\n\\r\\n' +\n contents + '\\r\\n' +\n '--' + boundary + '--';\n\n var httpOptions = $.extend(true, {}, serviceOptions, options, {\n url: urlConfig.getAPIPath('file') + path,\n data: body,\n contentType: 'multipart/form-data; boundary=' + boundary\n });\n\n return http.put(body, httpOptions);\n },\n\n /**\n * Removes the file\n * @param {String} `filePath` Path to the file\n * @param {Object} `options` (Optional) Overrides for configuration options\n */\n remove: function (filePath, options) {\n var path = serviceOptions.folderType + '/' + filePath;\n var httpOptions = $.extend(true, {}, serviceOptions, options, {\n url: urlConfig.getAPIPath('file') + path\n });\n return http.delete(null, httpOptions);\n },\n\n /**\n * Rename the file\n * @param {String} filePath Path to the file\n * @param {Stirng} newName New name of file\n * @param {Object} options (Optional) Overrides for configuration options\n */\n rename: function (filePath, newName, options) {\n var path = serviceOptions.folderType + '/' + filePath;\n var httpOptions = $.extend(true, {}, serviceOptions, options, {\n url: urlConfig.getAPIPath('file') + path\n });\n return http.patch({ 'name': newName }, httpOptions);\n }\n };\n\n $.extend(this, publicAsyncAPI);\n};\n","/**\n *\n * ## Variables API Service\n *\n * Used in conjunction with the [Run API Service](../run-api-service/) to read, write, and search for specific model variables.\n *\n * var rm = new F.manager.RunManager({\n * run: {\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * model: 'supply-chain-model.jl'\n * }\n * });\n * rm.getRun()\n * .then(function() {\n * var vs = rm.run.variables();\n * vs.save({sample_int: 4});\n * });\n *\n */\n\n\n 'use strict';\n\n var TransportFactory = require('../transport/http-transport-factory');\n var rutil = require('../util/run-util');\n\nmodule.exports = function (config) {\n var defaults = {\n /**\n * The runs object to which the variable filters apply. Defaults to null.\n * @type {runService}\n */\n runService: null\n };\n var serviceOptions = $.extend({}, defaults, config);\n\n var getURL = function () {\n return serviceOptions.runService.urlConfig.getFilterURL() + 'variables/';\n };\n\n var addAutoRestoreHeader = function (options) {\n return serviceOptions.runService.urlConfig.addAutoRestoreHeader(options);\n };\n\n var httpOptions = {\n url: getURL\n };\n if (serviceOptions.token) {\n httpOptions.headers = {\n 'Authorization': 'Bearer ' + serviceOptions.token\n };\n }\n var http = new TransportFactory(httpOptions);\n http.splitGet = rutil.splitGetFactory(httpOptions);\n\n var publicAPI = {\n\n /**\n * Get values for a variable.\n *\n * **Example**\n *\n * vs.load('sample_int')\n * .then(function(val){\n * // val contains the value of sample_int\n * });\n *\n * **Parameters**\n * @param {String} `variable` Name of variable to load.\n * @param {Object} `outputModifier` (Optional) Available fields include: `startrecord`, `endrecord`, `sort`, and `direction` (`asc` or `desc`).\n * @param {Object} `options` (Optional) Overrides for configuration options.\n */\n load: function (variable, outputModifier, options) {\n var httpOptions = $.extend(true, {}, serviceOptions, options);\n httpOptions = addAutoRestoreHeader(httpOptions);\n return http.get(outputModifier, $.extend({}, httpOptions, {\n url: getURL() + variable + '/'\n }));\n },\n\n /**\n * Returns particular variables, based on conditions specified in the `query` object.\n *\n * **Example**\n *\n * vs.query(['price', 'sales'])\n * .then(function(val) {\n * // val is an object with the values of the requested variables: val.price, val.sales\n * });\n *\n * vs.query({ include:['price', 'sales'] });\n *\n * **Parameters**\n * @param {Object|Array} `query` The names of the variables requested.\n * @param {Object} `outputModifier` (Optional) Available fields include: `startrecord`, `endrecord`, `sort`, and `direction` (`asc` or `desc`).\n * @param {Object} `options` (Optional) Overrides for configuration options.\n *\n */\n query: function (query, outputModifier, options) {\n //Query and outputModifier are both querystrings in the url; only calling them out separately here to be consistent with the other calls\n var httpOptions = $.extend(true, {}, serviceOptions, options);\n httpOptions = addAutoRestoreHeader(httpOptions);\n\n if ($.isArray(query)) {\n query = { include: query };\n }\n $.extend(query, outputModifier);\n return http.splitGet(query, httpOptions);\n },\n\n /**\n * Save values to model variables. Overwrites existing values. Note that you can only update model variables if the run is [in memory](../../../run_persistence/#runs-in-memory). (An alternate way to update model variables is to call a method from the model and make sure that the method persists the variables. See `do`, `serial`, and `parallel` in the [Run API Service](../run-api-service/) for calling methods from the model.)\n *\n * **Example**\n *\n * vs.save('price', 4);\n * vs.save({ price: 4, quantity: 5, products: [2,3,4] });\n *\n * **Parameters**\n * @param {Object|String} `variable` An object composed of the model variables and the values to save. Alternatively, a string with the name of the variable.\n * @param {Object} `val` (Optional) If passing a string for `variable`, use this argument for the value to save.\n * @param {Object} `options` (Optional) Overrides for configuration options.\n */\n save: function (variable, val, options) {\n var attrs;\n if (typeof variable === 'object') {\n attrs = variable;\n options = val;\n } else {\n (attrs = {})[variable] = val;\n }\n var httpOptions = $.extend(true, {}, serviceOptions, options);\n\n return http.patch.call(this, attrs, httpOptions);\n }\n\n // Not Available until underlying API supports PUT. Otherwise save would be PUT and merge would be PATCH\n // *\n // * Save values to the api. Merges arrays, but otherwise same as save\n // * @param {Object|String} variable Object with attributes, or string key\n // * @param {Object} val Optional if prev parameter was a string, set value here\n // * @param {Object} options Overrides for configuration options\n // *\n // * @example\n // * vs.merge({ price: 4, quantity: 5, products: [2,3,4] })\n // * vs.merge('price', 4);\n\n // merge: function (variable, val, options) {\n // var attrs;\n // if (typeof variable === 'object') {\n // attrs = variable;\n // options = val;\n // } else {\n // (attrs = {})[variable] = val;\n // }\n // var httpOptions = $.extend(true, {}, serviceOptions, options);\n\n // return http.patch.call(this, attrs, httpOptions);\n // }\n };\n $.extend(this, publicAPI);\n};\n","/**\n * ## Data API Service\n *\n * The Data API Service allows you to create, access, and manipulate data related to any of your projects. Data are organized in collections. Each collection contains a document; each element of this top-level document is a JSON object. (See additional information on the underlying [Data API](../../../rest_apis/data_api/).)\n *\n * All API calls take in an \"options\" object as the last parameter. The options can be used to extend/override the Data API Service defaults. In particular, there are three required parameters when you instantiate the Data Service:\n *\n * * `account`: Epicenter account id (**Team ID** for team projects, **User ID** for personal projects).\n * * `project`: Epicenter project id.\n * * `root`: The the name of the collection. If you have multiple collections within each of your projects, you can also pass the collection name as an option for each call.\n *\n * var ds = new F.service.Data({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * root: 'survey-responses',\n * server: { host: 'api.forio.com' }\n * });\n * ds.saveAs('user1',\n * { 'question1': 2, 'question2': 10,\n * 'question3': false, 'question4': 'sometimes' } );\n * ds.saveAs('user2',\n * { 'question1': 3, 'question2': 8,\n * 'question3': true, 'question4': 'always' } );\n * ds.query('',{ 'question2': { '$gt': 9} });\n *\n * Note that in addition to the `account`, `project`, and `root`, the Data Service parameters optionally include a `server` object, whose `host` field contains the URI of the Forio server. This is automatically set, but you can pass it explicitly if desired. It is most commonly used for clarity when you are [hosting an Epicenter project on your own server](../../../how_to/self_hosting/).\n */\n\n'use strict';\n\nvar ConfigService = require('./configuration-service');\nvar qutil = require('../util/query-util');\nvar TransportFactory = require('../transport/http-transport-factory');\nvar SessionManager = require('../store/session-manager');\n\nmodule.exports = function (config) {\n var defaults = {\n /**\n * Name of collection. Defaults to `/`, that is, the root level of your project at `forio.com/app/your-account-id/your-project-id/`. Required.\n * @type {String}\n */\n root: '/',\n\n /**\n * The account id. In the Epicenter UI, this is the **Team ID** (for team projects) or **User ID** (for personal projects). Defaults to empty string. If left undefined, taken from the URL.\n * @type {String}\n */\n account: undefined,\n\n /**\n * The project id. Defaults to empty string. If left undefined, taken from the URL.\n * @type {String}\n */\n project: undefined,\n\n /**\n * For operations that require authentication, pass in the user access token (defaults to empty string). If the user is already logged in to Epicenter, the user access token is already set in a cookie and automatically loaded from there. (See [more background on access tokens](../../../project_access/)).\n * @see [Authentication API Service](../auth-api-service/) for getting tokens.\n * @type {String}\n */\n token: undefined,\n\n //Options to pass on to the underlying transport layer\n transport: {}\n };\n this.sessionManager = new SessionManager();\n var serviceOptions = this.sessionManager.getMergedOptions(defaults, config);\n\n var urlConfig = new ConfigService(serviceOptions).get('server');\n if (serviceOptions.account) {\n urlConfig.accountPath = serviceOptions.account;\n }\n if (serviceOptions.project) {\n urlConfig.projectPath = serviceOptions.project;\n }\n\n var getURL = function (key, root) {\n if (!root) {\n root = serviceOptions.root;\n }\n var url = urlConfig.getAPIPath('data') + qutil.addTrailingSlash(root);\n if (key) {\n url+= qutil.addTrailingSlash(key);\n }\n return url;\n };\n\n var httpOptions = $.extend(true, {}, serviceOptions.transport, {\n url: getURL\n });\n if (serviceOptions.token) {\n httpOptions.headers = {\n 'Authorization': 'Bearer ' + serviceOptions.token\n };\n }\n var http = new TransportFactory(httpOptions);\n\n var publicAPI = {\n\n /**\n * Search for data within a collection.\n *\n * Searching using comparison or logical operators (as opposed to exact matches) requires MongoDB syntax. See the underlying [Data API](../../../rest_apis/data_api/#searching) for additional details.\n *\n * **Examples**\n *\n * // request all data associated with document 'user1'\n * ds.query('user1');\n *\n * // exact matching:\n * // request all documents in collection where 'question2' is 9\n * ds.query('', { 'question2': 9});\n *\n * // comparison operators:\n * // request all documents in collection\n * // where 'question2' is greater than 9\n * ds.query('', { 'question2': { '$gt': 9} });\n *\n * // logical operators:\n * // request all documents in collection\n * // where 'question2' is less than 10, and 'question3' is false\n * ds.query('', { '$and': [ { 'question2': { '$lt':10} }, { 'question3': false }] });\n *\n * // regular expresssions: use any Perl-compatible regular expressions\n * // request all documents in collection\n * // where 'question5' contains the string '.*day'\n * ds.query('', { 'question5': { '$regex': '.*day' } });\n *\n * **Parameters**\n * @param {String} `key` The name of the document to search. Pass the empty string ('') to search the entire collection.\n * @param {Object} `query` The query object. For exact matching, this object contains the field name and field value to match. For matching based on comparison, this object contains the field name and the comparison expression. For matching based on logical operators, this object contains an expression using MongoDB syntax. See the underlying [Data API](../../../rest_apis/data_api/#searching) for additional examples.\n * @param {Object} `outputModifier` (Optional) Available fields include: `startrecord`, `endrecord`, `sort`, and `direction` (`asc` or `desc`).\n * @param {Object} `options` (Optional) Overrides for configuration options.\n *\n */\n query: function (key, query, outputModifier, options) {\n var params = $.extend(true, { q: query }, outputModifier);\n var httpOptions = $.extend(true, {}, serviceOptions, options);\n httpOptions.url = getURL(key, httpOptions.root);\n return http.get(params, httpOptions);\n },\n\n /**\n * Save data to an anonymous document within the collection.\n *\n * (Documents are top-level elements within a collection. Collections must be unique within this account (team or personal account) and project and are set with the `root` field in the `option` parameter. See the underlying [Data API](../../../rest_apis/data_api/) for additional background.)\n *\n * **Example**\n *\n * ds.save('question1', 'yes');\n * ds.save({question1:'yes', question2: 32 });\n * ds.save({ name:'John', className: 'CS101' }, { root: 'students' });\n *\n * **Parameters**\n *\n * @param {String|Object} `key` If `key` is a string, it is the id of the element to save (create) in this document. If `key` is an object, the object is the data to save (create) in this document. In both cases, the id for the document is generated automatically.\n * @param {Object} `value` (Optional) The data to save. If `key` is a string, this is the value to save. If `key` is an object, the value(s) to save are already part of `key` and this argument is not required.\n * @param {Object} `options` (Optional) Overrides for configuration options.\n */\n save: function (key, value, options) {\n var attrs;\n if (typeof key === 'object') {\n attrs = key;\n options = value;\n } else {\n (attrs = {})[key] = value;\n }\n var httpOptions = $.extend(true, {}, serviceOptions, options);\n httpOptions.url = getURL('', httpOptions.root);\n\n return http.post(attrs, httpOptions);\n },\n\n /**\n * Save data to a named document or element within the collection. The `root` of the collection must be specified separately in configuration options, either as part of the call or as part of the initialization of ds.\n *\n * (Documents are top-level elements within a collection. Collections must be unique within this account (team or personal account) and project and are set with the `root` field in the `option` parameter. See the underlying [Data API](../../../rest_apis/data_api/) for additional background.)\n *\n * **Example**\n *\n * ds.saveAs('user1',\n * { 'question1': 2, 'question2': 10,\n * 'question3': false, 'question4': 'sometimes' } );\n * ds.saveAs('student1',\n * { firstName: 'john', lastName: 'smith' },\n * { root: 'students' });\n * ds.saveAs('mgmt100/groupB',\n * { scenarioYear: '2015' },\n * { root: 'myclasses' });\n *\n * **Parameters**\n *\n * @param {String} `key` Id of the document.\n * @param {Object} `value` (Optional) The data to save, in key:value pairs.\n * @param {Object} `options` (Optional) Overrides for configuration options.\n */\n saveAs: function (key, value, options) {\n var httpOptions = $.extend(true, {}, serviceOptions, options);\n httpOptions.url = getURL(key, httpOptions.root);\n\n return http.put(value, httpOptions);\n },\n\n /**\n * Get data for a specific document or field.\n *\n * **Example**\n *\n * ds.load('user1');\n * ds.load('user1/question3');\n *\n * **Parameters**\n * @param {String|Object} `key` The id of the data to return. Can be the id of a document, or a path to data within that document.\n * @param {Object} `outputModifier` (Optional) Available fields include: `startrecord`, `endrecord`, `sort`, and `direction` (`asc` or `desc`).\n * @param {Object} `options` Overrides for configuration options.\n */\n load: function (key, outputModifier, options) {\n var httpOptions = $.extend(true, {}, serviceOptions, options);\n httpOptions.url = getURL(key, httpOptions.root);\n return http.get(outputModifier, httpOptions);\n },\n\n /**\n * Removes data from collection. Only documents (top-level elements in each collection) can be deleted.\n *\n * **Example**\n *\n * ds.remove('user1');\n *\n *\n * **Parameters**\n *\n * @param {String|Array} `keys` The id of the document to remove from this collection, or an array of such ids.\n * @param {Object} `options` (Optional) Overrides for configuration options.\n */\n remove: function (keys, options) {\n var httpOptions = $.extend(true, {}, serviceOptions, options);\n var params;\n if ($.isArray(keys)) {\n params = { id: keys };\n } else {\n params = '';\n httpOptions.url = getURL(keys, httpOptions.root);\n }\n return http.delete(params, httpOptions);\n }\n\n // Epicenter doesn't allow nuking collections\n // /**\n // * Removes collection being referenced\n // * @return null\n // */\n // destroy: function (options) {\n // return this.remove('', options);\n // }\n };\n\n $.extend(this, publicAPI);\n};\n","/**\n *\n * ## Authentication API Service\n *\n * The Authentication API Service provides a method for logging in, which creates and returns a user access token.\n *\n * User access tokens are required for each call to Epicenter. (See [Project Access](../../../project_access/) for more information.)\n *\n * If you need additional functionality -- such as tracking session information, easily retrieving the user token, or getting the groups to which an end user belongs -- consider using the [Authorization Manager](../auth-manager/) instead.\n *\n * var auth = new F.service.Auth();\n * auth.login({ userName: 'jsmith@acmesimulations.com',\n * password: 'passw0rd' });\n */\n\n'use strict';\n\nvar ConfigService = require('./configuration-service');\nvar TransportFactory = require('../transport/http-transport-factory');\n\nmodule.exports = function (config) {\n var defaults = {\n /**\n * Email or username to use for logging in. Defaults to empty string.\n * @type {String}\n */\n userName: '',\n\n /**\n * Password for specified `userName`. Defaults to empty string.\n * @type {String}\n */\n password: '',\n\n /**\n * The account id for this `userName`. In the Epicenter UI, this is the **Team ID** (for team projects) or the **User ID** (for personal projects). Required if the `userName` is for an [end user](../../../glossary/#users). Defaults to empty string.\n * @type {String}\n */\n account: '',\n\n /**\n * Options to pass on to the underlying transport layer. All jquery.ajax options at http://api.jquery.com/jQuery.ajax/ are available. Defaults to empty object.\n * @type {Object}\n */\n transport: {}\n };\n var serviceOptions = $.extend({}, defaults, config);\n var urlConfig = new ConfigService(serviceOptions).get('server');\n\n var transportOptions = $.extend(true, {}, serviceOptions.transport, {\n url: urlConfig.getAPIPath('authentication')\n });\n var http = new TransportFactory(transportOptions);\n\n var publicAPI = {\n\n /**\n * Logs user in, returning the user access token.\n *\n * If no `userName` or `password` were provided in the initial configuration options, they are required in the `options` here. If no `account` was provided in the initial configuration options and the `userName` is for an [end user](../../../glossary/#users), the `account` is required as well.\n *\n * **Example**\n *\n * auth.login({\n * userName: 'jsmith',\n * password: 'passw0rd',\n * account: 'acme-simulations' })\n * .then(function (token) {\n * console.log(\"user access token is: \", token.access_token);\n * });\n *\n * **Parameters**\n * @param {Object} `options` (Optional) Overrides for configuration options.\n */\n login: function (options) {\n var httpOptions = $.extend(true, { success: $.noop }, serviceOptions, options);\n if (!httpOptions.userName || !httpOptions.password) {\n var resp = { status: 401, statusMessage: 'No username or password specified.' };\n if (options.error) {\n options.error.call(this, resp);\n }\n\n return $.Deferred().reject(resp).promise();\n }\n\n var postParams = {\n userName: httpOptions.userName,\n password: httpOptions.password,\n };\n if (httpOptions.account) {\n //pass in null for account under options if you don't want it to be sent\n postParams.account = httpOptions.account;\n }\n\n return http.post(postParams, httpOptions);\n },\n\n // (replace with /* */ comment block, to make visible in docs, once this is more than a noop)\n //\n // Logs user out from specified accounts.\n //\n // Epicenter logout is not implemented yet, so for now this is a dummy promise that gets automatically resolved.\n //\n // **Example**\n //\n // auth.logout();\n //\n // **Parameters**\n // @param {Object} `options` (Optional) Overrides for configuration options.\n //\n logout: function (options) {\n var dtd = $.Deferred();\n dtd.resolve();\n return dtd.promise();\n }\n };\n\n $.extend(this, publicAPI);\n};\n","'use strict';\n/**\n * ## State API Adapter\n *\n * The State API Adapter allows you to replay or clone runs. It brings existing, persisted run data from the database back into memory, using the same run id (`replay`) or a new run id (`clone`). Runs must be in memory in order for you to update variables or call operations on them.\n *\n * Specifically, the State API Adapter works by \"re-running\" the run (user interactions) from the creation of the run up to the time it was last persisted in the database. This process uses the current version of the run's model. Therefore, if the model has changed since the original run was created, the retrieved run will use the new model — and may end up having different values or behavior as a result. Use with care!\n *\n * To use the State API Adapter, instantiate it and then call its methods:\n *\n * var sa = new F.service.State();\n * sa.replay({runId: '1842bb5c-83ad-4ba8-a955-bd13cc2fdb4f'});\n *\n * The constructor takes an optional `options` parameter in which you can specify the `account` and `project` if they are not already available in the current context.\n *\n */\n\nvar ConfigService = require('./configuration-service');\nvar TransportFactory = require('../transport/http-transport-factory');\nvar _pick = require('../util/object-util')._pick;\nvar SessionManager = require('../store/session-manager');\nvar apiEndpoint = 'model/state';\n\nmodule.exports = function (config) {\n\n var defaults = {\n\n };\n\n this.sessionManager = new SessionManager();\n var serviceOptions = this.sessionManager.getMergedOptions(defaults, config);\n var urlConfig = new ConfigService(serviceOptions).get('server');\n\n var transportOptions = $.extend(true, {}, serviceOptions.transport, {\n url: urlConfig.getAPIPath(apiEndpoint)\n });\n\n if (serviceOptions.token) {\n transportOptions.headers = {\n 'Authorization': 'Bearer ' + serviceOptions.token\n };\n }\n\n var http = new TransportFactory(transportOptions);\n var parseRunIdOrError = function (params) {\n if ($.isPlainObject(params) && params.runId) {\n return params.runId;\n } else {\n throw new Error('Please pass in a run id');\n }\n };\n\n var publicAPI = {\n /**\n * Replay a run. After this call, the run, with its original run id, is now available [in memory](../../../run_persistence/#runs-in-memory). (It continues to be persisted into the Epicenter database at regular intervals.)\n *\n * **Example**\n *\n * var sa = new F.service.State();\n * sa.replay({runId: '1842bb5c-83ad-4ba8-a955-bd13cc2fdb4f', stopBefore: 'calculateScore'});\n *\n * **Parameters**\n * @param {object} `params` Parameters object.\n * @param {string} `params.runId` The id of the run to bring back to memory.\n * @param {string} `params.stopBefore` (Optional) The run is advanced only up to the first occurrence of this method.\n * @param {array} `params.exclude` (Optional) Array of methods to exclude when advancing the run.\n * @param {object} `options` (Optional) Overrides for configuration options.\n */\n replay: function (params, options) {\n var runId = parseRunIdOrError(params);\n\n var replayOptions = $.extend(true, {},\n serviceOptions,\n options,\n { url: urlConfig.getAPIPath(apiEndpoint) + runId }\n );\n\n params = $.extend(true, { action: 'replay' }, _pick(params, ['stopBefore', 'exclude']));\n\n return http.post(params, replayOptions);\n },\n\n /**\n * Clone a given run and return a new run in the same state as the given run.\n *\n * The new run id is now available [in memory](../../../run_persistence/#runs-in-memory). The new run includes a copy of all of the data from the original run, EXCEPT:\n *\n * * The `saved` field in the new run record is not copied from the original run record. It defaults to `false`.\n * * The `initialized` field in the new run record is not copied from the original run record. It defaults to `false` but may change to `true` as the new run is advanced. For example, if there has been a call to the `step` function (for Vensim models), the `initialized` field is set to `true`.\n * * The `created` field in the new run record is the date and time at which the clone was created (not the time that the original run was created.)\n *\n * The original run remains only [in the database](../../../run_persistence/#runs-in-db).\n *\n * **Example**\n *\n * var sa = new F.service.State();\n * sa.clone({runId: '1842bb5c-83ad-4ba8-a955-bd13cc2fdb4f', stopBefore: 'calculateScore', exclude: ['interimCalculation'] });\n *\n * **Parameters**\n * @param {object} `params` Parameters object.\n * @param {string} `params.runId` The id of the run to clone from memory.\n * @param {string} `params.stopBefore` (Optional) The newly cloned run is advanced only up to the first occurrence of this method.\n * @param {array} `params.exclude` (Optional) Array of methods to exclude when advancing the newly cloned run.\n * @param {object} `options` (Optional) Overrides for configuration options.\n */\n clone: function (params, options) {\n var runId = parseRunIdOrError(params);\n\n var replayOptions = $.extend(true, {},\n serviceOptions,\n options,\n { url: urlConfig.getAPIPath(apiEndpoint) + runId }\n );\n\n params = $.extend(true, { action: 'clone' }, _pick(params, ['stopBefore', 'exclude']));\n\n return http.post(params, replayOptions);\n }\n };\n\n $.extend(this, publicAPI);\n};\n","/**\n * ## World API Adapter\n *\n * A [run](../../../glossary/#run) is a collection of end user interactions with a project and its model -- including setting variables, making decisions, and calling operations. For building multiplayer simulations you typically want multiple end users to share the same set of interactions, and work within a common state. Epicenter allows you to create \"worlds\" to handle such cases. Only [team projects](../../../glossary/#team) can be multiplayer.\n *\n * The World API Adapter allows you to create, access, and manipulate multiplayer worlds within your Epicenter project. You can use this to add and remove end users from the world, and to create, access, and remove their runs. Because of this, typically the World Adapter is used for facilitator pages in your project. (The related [World Manager](../world-manager/) provides an easy way to access runs and worlds for particular end users, so is typically used in pages that end users will interact with.)\n *\n * As with all the other [API Adapters](../../), all methods take in an \"options\" object as the last parameter. The options can be used to extend/override the World API Service defaults.\n *\n * To use the World Adapter, instantiate it and then access the methods provided. Instantiating requires the account id (**Team ID** in the Epicenter user interface), project id (**Project ID**), and group (**Group Name**).\n *\n * var wa = new F.service.World({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * group: 'team1' });\n * wa.create()\n * .then(function(world) {\n * // call methods, e.g. wa.addUsers()\n * });\n */\n\n'use strict';\n\nvar ConfigService = require('./configuration-service');\n// var qutil = require('../util/query-util');\nvar TransportFactory = require('../transport/http-transport-factory');\nvar SessionManager = require('../store/session-manager');\nvar _pick = require('../util/object-util')._pick;\n\nvar apiBase = 'multiplayer/';\nvar assignmentEndpoint = apiBase + 'assign';\nvar apiEndpoint = apiBase + 'world';\nvar projectEndpoint = apiBase + 'project';\n\nmodule.exports = function (config) {\n var defaults = {\n /**\n * For projects that require authentication, pass in the user access token (defaults to empty string). If the user is already logged in to Epicenter, the user access token is already set in a cookie and automatically loaded from there. (See [more background on access tokens](../../../project_access/)).\n * @see [Authentication API Service](../auth-api-service/) for getting tokens.\n * @type {String}\n */\n token: undefined,\n\n /**\n * The project id. If left undefined, taken from the URL.\n * @type {String}\n */\n project: undefined,\n\n /**\n * The account id. In the Epicenter UI, this is the **Team ID** (for team projects). If left undefined, taken from the URL.\n * @type {String}\n */\n account: undefined,\n\n /**\n * The group name. Defaults to undefined.\n * @type {String}\n */\n group: undefined,\n\n /**\n * The model file to use to create runs in this world. Defaults to undefined.\n * @type {String}\n */\n model: undefined,\n\n /**\n * Criteria by which to filter world. Currently only supports world-ids as filters.\n * @type {String}\n */\n filter: '',\n\n /**\n * Convenience alias for filter\n * @type {String}\n */\n id: '',\n\n /**\n * Options to pass on to the underlying transport layer. All jquery.ajax options at http://api.jquery.com/jQuery.ajax/ are available. Defaults to empty object.\n * @type {Object}\n */\n transport: {},\n\n /**\n * Called when the call completes successfully. Defaults to `$.noop`.\n * @type {function}\n */\n success: $.noop,\n\n /**\n * Called when the call fails. Defaults to `$.noop`.\n * @type {function}\n */\n error: $.noop\n };\n\n this.sessionManager = new SessionManager();\n var serviceOptions = this.sessionManager.getMergedOptions(defaults, config);\n if (serviceOptions.id) {\n serviceOptions.filter = serviceOptions.id;\n }\n\n var urlConfig = new ConfigService(serviceOptions).get('server');\n\n if (!serviceOptions.account) {\n serviceOptions.account = urlConfig.accountPath;\n }\n\n if (!serviceOptions.project) {\n serviceOptions.project = urlConfig.projectPath;\n }\n\n var transportOptions = $.extend(true, {}, serviceOptions.transport, {\n url: urlConfig.getAPIPath(apiEndpoint)\n });\n\n if (serviceOptions.token) {\n transportOptions.headers = {\n 'Authorization': 'Bearer ' + serviceOptions.token\n };\n }\n\n var http = new TransportFactory(transportOptions);\n\n var setIdFilterOrThrowError = function (options) {\n if (options.id) {\n serviceOptions.filter = options.id;\n }\n if (options.filter) {\n serviceOptions.filter = options.filter;\n }\n if (!serviceOptions.filter) {\n throw new Error('No world id specified to apply operations against. This could happen if the user is not assigned to a world and is trying to work with runs from that world.');\n }\n };\n\n var validateModelOrThrowError = function (options) {\n if (!options.model) {\n throw new Error('No model specified to get the current run');\n }\n };\n\n var publicAPI = {\n\n /**\n * Creates a new World.\n *\n * Using this method is rare. It is more common to create worlds automatically while you `autoAssign()` end users to worlds. (In this case, configuration data for the world, such as the roles, are read from the project-level world configuration information, for example by `getProjectSettings()`.)\n *\n * **Example**\n *\n * var wa = new F.service.World({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * group: 'team1' });\n * wa.create({\n * roles: ['VP Marketing', 'VP Sales', 'VP Engineering']\n * });\n *\n * **Parameters**\n * @param {object} `params` Parameters to create the world.\n * @param {string} `params.group` (Optional) The **Group Name** to create this world under. Only end users in this group are eligible to join the world. Optional here; required when instantiating the service (`new F.service.World()`).\n * @param {object} `params.roles` (Optional) The list of roles (strings) for this world. Some worlds have specific roles that **must** be filled by end users. Listing the roles allows you to autoassign users to worlds and ensure that all roles are filled in each world.\n * @param {object} `params.optionalRoles` (Optional) The list of optional roles (strings) for this world. Some worlds have specific roles that **may** be filled by end users. Listing the optional roles as part of the world object allows you to autoassign users to worlds and ensure that all roles are filled in each world.\n * @param {integer} `params.minUsers` (Optional) The minimum number of users for the world. Including this number allows you to autoassign end users to worlds and ensure that the correct number of users are in each world.\n * @param {object} `options` (Optional) Options object to override global options.\n *\n */\n create: function (params, options) {\n var createOptions = $.extend(true, {}, serviceOptions, options, { url: urlConfig.getAPIPath(apiEndpoint) });\n var worldApiParams = ['scope', 'files', 'roles', 'optionalRoles', 'minUsers', 'group', 'name'];\n var validParams = _pick(serviceOptions, ['account', 'project', 'group']);\n // whitelist the fields that we actually can send to the api\n params = _pick(params, worldApiParams);\n\n // account and project go in the body, not in the url\n params = $.extend({}, validParams, params);\n\n var oldSuccess = createOptions.success;\n createOptions.success = function (response) {\n serviceOptions.filter = response.id; //all future chained calls to operate on this id\n return oldSuccess.apply(this, arguments);\n };\n\n return http.post(params, createOptions);\n },\n\n /**\n * Updates a World, for example to replace the roles in the world.\n *\n * Typically, you complete world configuration at the project level, rather than at the world level. For example, each world in your project probably has the same roles for end users. And your project is probably either configured so that all end users share the same world (and run), or smaller sets of end users share worlds — but not both. However, this method is available if you need to update the configuration of a particular world.\n *\n * **Example**\n *\n * var wa = new F.service.World({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * group: 'team1' });\n * wa.create()\n * .then(function(world) {\n * wa.update({ roles: ['VP Marketing', 'VP Sales', 'VP Engineering'] });\n * });\n *\n * **Parameters**\n * @param {object} `params` Parameters to update the world.\n * @param {string} `params.name` A string identifier for the linked end users, for example, \"name\": \"Our Team\".\n * @param {object} `params.roles` (Optional) The list of roles (strings) for this world. Some worlds have specific roles that **must** be filled by end users. Listing the roles allows you to autoassign users to worlds and ensure that all roles are filled in each world.\n * @param {object} `params.optionalRoles` (Optional) The list of optional roles (strings) for this world. Some worlds have specific roles that **may** be filled by end users. Listing the optional roles as part of the world object allows you to autoassign users to worlds and ensure that all roles are filled in each world.\n * @param {integer} `params.minUsers` (Optional) The minimum number of users for the world. Including this number allows you to autoassign end users to worlds and ensure that the correct number of users are in each world.\n * @param {object} `options` (Optional) Options object to override global options.\n *\n */\n update: function (params, options) {\n var whitelist = ['roles', 'optionalRoles', 'minUsers'];\n options = options || {};\n setIdFilterOrThrowError(options);\n\n var updateOptions = $.extend(true, {},\n serviceOptions,\n options,\n { url: urlConfig.getAPIPath(apiEndpoint) + serviceOptions.filter }\n );\n\n params = _pick(params || {}, whitelist);\n\n return http.patch(params, updateOptions);\n },\n\n /**\n * Deletes an existing world.\n *\n * This function optionally takes one argument. If the argument is a string, it is the id of the world to delete. If the argument is an object, it is the override for global options.\n *\n * **Example**\n *\n * var wa = new F.service.World({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * group: 'team1' });\n * wa.create()\n * .then(function(world) {\n * wa.delete();\n * });\n *\n * **Parameters**\n * @param {String|Object} `options` (Optional) The id of the world to delete, or options object to override global options.\n *\n */\n delete: function (options) {\n options = (options && (typeof options === 'string')) ? { filter: options } : {};\n setIdFilterOrThrowError(options);\n\n var deleteOptions = $.extend(true, {},\n serviceOptions,\n options,\n { url: urlConfig.getAPIPath(apiEndpoint) + serviceOptions.filter }\n );\n\n return http.delete(null, deleteOptions);\n },\n\n /**\n * Updates the configuration for the current instance of the World API Adapter (including all subsequent function calls, until the configuration is updated again).\n *\n * **Example**\n *\n * var wa = new F.service.World({...}).updateConfig({ filter: '123' }).addUser({ userId: '123' });\n *\n * **Parameters**\n * @param {object} `config` The configuration object to use in updating existing configuration.\n */\n updateConfig: function (config) {\n $.extend(serviceOptions, config);\n\n return this;\n },\n\n /**\n * Lists all worlds for a given account, project, and group. All three are required, and if not specified as parameters, are read from the service.\n *\n * **Example**\n *\n * var wa = new F.service.World({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * group: 'team1' });\n * wa.create()\n * .then(function(world) {\n * // lists all worlds in group \"team1\"\n * wa.list();\n *\n * // lists all worlds in group \"other-group-name\"\n * wa.list({ group: 'other-group-name' });\n * });\n *\n * **Parameters**\n * @param {object} `options` (Optional) Options object to override global options.\n *\n */\n list: function (options) {\n options = options || {};\n\n var getOptions = $.extend(true, {},\n serviceOptions,\n options,\n { url: urlConfig.getAPIPath(apiEndpoint) }\n );\n\n var filters = _pick(getOptions, ['account', 'project', 'group']);\n\n return http.get(filters, getOptions);\n },\n\n /**\n * Gets all worlds that an end user belongs to for a given account (team), project, and group.\n *\n * **Example**\n *\n * var wa = new F.service.World({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * group: 'team1' });\n * wa.create()\n * .then(function(world) {\n * wa.getWorldsForUser('b1c19dda-2d2e-4777-ad5d-3929f17e86d3')\n * });\n *\n * ** Parameters **\n * @param {string} `userId` The `userId` of the user whose worlds are being retrieved.\n * @param {object} `options` (Optional) Options object to override global options.\n */\n getWorldsForUser: function (userId, options) {\n options = options || {};\n\n var getOptions = $.extend(true, {},\n serviceOptions,\n options,\n { url: urlConfig.getAPIPath(apiEndpoint) }\n );\n\n var filters = $.extend(\n _pick(getOptions, ['account', 'project', 'group']),\n { userId: userId }\n );\n\n return http.get(filters, getOptions);\n },\n\n /**\n * Load information for a specific world. All further calls to the world service will use the id provided.\n *\n * **Parameters**\n * @param {String} `worldId` The id of the world to load.\n * @param {Object} `options` (Optional) Options object to override global options.\n */\n load: function (worldId, options) {\n if (worldId) {\n serviceOptions.filter = worldId;\n }\n if (!serviceOptions.filter) {\n throw new Error('Please provide a worldid to load');\n }\n var httpOptions = $.extend(true, {}, serviceOptions, options, { url: urlConfig.getAPIPath(apiEndpoint) + serviceOptions.filter + '/' });\n return http.get('', httpOptions);\n },\n\n /**\n * Adds an end user or list of end users to a given world. The end user must be a member of the `group` that is associated with this world.\n *\n * **Example**\n *\n * var wa = new F.service.World({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * group: 'team1' });\n * wa.create()\n * .then(function(world) {\n * // add one user\n * wa.addUsers('b1c19dda-2d2e-4777-ad5d-3929f17e86d3');\n * wa.addUsers(['b1c19dda-2d2e-4777-ad5d-3929f17e86d3']);\n * wa.addUsers({ userId: 'b1c19dda-2d2e-4777-ad5d-3929f17e86d3', role: 'VP Sales' });\n *\n * // add several users\n * wa.addUsers([\n * { userId: 'a6fe0c1e-f4b8-4f01-9f5f-01ccf4c2ed44',\n * role: 'VP Marketing' },\n * { userId: '8f2604cf-96cd-449f-82fa-e331530734ee',\n * role: 'VP Engineering' }\n * ]);\n *\n * // add one user to a specific world\n * wa.addUsers('b1c19dda-2d2e-4777-ad5d-3929f17e86d3', world.id);\n * wa.addUsers('b1c19dda-2d2e-4777-ad5d-3929f17e86d3', { filter: world.id });\n * });\n *\n * ** Parameters **\n * @param {string|object|array} `users` User id, array of user ids, object, or array of objects of the users to add to this world.\n * @param {string} `users.role` The `role` the user should have in the world. It is up to the caller to ensure, if needed, that the `role` passed in is one of the `roles` or `optionalRoles` of this world.\n * @param {string} `worldId` The world to which the users should be added. If not specified, the filter parameter of the `options` object is used.\n * @param {object} `options` (Optional) Options object to override global options.\n */\n addUsers: function (users, worldId, options) {\n\n if (!users) {\n throw new Error('Please provide a list of users to add to the world');\n }\n\n // normalize the list of users to an array of user objects\n users = $.map([].concat(users), function (u) {\n var isObject = $.isPlainObject(u);\n\n if (typeof u !== 'string' && !isObject) {\n throw new Error('Some of the users in the list are not in the valid format: ' + u);\n }\n\n return isObject ? u : { userId: u };\n });\n\n // check if options were passed as the second parameter\n if ($.isPlainObject(worldId) && !options) {\n options = worldId;\n worldId = null;\n }\n\n options = options || {};\n\n // we must have options by now\n if (typeof worldId === 'string') {\n options.filter = worldId;\n }\n\n setIdFilterOrThrowError(options);\n\n var updateOptions = $.extend(true, {},\n serviceOptions,\n options,\n { url: urlConfig.getAPIPath(apiEndpoint) + serviceOptions.filter + '/users' }\n );\n\n return http.post(users, updateOptions);\n },\n\n /**\n * Updates the role of an end user in a given world. (You can only update one end user at a time.)\n *\n * **Example**\n *\n * var wa = new F.service.World({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * group: 'team1' });\n *\n * wa.create().then(function(world) {\n * wa.addUsers('b1c19dda-2d2e-4777-ad5d-3929f17e86d3');\n * wa.updateUser({ userId: 'b1c19dda-2d2e-4777-ad5d-3929f17e86d3', role: 'leader' });\n * });\n *\n * **Parameters**\n * @param {object} `user` User object with `userId` and the new `role`.\n * @param {object} `options` (Optional) Options object to override global options.\n *\n */\n updateUser: function (user, options) {\n options = options || {};\n\n if (!user || !user.userId) {\n throw new Error('You need to pass a userId to update from the world');\n }\n\n setIdFilterOrThrowError(options);\n\n var patchOptions = $.extend(true, {},\n serviceOptions,\n options,\n { url: urlConfig.getAPIPath(apiEndpoint) + serviceOptions.filter + '/users/' + user.userId }\n );\n\n return http.patch(_pick(user, 'role'), patchOptions);\n },\n\n /**\n * Removes an end user from a given world.\n *\n * **Example**\n *\n * var wa = new F.service.World({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * group: 'team1' });\n * wa.create()\n * .then(function(world) {\n * wa.addUsers(['a6fe0c1e-f4b8-4f01-9f5f-01ccf4c2ed44', '8f2604cf-96cd-449f-82fa-e331530734ee']);\n * wa.removeUser('a6fe0c1e-f4b8-4f01-9f5f-01ccf4c2ed44');\n * wa.removeUser({ userId: '8f2604cf-96cd-449f-82fa-e331530734ee' });\n * });\n *\n * ** Parameters **\n * @param {object|string} `user` The `userId` of the user to remove from the world, or an object containing the `userId` field.\n * @param {object} `options` (Optional) Options object to override global options.\n */\n removeUser: function (user, options) {\n options = options || {};\n\n if (typeof user === 'string') {\n user = { userId: user };\n }\n\n if (!user.userId) {\n throw new Error('You need to pass a userId to remove from the world');\n }\n\n setIdFilterOrThrowError(options);\n\n var getOptions = $.extend(true, {},\n serviceOptions,\n options,\n { url: urlConfig.getAPIPath(apiEndpoint) + serviceOptions.filter + '/users/' + user.userId }\n );\n\n return http.delete(null, getOptions);\n },\n\n /**\n * Gets the run id of current run for the given world. If the world does not have a run, creates a new one and returns the run id.\n *\n * Remember that a [run](../../glossary/#run) is a collection of interactions with a project and its model. In the case of multiplayer projects, the run is shared by all end users in the world.\n *\n * **Example**\n *\n * var wa = new F.service.World({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * group: 'team1' });\n * wa.create()\n * .then(function(world) {\n * wa.getCurrentRunId({ model: 'model.py' });\n * });\n *\n * ** Parameters **\n * @param {object} `options` (Optional) Options object to override global options.\n * @param {object} `options.model` The model file to use to create a run if needed.\n */\n getCurrentRunId: function (options) {\n options = options || {};\n\n setIdFilterOrThrowError(options);\n\n var getOptions = $.extend(true, {},\n serviceOptions,\n options,\n { url: urlConfig.getAPIPath(apiEndpoint) + serviceOptions.filter + '/run' }\n );\n\n validateModelOrThrowError(getOptions);\n return http.post(_pick(getOptions, 'model'), getOptions);\n },\n\n /**\n * Gets the current (most recent) world for the given end user in the given group. Brings this most recent world into memory if needed.\n *\n * **Example**\n *\n * var wa = new F.service.World({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * group: 'team1' });\n * wa.getCurrentWorldForUser('8f2604cf-96cd-449f-82fa-e331530734ee')\n * .then(function(world) {\n * // use data from world\n * });\n *\n * ** Parameters **\n * @param {string} `userId` The `userId` of the user whose current (most recent) world is being retrieved.\n * @param {string} `groupName` (Optional) The name of the group. If not provided, defaults to the group used to create the service.\n */\n getCurrentWorldForUser: function (userId, groupName) {\n var dtd = $.Deferred();\n var me = this;\n this.getWorldsForUser(userId, { group: groupName })\n .then(function (worlds) {\n // assume the most recent world as the 'active' world\n worlds.sort(function (a, b) { return new Date(b.lastModified) - new Date(a.lastModified); });\n var currentWorld = worlds[0];\n\n if (currentWorld) {\n serviceOptions.filter = currentWorld.id;\n }\n\n dtd.resolve(currentWorld, me);\n })\n .fail(dtd.reject);\n\n return dtd.promise();\n },\n\n /**\n * Deletes the current run from the world.\n *\n * (Note that the world id remains part of the run record, indicating that the run was formerly an active run for the world.)\n *\n * **Example**\n *\n * var wa = new F.service.World({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * group: 'team1' });\n *\n * wa.deleteRun('sample-world-id');\n *\n * **Parameters**\n * @param {string} `worldId` The `worldId` of the world from which the current run is being deleted.\n * @param {object} `options` (Optional) Options object to override global options.\n */\n deleteRun: function (worldId, options) {\n options = options || {};\n\n if (worldId) {\n options.filter = worldId;\n }\n\n setIdFilterOrThrowError(options);\n\n var deleteOptions = $.extend(true, {},\n serviceOptions,\n options,\n { url: urlConfig.getAPIPath(apiEndpoint) + serviceOptions.filter + '/run' }\n );\n\n return http.delete(null, deleteOptions);\n },\n\n /**\n * Creates a new run for the world.\n *\n * **Example**\n *\n * var wa = new F.service.World({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * group: 'team1' });\n *\n * wa.getCurrentWorldForUser('8f2604cf-96cd-449f-82fa-e331530734ee')\n * .then(function (world) {\n * wa.newRunForWorld(world.id);\n * });\n *\n * **Parameters**\n * @param {string} `worldId` worldId in which we create the new run.\n * @param {object} `options` (Optional) Options object to override global options.\n * @param {object} `options.model` The model file to use to create a run if needed.\n */\n newRunForWorld: function (worldId, options) {\n var currentRunOptions = $.extend(true, {},\n options,\n { filter: worldId || serviceOptions.filter }\n );\n var _this = this;\n\n validateModelOrThrowError(currentRunOptions);\n\n return this.deleteRun(worldId, options)\n .then(function () {\n return _this.getCurrentRunId(currentRunOptions);\n });\n },\n\n /**\n * Assigns end users to worlds, creating new worlds as appropriate, automatically. Assigns all end users in the group, and creates new worlds as needed based on the project-level world configuration (roles, optional roles, and minimum end users per world).\n *\n * **Example**\n *\n * var wa = new F.service.World({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * group: 'team1' });\n *\n * wa.autoAssign();\n *\n * **Parameters**\n * @param {object} `options` (Optional) Options object to override global options.\n *\n */\n autoAssign: function (options) {\n options = options || {};\n\n var opt = $.extend(true, {},\n serviceOptions,\n options,\n { url: urlConfig.getAPIPath(assignmentEndpoint) }\n );\n\n var params = {\n account: opt.account,\n project: opt.project,\n group: opt.group\n };\n\n if (opt.maxUsers) {\n params.maxUsers = opt.maxUsers;\n }\n\n return http.post(params, opt);\n },\n\n /**\n * Gets the project's world configuration.\n *\n * Typically, every interaction with your project uses the same configuration of each world. For example, each world in your project probably has the same roles for end users. And your project is probably either configured so that all end users share the same world (and run), or smaller sets of end users share worlds — but not both.\n *\n * (The [Multiplayer Project REST API](../../../rest_apis/multiplayer/multiplayer_project/) allows you to set these project-level world configurations. The World Adapter simply retrieves them, for example so they can be used in auto-assignment of end users to worlds.)\n *\n * **Example**\n *\n * var wa = new F.service.World({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * group: 'team1' });\n *\n * wa.getProjectSettings()\n * .then(function(settings) {\n * console.log(settings.roles);\n * console.log(settings.optionalRoles);\n * });\n *\n * **Parameters**\n * @param {object} `options` (Optional) Options object to override global options.\n */\n getProjectSettings: function (options) {\n options = options || {};\n\n var opt = $.extend(true, {},\n serviceOptions,\n options,\n { url: urlConfig.getAPIPath(projectEndpoint) }\n );\n\n opt.url += [opt.account, opt.project].join('/');\n\n return http.get(null, opt);\n }\n\n };\n\n $.extend(this, publicAPI);\n};\n","'use strict';\n/**\n* ## User API Adapter\n*\n* The User API Adapter allows you to retrieve details about end users in your team (account). It is based on the querying capabilities of the underlying RESTful [User API](../../../rest_apis/user_management/user/).\n*\n* To use the User API Adapter, instantiate it and then call its methods.\n*\n* var ua = new F.service.User({\n* account: 'acme-simulations',\n* token: 'user-or-project-access-token'\n* });\n* ua.getById('42836d4b-5b61-4fe4-80eb-3136e956ee5c');\n* ua.get({ userName: 'jsmith' });\n* ua.get({ id: ['42836d4b-5b61-4fe4-80eb-3136e956ee5c',\n* '4ea75631-4c8d-4872-9d80-b4600146478e'] });\n*\n* The constructor takes an optional `options` parameter in which you can specify the `account` and `token` if they are not already available in the current context.\n*/\n\nvar ConfigService = require('./configuration-service');\nvar TransportFactory = require('../transport/http-transport-factory');\nvar SessionManager = require('../store/session-manager');\nvar qutil = require('../util/query-util');\n\nmodule.exports = function (config) {\n var defaults = {\n\n /**\n * The account id. In the Epicenter UI, this is the **Team ID** (for team projects) or **User ID** (for personal projects). Defaults to empty string.\n * @type {String}\n */\n account: undefined,\n\n /**\n * The access token to use when searching for end users. (See [more background on access tokens](../../../project_access/)).\n * @type {String}\n */\n token: undefined,\n\n /**\n * Options to pass on to the underlying transport layer. All jquery.ajax options at http://api.jquery.com/jQuery.ajax/ are available. Defaults to empty object.\n * @type {Object}\n */\n transport: {}\n };\n\n this.sessionManager = new SessionManager();\n var serviceOptions = this.sessionManager.getMergedOptions(defaults, config);\n var urlConfig = new ConfigService(serviceOptions).get('server');\n var transportOptions = $.extend(true, {}, serviceOptions.transport, {\n url: urlConfig.getAPIPath('user')\n });\n\n if (serviceOptions.token) {\n transportOptions.headers = {\n 'Authorization': 'Bearer ' + serviceOptions.token\n };\n }\n\n var http = new TransportFactory(transportOptions);\n\n var publicAPI = {\n\n /**\n * Retrieve details about particular end users in your team, based on user name or user id.\n *\n * **Example**\n *\n * var ua = new F.service.User({\n * account: 'acme-simulations',\n * token: 'user-or-project-access-token'\n * });\n * ua.get({ userName: 'jsmith' });\n * ua.get({ id: ['42836d4b-5b61-4fe4-80eb-3136e956ee5c',\n * '4ea75631-4c8d-4872-9d80-b4600146478e'] });\n *\n * **Parameters**\n * @param {object} `filter` Object with field `userName` and value of the username. Alternatively, object with field `id` and value of an array of user ids.\n * @param {object} `options` (Optional) Overrides for configuration options.\n */\n\n get: function (filter, options) {\n options = options || {};\n filter = filter || {};\n\n var getOptions = $.extend(true, {},\n serviceOptions,\n options\n );\n\n var toQFilter = function (filter) {\n var res = {};\n\n // API only supports filtering by username for now\n if (filter.userName) {\n res.q = filter.userName;\n }\n\n return res;\n };\n\n var toIdFilters = function (id) {\n if (!id) {\n return '';\n }\n\n id = $.isArray(id) ? id : [id];\n return 'id=' + id.join('&id=');\n };\n\n var getFilters = [\n 'account=' + getOptions.account,\n toIdFilters(filter.id),\n qutil.toQueryFormat(toQFilter(filter))\n ].join('&');\n\n // special case for queries with large number of ids\n // make it as a post with GET semantics\n var threshold = 30;\n if (filter.id && $.isArray(filter.id) && filter.id.length >= threshold) {\n getOptions.url = urlConfig.getAPIPath('user') + '?_method=GET';\n return http.post({ id: filter.id }, getOptions);\n } else {\n return http.get(getFilters, getOptions);\n }\n },\n\n /**\n * Retrieve details about a single end user in your team, based on user id.\n *\n * **Example**\n *\n * var ua = new F.service.User({\n * account: 'acme-simulations',\n * token: 'user-or-project-access-token'\n * });\n * ua.getById('42836d4b-5b61-4fe4-80eb-3136e956ee5c');\n *\n * **Parameters**\n * @param {string} `userId` The user id for the end user in your team.\n * @param {object} `options` (Optional) Overrides for configuration options.\n */\n\n getById: function (userId, options) {\n return publicAPI.get({ id: userId }, options);\n }\n };\n\n $.extend(this, publicAPI);\n};\n\n\n\n\n","/**\n *\n * ## Member API Adapter\n *\n * The Member API Adapter provides methods to look up information about end users for your project and how they are divided across groups. It is based on query capabilities of the underlying RESTful [Member API](../../../rest_apis/user_management/member/).\n *\n * This is only needed for Authenticated projects, that is, team projects with [end users and groups](../../../groups_and_end_users/). For example, if some of your end users are facilitators, or if your end users should be treated differently based on which group they are in, use the Member API to find that information.\n *\n * var ma = new F.service.Member({ token: 'user-or-project-access-token' });\n * ma.getGroupsForUser({ userId: 'b6b313a3-ab84-479c-baea-206f6bff337' });\n * ma.getGroupDetails({ groupId: '00b53308-9833-47f2-b21e-1278c07d53b8' });\n */\n\n'use strict';\n\nvar ConfigService = require('./configuration-service');\nvar TransportFactory = require('../transport/http-transport-factory');\nvar SessionManager = require('../store/session-manager');\nvar _pick = require('../util/object-util')._pick;\nvar apiEndpoint = 'member/local';\n\nmodule.exports = function (config) {\n var defaults = {\n /**\n * Epicenter user id. Defaults to a blank string.\n * @type {string}\n */\n userId: undefined,\n\n /**\n * Epicenter group id. Defaults to a blank string. Note that this is the group *id*, not the group *name*.\n * @type {string}\n */\n groupId: undefined,\n\n /**\n * Options to pass on to the underlying transport layer. All jquery.ajax options at http://api.jquery.com/jQuery.ajax/ are available. Defaults to empty object.\n * @type {object}\n */\n transport: {}\n };\n this.sessionManager = new SessionManager();\n var serviceOptions = this.sessionManager.getMergedOptions(defaults, config);\n var urlConfig = new ConfigService(serviceOptions).get('server');\n\n var transportOptions = $.extend(true, {}, serviceOptions.transport, {\n url: urlConfig.getAPIPath(apiEndpoint)\n });\n\n if (serviceOptions.token) {\n transportOptions.headers = {\n 'Authorization': 'Bearer ' + serviceOptions.token\n };\n }\n var http = new TransportFactory(transportOptions, serviceOptions);\n\n var getFinalParams = function (params) {\n if (typeof params === 'object') {\n return $.extend(true, serviceOptions, params);\n }\n return serviceOptions;\n };\n\n var patchUserActiveField = function (params, active, options) {\n var httpOptions = $.extend(true, serviceOptions, options, {\n url: urlConfig.getAPIPath(apiEndpoint) + params.groupId + '/' + params.userId\n });\n\n return http.patch({ active: active }, httpOptions);\n };\n\n var publicAPI = {\n\n /**\n * Retrieve details about all of the group memberships for one end user. The membership details are returned in an array, with one element (group record) for each group to which the end user belongs.\n *\n * In the membership array, each group record includes the group id, project id, account (team) id, and an array of members. However, only the user whose userId is included in the call is listed in the members array (regardless of whether there are other members in this group).\n *\n * **Example**\n *\n * var ma = new F.service.Member({ token: 'user-or-project-access-token' });\n * ma.getGroupsForUser('42836d4b-5b61-4fe4-80eb-3136e956ee5c')\n * .then(function(memberships){\n * for (var i=0; i\n * // \n * // \n * // \n * // \n * //\n * $('#upload-file').on('submit', function (e) {\n * e.preventDefault();\n * var filename = $('#filename').val();\n * var data = new FormData();\n * var inputControl = $('#file')[0];\n * data.append('file', inputControl.files[0], filename);\n *\n * aa.create(filename, data, { scope: 'user' });\n * });\n *\n */\n\n'use strict';\n\nvar ConfigService = require('./configuration-service');\nvar TransportFactory = require('../transport/http-transport-factory');\nvar _pick = require('../util/object-util')._pick;\nvar SessionManager = require('../store/session-manager');\n\nvar apiEndpoint = 'asset';\n\nmodule.exports = function (config) {\n var defaults = {\n /**\n * For projects that require authentication, pass in the user access token (defaults to empty string). If the user is already logged in to Epicenter, the user access token is already set in a cookie and automatically loaded from there. (See [more background on access tokens](../../../project_access/)).\n * @see [Authentication API Service](../auth-api-service/) for getting tokens.\n * @type {String}\n */\n token: undefined,\n /**\n * The account id. In the Epicenter UI, this is the **Team ID** (for team projects). If left undefined, taken from the URL.\n * @type {String}\n */\n account: undefined,\n /**\n * The project id. If left undefined, taken from the URL.\n * @type {String}\n */\n project: undefined,\n /**\n * The group name. Defaults to session's `groupName`.\n * @type {String}\n */\n group: undefined,\n /**\n * The user id. Defaults to session's `userId`.\n * @type {String}\n */\n userId: undefined,\n /**\n * The scope for the asset. Valid values are: `user`, `group`, and `project`. See above for the required permissions to write to each scope. Defaults to `user`, meaning the current end user or a facilitator in the end user's group can edit the asset.\n * @type {String}\n */\n scope: 'user',\n /**\n * Determines if a request to list the assets in a scope includes the complete URL for each asset (`true`), or only the file names of the assets (`false`). Defaults to `true`.\n * @type {boolean}\n */\n fullUrl: true,\n /**\n * The transport object contains the options passed to the XHR request.\n * @type {object}\n */\n transport: {\n processData: false\n }\n };\n this.sessionManager = new SessionManager();\n var serviceOptions = this.sessionManager.getMergedOptions(defaults, config);\n var urlConfig = new ConfigService(serviceOptions).get('server');\n\n if (!serviceOptions.account) {\n serviceOptions.account = urlConfig.accountPath;\n }\n\n if (!serviceOptions.project) {\n serviceOptions.project = urlConfig.projectPath;\n }\n\n var transportOptions = $.extend(true, {}, serviceOptions.transport, {\n url: urlConfig.getAPIPath(apiEndpoint)\n });\n\n if (serviceOptions.token) {\n transportOptions.headers = {\n 'Authorization': 'Bearer ' + serviceOptions.token\n };\n }\n\n var http = new TransportFactory(transportOptions);\n\n var assetApiParams = ['encoding', 'data', 'contentType'];\n var scopeConfig = {\n user: ['scope', 'account', 'project', 'group', 'userId'],\n group: ['scope', 'account', 'project', 'group'],\n project: ['scope', 'account', 'project'],\n };\n\n var validateFilename = function (filename) {\n if (!filename) {\n throw new Error('filename is needed.');\n }\n };\n\n var validateUrlParams = function (options) {\n var partKeys = scopeConfig[options.scope];\n if (!partKeys) {\n throw new Error('scope parameter is needed.');\n }\n\n $.each(partKeys, function () {\n if (!options[this]) {\n throw new Error(this + ' parameter is needed.');\n }\n });\n };\n\n var buildUrl = function (filename, options) {\n validateUrlParams(options);\n var partKeys = scopeConfig[options.scope];\n var parts = $.map(partKeys, function (key) {\n return options[key];\n });\n if (filename) {\n // This prevents adding a trailing / in the URL as the Asset API\n // does not work correctly with it\n filename = '/' + filename;\n }\n return urlConfig.getAPIPath(apiEndpoint) + parts.join('/') + filename;\n };\n\n // Private function, all requests follow a more or less same approach to\n // use the Asset API and the difference is the HTTP verb\n //\n // @param {string} `method` (Required) HTTP verb\n // @param {string} `filename` (Required) Name of the file to delete/replace/create\n // @param {object} `params` (Optional) Body parameters to send to the Asset API\n // @param {object} `options` (Optional) Options object to override global options.\n var upload = function (method, filename, params, options) {\n validateFilename(filename);\n // make sure the parameter is clean\n method = method.toLowerCase();\n var contentType = params instanceof FormData === true ? false : 'application/json';\n if (contentType === 'application/json') {\n // whitelist the fields that we actually can send to the api\n params = _pick(params, assetApiParams);\n } else { // else we're sending form data which goes directly in request body\n // For multipart/form-data uploads the filename is not set in the URL,\n // it's getting picked by the FormData field filename.\n filename = method === 'post' || method === 'put' ? '' : filename;\n }\n var urlOptions = $.extend({}, serviceOptions, options);\n var url = buildUrl(filename, urlOptions);\n var createOptions = $.extend(true, {}, urlOptions, { url: url, contentType: contentType });\n\n return http[method](params, createOptions);\n };\n\n var publicAPI = {\n /**\n * Creates a file in the Asset API. The server returns an error (status code `409`, conflict) if the file already exists, so\n * check first with a `list()` or a `get()`.\n *\n * **Example**\n *\n * var aa = new F.service.Asset({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * group: 'team1',\n * userId: ''\n * });\n *\n * // create a new asset using encoded text\n * aa.create('test.txt', {\n * encoding: 'BASE_64',\n * data: 'VGhpcyBpcyBhIHRlc3QgZmlsZS4=',\n * contentType: 'text/plain'\n * }, { scope: 'user' });\n *\n * // alternatively, create a new asset using a file uploaded through a form\n * // this sample code goes with an html form that looks like this:\n * //\n * //
\n * // \n * // \n * // \n * //
\n * //\n * $('#upload-file').on('submit', function (e) {\n * e.preventDefault();\n * var filename = $('#filename').val();\n * var data = new FormData();\n * var inputControl = $('#file')[0];\n * data.append('file', inputControl.files[0], filename);\n *\n * aa.create(filename, data, { scope: 'user' });\n * });\n *\n *\n * **Parameters**\n * @param {string} `filename` (Required) Name of the file to create.\n * @param {object} `params` (Optional) Body parameters to send to the Asset API. Required if the `options.transport.contentType` is `application/json`, otherwise ignored.\n * @param {string} `params.encoding` Either `HEX` or `BASE_64`. Required if `options.transport.contentType` is `application/json`.\n * @param {string} `params.data` The encoded data for the file. Required if `options.transport.contentType` is `application/json`.\n * @param {string} `params.contentType` The mime type of the file. Optional.\n * @param {object} `options` (Optional) Options object to override global options.\n *\n */\n create: function (filename, params, options) {\n return upload('post', filename, params, options);\n },\n\n /**\n * Gets a file from the Asset API, fetching the asset content. (To get a list\n * of the assets in a scope, use `list()`.)\n *\n * **Parameters**\n * @param {string} `filename` (Required) Name of the file to retrieve.\n * @param {object} `options` (Optional) Options object to override global options.\n *\n */\n get: function (filename, options) {\n var getServiceOptions = _pick(serviceOptions, ['scope', 'account', 'project', 'group', 'userId']);\n var urlOptions = $.extend({}, getServiceOptions, options);\n var url = buildUrl(filename, urlOptions);\n var getOptions = $.extend(true, {}, urlOptions, { url: url });\n\n return http.get({}, getOptions);\n },\n\n /**\n * Gets the list of the assets in a scope.\n *\n * **Example**\n *\n * aa.list({ fullUrl: true }).then(function(fileList){\n * console.log('array of files = ', fileList);\n * });\n *\n * **Parameters**\n * @param {object} `options` (Optional) Options object to override global options.\n * @param {string} `options.scope` (Optional) The scope (`user`, `group`, `project`).\n * @param {boolean} `options.fullUrl` (Optional) Determines if the list of assets in a scope includes the complete URL for each asset (`true`), or only the file names of the assets (`false`).\n *\n */\n list: function (options) {\n var dtd = $.Deferred();\n var me = this;\n var urlOptions = $.extend({}, serviceOptions, options);\n var url = buildUrl('', urlOptions);\n var getOptions = $.extend(true, {}, urlOptions, { url: url });\n var fullUrl = getOptions.fullUrl;\n\n if (!fullUrl) {\n return http.get({}, getOptions);\n }\n\n http.get({}, getOptions)\n .then(function (files) {\n var fullPathFiles = $.map(files, function (file) {\n return buildUrl(file, urlOptions);\n });\n dtd.resolve(fullPathFiles, me);\n })\n .fail(dtd.reject);\n\n return dtd.promise();\n },\n\n /**\n * Replaces an existing file in the Asset API.\n *\n * **Example**\n *\n * // replace an asset using encoded text\n * aa.replace('test.txt', {\n * encoding: 'BASE_64',\n * data: 'VGhpcyBpcyBhIHNlY29uZCB0ZXN0IGZpbGUu',\n * contentType: 'text/plain'\n * }, { scope: 'user' });\n *\n * // alternatively, replace an asset using a file uploaded through a form\n * // this sample code goes with an html form that looks like this:\n * //\n * //
\n * // \n * // \n * // \n * //
\n * //\n * $('#replace-file').on('submit', function (e) {\n * e.preventDefault();\n * var filename = $('#replace-filename').val();\n * var data = new FormData();\n * var inputControl = $('#file')[0];\n * data.append('file', inputControl.files[0], filename);\n *\n * aa.replace(filename, data, { scope: 'user' });\n * });\n *\n * **Parameters**\n * @param {string} `filename` (Required) Name of the file being replaced.\n * @param {object} `params` (Optional) Body parameters to send to the Asset API. Required if the `options.transport.contentType` is `application/json`, otherwise ignored.\n * @param {string} `params.encoding` Either `HEX` or `BASE_64`. Required if `options.transport.contentType` is `application/json`.\n * @param {string} `params.data` The encoded data for the file. Required if `options.transport.contentType` is `application/json`.\n * @param {string} `params.contentType` The mime type of the file. Optional.\n * @param {object} `options` (Optional) Options object to override global options.\n *\n */\n replace: function (filename, params, options) {\n return upload('put', filename, params, options);\n },\n\n /**\n * Deletes a file from the Asset API.\n *\n * **Example**\n *\n * aa.delete(sampleFileName);\n *\n * **Parameters**\n * @param {string} `filename` (Required) Name of the file to delete.\n * @param {object} `options` (Optional) Options object to override global options.\n *\n */\n delete: function (filename, options) {\n return upload('delete', filename, {}, options);\n },\n\n assetUrl: function (filename, options) {\n var urlOptions = $.extend({}, serviceOptions, options);\n return buildUrl(filename, urlOptions);\n }\n };\n $.extend(this, publicAPI);\n};\n","/**\n *\n * ## Group API Adapter\n *\n * The Group API Adapter provides methods to look up, create, change or remove information about groups in a project. It is based on query capabilities of the underlying RESTful [Group API](../../../rest_apis/user_management/group/).\n *\n * This is only needed for Authenticated projects, that is, team projects with [end users and groups](../../../groups_and_end_users/).\n *\n * var ma = new F.service.Group({ token: 'user-or-project-access-token' });\n * ma.getGroupsForProject({ account: 'acme', project: 'sample' });\n */\n\n'use strict';\n\nvar serviceUtils = require('./service-utils');\nvar TransportFactory = require('../transport/http-transport-factory');\nvar objectAssign = require('object-assign');\n\nvar apiEndpoint = 'group/local';\n\nvar GroupService = function (config) {\n var defaults = {\n /**\n * Epicenter account name. Defaults to undefined.\n * @type {string}\n */\n account: undefined,\n\n /**\n * Epicenter project name. Defaults to undefined.\n * @type {string}\n */\n project: undefined,\n\n /**\n * Options to pass on to the underlying transport layer. All jquery.ajax options at http://api.jquery.com/jQuery.ajax/ are available. Defaults to empty object.\n * @type {object}\n */\n transport: {}\n };\n var serviceOptions = serviceUtils.getDefaultOptions(defaults, config, { apiEndpoint: apiEndpoint });\n var transportOptions = serviceOptions.transport;\n delete serviceOptions.transport;\n var http = new TransportFactory(transportOptions, serviceOptions);\n var publicAPI = {\n /*\n * Gets information for a group or multiple groups.\n * @param {string} `params` the groupId of the target group\n * @param {Object} `params` object with query parameters\n * @patam {string} `params.q` partial match for name, organization or event.\n * @patam {string} `params.account` Epicenter's Team ID\n * @patam {string} `params.project` Epicenter's Project ID\n * @patam {string} `params.name` Epicenter's Group Name\n * @param {Object} `options` (Optional) Overrides for configuration options.\n */\n getGroups: function (params, options) {\n //groupID is part of the URL\n //q, account and project are part of the query string\n var finalOpts = objectAssign({}, serviceOptions, options);\n var finalParams;\n if (typeof params === 'string') {\n finalOpts.url = serviceUtils.getApiUrl(apiEndpoint + '/' + params, finalOpts);\n } else {\n finalParams = params;\n }\n return http.get(finalParams, finalOpts);\n }\n };\n objectAssign(this, publicAPI);\n};\n\nmodule.exports = GroupService;\n","/**\n * @class Cookie Storage Service\n *\n * @example\n * var people = require('cookie-store')({ root: 'people' });\n people\n .save({lastName: 'smith' })\n\n */\n\n\n'use strict';\n\n// Thin document.cookie wrapper to allow unit testing\nvar Cookie = function () {\n this.get = function () {\n return document.cookie;\n };\n\n this.set = function (newCookie) {\n document.cookie = newCookie;\n };\n};\n\nmodule.exports = function (config) {\n var host = window.location.hostname;\n var validHost = host.split('.').length > 1;\n var domain = validHost ? '.' + host : null;\n\n var defaults = {\n /**\n * Name of collection\n * @type { string}\n */\n root: '/',\n\n domain: domain,\n cookie: new Cookie()\n };\n this.serviceOptions = $.extend({}, defaults, config);\n\n var publicAPI = {\n // * TBD\n // * Query collection; uses MongoDB syntax\n // * @see \n // *\n // * @param { string} qs Query Filter\n // * @param { string} limiters @see \n // *\n // * @example\n // * cs.query(\n // * { name: 'John', className: 'CSC101' },\n // * {limit: 10}\n // * )\n\n // query: function (qs, limiters) {\n\n // },\n\n /**\n * Save cookie value\n * @param { string|Object} key If given a key save values under it, if given an object directly, save to top-level api\n * @param {Object} value (Optional)\n * @param {Object} options Overrides for service options\n *\n * @return {*} The saved value\n *\n * @example\n * cs.set('person', { firstName: 'john', lastName: 'smith' });\n * cs.set({ name:'smith', age:'32' });\n */\n set: function (key, value, options) {\n var setOptions = $.extend(true, {}, this.serviceOptions, options);\n\n var domain = setOptions.domain;\n var path = setOptions.root;\n var cookie = setOptions.cookie;\n\n cookie.set(encodeURIComponent(key) + '=' +\n encodeURIComponent(value) +\n (domain ? '; domain=' + domain : '') +\n (path ? '; path=' + path : '')\n );\n\n return value;\n },\n\n /**\n * Load cookie value\n * @param { string|Object} key If given a key save values under it, if given an object directly, save to top-level api\n * @return {*} The value stored\n *\n * @example\n * cs.get('person');\n */\n get: function (key) {\n var cookie = this.serviceOptions.cookie;\n var cookieReg = new RegExp('(?:^|;)\\\\s*' + encodeURIComponent(key).replace(/[\\-\\.\\+\\*]/g, '\\\\$&') + '\\\\s*\\\\=\\\\s*([^;]*).*$');\n var res = cookieReg.exec(cookie.get());\n var val = res ? decodeURIComponent(res[1]) : null;\n return val;\n },\n\n /**\n * Removes key from collection\n * @param { string} key key to remove\n * @return { string} key The key removed\n *\n * @example\n * cs.remove('person');\n */\n remove: function (key, options) {\n var remOptions = $.extend(true, {}, this.serviceOptions, options);\n\n var domain = remOptions.domain;\n var path = remOptions.root;\n var cookie = remOptions.cookie;\n\n cookie.set(encodeURIComponent(key) +\n '=; expires=Thu, 01 Jan 1970 00:00:00 GMT' +\n (domain ? '; domain=' + domain : '') +\n (path ? '; path=' + path : '')\n );\n return key;\n },\n\n /**\n * Removes collection being referenced\n * @return { array} keys All the keys removed\n */\n destroy: function () {\n var cookie = this.serviceOptions.cookie;\n var aKeys = cookie.get().replace(/((?:^|\\s*;)[^\\=]+)(?=;|$)|^\\s*|\\s*(?:\\=[^;]*)?(?:\\1|$)/g, '').split(/\\s*(?:\\=[^;]*)?;\\s*/);\n for (var nIdx = 0; nIdx < aKeys.length; nIdx++) {\n var cookieKey = decodeURIComponent(aKeys[nIdx]);\n this.remove(cookieKey);\n }\n return aKeys;\n }\n };\n\n $.extend(this, publicAPI);\n};\n","/**\n Decides type of store to provide\n*/\n\n'use strict';\n// var isNode = false; FIXME: Browserify/minifyify has issues with the next link\n// var store = (isNode) ? require('./session-store') : require('./cookie-store');\nvar store = require('./cookie-store');\n\nmodule.exports = store;\n","'use strict';\nvar RunService = require('../service/run-api-service');\n\nvar defaults = {\n validFilter: { saved: true }\n};\n\nfunction ScenarioManager(options) {\n this.options = $.extend(true, {}, defaults, options);\n this.runService = this.options.run || new RunService(this.options);\n}\n\nScenarioManager.prototype = {\n getRuns: function (filter) {\n this.filter = $.extend(true, {}, this.options.validFilter, filter);\n return this.runService.query(this.filter);\n },\n\n loadVariables: function (vars) {\n return this.runService.query(this.filter, { include: vars });\n },\n\n save: function (run, meta) {\n return this._getService(run).save($.extend(true, {}, { saved: true }, meta));\n },\n\n archive: function (run) {\n return this._getService(run).save({ saved: false });\n },\n\n _getService: function (run) {\n if (typeof run === 'string') {\n return new RunService($.extend(true, {}, this.options, { filter: run }));\n }\n\n if (typeof run === 'object' && run instanceof RunService) {\n return run;\n }\n\n throw new Error('Save method requires a run service or a runId');\n },\n\n getRun: function (runId) {\n return new RunService($.extend(true, {}, this.options, { filter: runId }));\n }\n};\n\nmodule.exports = ScenarioManager;\n\n","/**\n* ## Run Manager\n*\n* The Run Manager gives you access to runs for your project. This allows you to read and update variables, call operations, etc. Additionally, the Run Manager gives you control over run creation depending on run states. Specifically, you can select [run creation strategies (rules)](../../strategy/) for which runs end users of your project work with when they log in to your project.\n*\n* There are many ways to create new runs, including the Epicenter.js [Run Service](../run-api-service/), the RESFTful [Run API](../../../rest_apis/aggregate_run_api) and the [Model Run API](../../../rest_apis/other_apis/model_apis/run/). However, for some projects it makes more sense to pick up where the user left off, using an existing run. And in some projects, whether to create a new run or use an existing one is conditional, for example based on characteristics of the existing run or your own knowledge about the model. The Run Manager provides this level of control: your call to `getRun()`, rather than always returning a new run, returns a run based on the strategy you've specified. (Note that many of the Epicenter sample projects use a Run Service directly, because generally the sample projects are played in one end user session and don't care about run states or run strategies.)\n*\n*\n* ### Using the Run Manager to create and access runs\n*\n* To use the Run Manager, instantiate it by passing in:\n*\n* * `run`: (required) Run object. Must contain:\n* * `account`: Epicenter account id (**Team ID** for team projects, **User ID** for personal projects).\n* * `project`: Epicenter project id.\n* * `model`: The name of your primary model file. (See more on [Writing your Model](../../../writing_your_model/).)\n* * `scope`: (optional) Scope object for the run, for example `scope.group` with value of the name of the group.\n* * `server`: (optional) An object with one field, `host`. The value of `host` is the string `api.forio.com`, the URI of the Forio server. This is automatically set, but you can pass it explicitly if desired. It is most commonly used for clarity when you are [hosting an Epicenter project on your own server](../../../how_to/self_hosting/).\n* * `files`: (optional) If and only if you are using a Vensim model and you have additional data to pass in to your model, you can pass a `files` object with the names of the files, for example: `\"files\": {\"data\": \"myExtraData.xls\"}`. (Note that you'll also need to add this same files object to your Vensim [configuration file](../../../model_code/vensim/).) See the [underlying Model Run API](../../../rest_apis/other_apis/model_apis/run/#post-creating-a-new-run-for-this-project) for additional information.\n*\n* * `strategy`: (optional) Run creation strategy for when to create a new run and when to reuse an end user's existing run. See [Run Manager Strategies](../../strategy/) for details. Defaults to `new-if-initialized`.\n*\n* * `sessionKey`: (optional) Name of browser cookie in which to store run information, including run id. Many conditional strategies, including the provided strategies, rely on this browser cookie to store the run id and help make the decision of whether to create a new run or use an existing one. The name of this cookie defaults to `epicenter-scenario` and can be set with the `sessionKey` parameter.\n*\n*\n* After instantiating a Run Manager, make a call to `getRun()` whenever you need to access a run for this end user. The `RunManager.run` contains the instantiated [Run Service](../run-api-service/). The Run Service allows you to access variables, call operations, etc.\n*\n* **Example**\n*\n* var rm = new F.manager.RunManager({\n* run: {\n* account: 'acme-simulations',\n* project: 'supply-chain-game',\n* model: 'supply-chain-model.jl',\n* server: { host: 'api.forio.com' }\n* },\n* strategy: 'always-new',\n* sessionKey: 'epicenter-session'\n* });\n* rm.getRun()\n* .then(function(run) {\n* // the return value of getRun() is a run object\n* var thisRunId = run.id;\n* // the RunManager.run also contains the instantiated Run Service,\n* // so any Run Service method is valid here\n* rm.run.do('runModel');\n* })\n*\n*/\n\n'use strict';\nvar strategiesMap = require('./run-strategies/strategies-map');\nvar specialOperations = require('./special-operations');\nvar RunService = require('../service/run-api-service');\n\n\nfunction patchRunService(service, manager) {\n if (service.patched) {\n return service;\n }\n\n var orig = service.do;\n service.do = function (operation, params, options) {\n var reservedOps = Object.keys(specialOperations);\n if (reservedOps.indexOf(operation) === -1) {\n return orig.apply(service, arguments);\n } else {\n return specialOperations[operation].call(service, params, options, manager);\n }\n };\n\n service.patched = true;\n\n return service;\n}\n\n\n\nvar defaults = {\n /**\n * Run creation strategy for when to create a new run and when to reuse an end user's existing run. See [Run Manager Strategies](../../strategy/) for details. Defaults to `new-if-initialized`.\n * @type {String}\n */\n\n strategy: 'new-if-initialized'\n};\n\nfunction RunManager(options) {\n this.options = $.extend(true, {}, defaults, options);\n\n if (this.options.run instanceof RunService) {\n this.run = this.options.run;\n } else {\n this.run = new RunService(this.options.run);\n }\n\n patchRunService(this.run, this);\n\n var StrategyCtor = typeof this.options.strategy === 'function' ? this.options.strategy : strategiesMap[this.options.strategy];\n\n if (!StrategyCtor) {\n throw new Error('Specified run creation strategy was invalid:', this.options.strategy);\n }\n\n this.strategy = new StrategyCtor(this.run, this.options);\n}\n\nRunManager.prototype = {\n /**\n * Returns the run object for a 'good' run.\n *\n * A good run is defined by the strategy. For example, if the strategy is `always-new`, the call\n * to `getRun()` always returns a newly created run; if the strategy is `new-if-persisted`,\n * `getRun()` creates a new run if the previous run is in a persisted state, otherwise\n * it returns the previous run. See [Run Manager Strategies](../../strategy/) for more on strategies.\n *\n * **Example**\n *\n * rm.getRun().then(function (run) {\n * // use the run object\n * var thisRunId = run.id;\n *\n * // use the Run Service object\n * rm.run.do('runModel');\n * });\n *\n * @return {$promise} Promise to complete the call.\n */\n getRun: function () {\n return this.strategy\n .getRun();\n },\n\n /**\n * Returns the run object for a new run, regardless of strategy: force creation of a new run.\n *\n * **Example**\n *\n * rm.reset().then(function (run) {\n * // use the (new) run object\n * var thisRunId = run.id;\n *\n * // use the Run Service object\n * rm.run.do('runModel');\n * });\n *\n * **Parameters**\n * @param {Object} `runServiceOptions` The options object to configure the Run Service. See [Run API Service](../run-api-service/) for more.\n */\n reset: function (runServiceOptions) {\n return this.strategy.reset(runServiceOptions);\n }\n};\n\nmodule.exports = RunManager;\n","/**\n* ## Authorization Manager\n*\n* The Authorization Manager provides an easy way to manage user authentication (logging in and out) and authorization (keeping track of tokens, sessions, and groups) for projects.\n*\n* The Authorization Manager is most useful for [team projects](../../../glossary/#team) with an access level of [Authenticated](../../../glossary/#access). These projects are accessed by [end users](../../../glossary/#users) who are members of one or more [groups](../../../glossary/#groups).\n*\n* #### Using the Authorization Manager\n*\n* To use the Authorization Manager, instantiate it. Then, make calls to any of the methods you need:\n*\n* var authMgr = new F.manager.AuthManager({\n* account: 'acme-simulations',\n* userName: 'enduser1',\n* password: 'passw0rd'\n* });\n* authMgr.login().then(function () {\n* authMgr.getCurrentUserSessionInfo();\n* });\n*\n*\n* The `options` object passed to the `F.manager.AuthManager()` call can include:\n*\n* * `account`: The account id for this `userName`. In the Epicenter UI, this is the **Team ID** (for team projects) or the **User ID** (for personal projects).\n* * `userName`: Email or username to use for logging in.\n* * `password`: Password for specified `userName`.\n* * `project`: The **Project ID** for the project to log this user into. Optional.\n* * `groupId`: Id of the group to which `userName` belongs. Required for end users if the `project` is specified.\n*\n* If you prefer starting from a template, the Epicenter JS Libs [Login Component](../../#components) uses the Authorization Manager as well. This sample HTML page (and associated CSS and JS files) provides a login form for team members and end users of your project. It also includes a group selector for end users that are members of multiple groups.\n*/\n\n'use strict';\nvar AuthAdapter = require('../service/auth-api-service');\nvar MemberAdapter = require('../service/member-api-adapter');\nvar GroupService = require('../service/group-api-service');\nvar SessionManager = require('../store/session-manager');\nvar Buffer = require('buffer').Buffer;\nvar _pick = require('../util/object-util')._pick;\nvar objectAssign = require('object-assign');\n\nvar defaults = {\n requiresGroup: true\n};\n\nfunction AuthManager(options) {\n options = $.extend(true, {}, defaults, options);\n this.sessionManager = new SessionManager(options);\n this.options = this.sessionManager.getMergedOptions();\n\n this.isLocal = this.options.isLocal;\n this.authAdapter = new AuthAdapter(this.options);\n}\n\nvar _findUserInGroup = function (members, id) {\n for (var j = 0; j 1) {\n if (groupId) {\n var filteredGroups = $.grep(groupList, function (resGroup) {\n return resGroup.groupId === groupId;\n });\n group = filteredGroups.length === 1 ? filteredGroups[0] : null;\n }\n }\n\n if (group) {\n // A team member does not get the group members because is calling the Group API\n // but it's automatically a fac user\n var isFac = isTeamMember ? true : _findUserInGroup(group.members, userInfo.user_id).role === 'facilitator';\n var groupData = {\n groupId: group.groupId,\n groupName: group.name,\n isFac: isFac\n };\n var sessionInfoWithGroup = objectAssign({}, sessionInfo, groupData);\n sessionInfo.groups[project] = groupData;\n _this.sessionManager.saveSession(sessionInfoWithGroup, adapterOptions);\n outSuccess.apply(this, [data]);\n $d.resolve(data);\n } else {\n handleGroupError('This user is associated with more than one group. Please specify a group id to log into and try again', 403, data);\n }\n };\n\n if (!isTeamMember) {\n _this.getUserGroups({ userId: userInfo.user_id, token: token }, userGroupOpts)\n .then(handleGroupList, $d.reject);\n } else {\n var opts = objectAssign({}, userGroupOpts, { token: token });\n var groupService = new GroupService(opts);\n groupService.getGroups({ account: adapterOptions.account, project: project })\n .then(function (groups) {\n // Group API returns id instead of groupId\n groups.forEach(function (group) {\n group.groupId = group.id;\n });\n handleGroupList(groups);\n }, $d.reject);\n }\n };\n\n adapterOptions.success = handleSuccess;\n adapterOptions.error = function (response) {\n if (adapterOptions.account) {\n // Try to login as a system user\n adapterOptions.account = null;\n adapterOptions.error = function () {\n outError.apply(this, arguments);\n $d.reject(response);\n };\n\n _this.authAdapter.login(adapterOptions);\n return;\n }\n\n outError.apply(this, arguments);\n $d.reject(response);\n };\n\n this.authAdapter.login(adapterOptions);\n return $d.promise();\n },\n\n /**\n * Logs user out by clearing all session information.\n *\n * **Example**\n *\n * authMgr.logout();\n *\n * **Parameters**\n *\n * @param {Object} `options` (Optional) Overrides for configuration options.\n */\n logout: function (options) {\n var _this = this;\n var adapterOptions = this.sessionManager.getMergedOptions(options);\n\n var removeCookieFn = function (response) {\n _this.sessionManager.removeSession();\n };\n\n return this.authAdapter.logout(adapterOptions).done(removeCookieFn);\n },\n\n /**\n * Returns the existing user access token if the user is already logged in. Otherwise, logs the user in, creating a new user access token, and returns the new token. (See [more background on access tokens](../../../project_access/)).\n *\n * **Example**\n *\n * authMgr.getToken()\n * .then(function (token) {\n * console.log('My token is ', token);\n * });\n *\n * **Parameters**\n * @param {Object} `options` (Optional) Overrides for configuration options.\n */\n getToken: function (options) {\n var httpOptions = this.sessionManager.getMergedOptions(options);\n\n var session = this.sessionManager.getSession();\n var $d = $.Deferred();\n //jshint camelcase: false\n //jscs:disable\n if (session.auth_token) {\n $d.resolve(session.auth_token);\n } else {\n this.login(httpOptions).then($d.resolve);\n }\n return $d.promise();\n },\n\n /**\n * Returns an array of group records, one for each group of which the current user is a member. Each group record includes the group `name`, `account`, `project`, and `groupId`.\n *\n * If some end users in your project are members of multiple groups, this is a useful method to call on your project's login page. When the user attempts to log in, you can use this to display the groups of which the user is member, and have the user select the correct group to log in to for this session.\n *\n * **Example**\n *\n * // get groups for current user\n * var sessionObj = authMgr.getCurrentUserSessionInfo();\n * authMgr.getUserGroups({ userId: sessionObj.userId, token: sessionObj.auth_token })\n * .then(function (groups) {\n * for (var i=0; i < groups.length; i++)\n * { console.log(groups[i].name); }\n * });\n *\n * // get groups for particular user\n * authMgr.getUserGroups({userId: 'b1c19dda-2d2e-4777-ad5d-3929f17e86d3', token: savedProjAccessToken });\n *\n * **Parameters**\n * @param {Object} `params` Object with a userId and token properties.\n * @param {String} `params.userId` The userId. If looking up groups for the currently logged in user, this is in the session information. Otherwise, pass a string.\n * @param {String} `params.token` The authorization credentials (access token) to use for checking the groups for this user. If looking up groups for the currently logged in user, this is in the session information. A team member's token or a project access token can access all the groups for all end users in the team or project.\n * @param {Object} `options` (Optional) Overrides for configuration options.\n */\n getUserGroups: function (params, options) {\n var adapterOptions = this.sessionManager.getMergedOptions({ success: $.noop }, options);\n var $d = $.Deferred();\n var outSuccess = adapterOptions.success;\n\n adapterOptions.success = function (memberInfo) {\n // The member API is at the account scope, we filter by project\n if (adapterOptions.project) {\n memberInfo = $.grep(memberInfo, function (group) {\n return group.project === adapterOptions.project;\n });\n }\n\n outSuccess.apply(this, [memberInfo]);\n $d.resolve(memberInfo);\n };\n\n var memberAdapter = new MemberAdapter({ token: params.token });\n memberAdapter.getGroupsForUser(params, adapterOptions).fail($d.reject);\n return $d.promise();\n },\n\n /**\n * Returns session information for the current user, including the `userId`, `account`, `project`, `groupId`, `groupName`, `isFac` (whether the end user is a facilitator of this group), and `auth_token` (user access token).\n *\n * *Important*: This method is synchronous. The session information is returned immediately in an object; no callbacks or promises are needed.\n *\n * Session information is stored in a cookie in the browser.\n *\n * **Example**\n *\n * var sessionObj = authMgr.getCurrentUserSessionInfo();\n *\n * **Parameters**\n * @param {Object} `options` (Optional) Overrides for configuration options.\n */\n getCurrentUserSessionInfo: function (options) {\n return this.sessionManager.getSession(options);\n },\n\n /*\n * Adds one or more groups to the current session. \n *\n * This method assumes that the project and group exist and the user specified in the session is part of this project and group.\n *\n * Returns the new session object.\n *\n * **Example**\n *\n * authMgr.addGroups({ project: 'hello-world', groupName: 'groupName', groupId: 'groupId' });\n * authMgr.addGroups([{ project: 'hello-world', groupName: 'groupName', groupId: 'groupId' }, { project: 'hello-world', groupName: '...' }]);\n *\n * **Parameters**\n * @param {object|array} `groups` (Required) The group object must contain the `project` (**Project ID**) and `groupName` properties. If passing an array of such objects, all of the objects must contain *different* `project` (**Project ID**) values: although end users may be logged in to multiple projects at once, they may only be logged in to one group per project at a time.\n * @param {string} `group.isFac` (optional) Defaults to `false`. Set to `true` if the user in the session should be a facilitator in this group.\n * @param {string} `group.groupId` (optional) Defaults to undefined. Needed mostly for the Members API.\n */\n addGroups: function (groups) {\n var session = this.getCurrentUserSessionInfo();\n var isArray = Array.isArray(groups);\n groups = isArray ? groups : [groups];\n\n $.each(groups, function (index, group) {\n var extendedGroup = $.extend({}, { isFac: false }, group);\n var project = extendedGroup.project;\n var validProps = ['groupName', 'groupId', 'isFac'];\n if (!project || !extendedGroup.groupName) {\n throw new Error('No project or groupName specified.');\n }\n // filter object\n extendedGroup = _pick(extendedGroup, validProps);\n session.groups[project] = extendedGroup;\n });\n this.sessionManager.saveSession(session);\n return session;\n }\n});\n\nmodule.exports = AuthManager;\n","/**\n* ## World Manager\n*\n* As discussed under the [World API Adapter](../world-api-adapter/), a [run](../../../glossary/#run) is a collection of end user interactions with a project and its model. For building multiplayer simulations you typically want multiple end users to share the same set of interactions, and work within a common state. Epicenter allows you to create \"worlds\" to handle such cases.\n*\n* The World Manager provides an easy way to track and access the current world and run for particular end users. It is typically used in pages that end users will interact with. (The related [World API Adapter](../world-api-adapter/) handles creating multiplayer worlds, and adding and removing end users and runs from a world. Because of this, typically the World Adapter is used for facilitator pages in your project.)\n*\n* ### Using the World Manager\n*\n* To use the World Manager, instantiate it. Then, make calls to any of the methods you need.\n*\n* When you instantiate a World Manager, the world's account id, project id, and group are automatically taken from the session (thanks to the [Authentication Service](../auth-api-service)).\n*\n* Note that the World Manager does *not* create worlds automatically. (This is different than the [Run Manager](../run-manager).) However, you can pass in specific options to any runs created by the manager, using a `run` object.\n*\n* The parameters for creating a World Manager are:\n*\n* * `account`: The **Team ID** in the Epicenter user interface for this project.\n* * `project`: The **Project ID** for this project.\n* * `group`: The **Group Name** for this world.\n* * `run`: Options to use when creating new runs with the manager, e.g. `run: { files: ['data.xls'] }`.\n* * `run.model`: The name of the primary model file for this project. Required if you have not already passed it in as part of the `options` parameter for an enclosing call.\n*\n* For example:\n*\n* var wMgr = new F.manager.WorldManager({\n* account: 'acme-simulations',\n* project: 'supply-chain-game',\n* run: { model: 'supply-chain.py' },\n* group: 'team1'\n* });\n*\n* wMgr.getCurrentRun();\n*/\n\n'use strict';\n\nvar WorldApi = require('../service/world-api-adapter');\nvar RunManager = require('./run-manager');\nvar AuthManager = require('./auth-manager');\nvar worldApi;\n\n// var defaults = {\n// account: '',\n// project: '',\n// group: '',\n// transport: {\n// }\n// };\n\n\nfunction buildStrategy(worldId, dtd) {\n\n return function Ctor(runService, options) {\n this.runService = runService;\n this.options = options;\n\n $.extend(this, {\n reset: function () {\n throw new Error('not implementd. Need api changes');\n },\n\n getRun: function () {\n var _this = this;\n //get or create!\n // Model is required in the options\n var model = this.options.run.model || this.options.model;\n return worldApi.getCurrentRunId({ model: model, filter: worldId })\n .then(function (runId) {\n return _this.runService.load(runId);\n })\n .then(function (run) {\n dtd.resolve.call(this, run, _this.runService);\n })\n .fail(dtd.reject);\n }\n }\n );\n };\n}\n\n\nmodule.exports = function (options) {\n this.options = options || { run: {}, world: {} };\n\n $.extend(true, this.options, this.options.run);\n $.extend(true, this.options, this.options.world);\n\n worldApi = new WorldApi(this.options);\n this._auth = new AuthManager();\n var _this = this;\n\n var api = {\n\n /**\n * Returns the current world (object) and an instance of the [World API Adapter](../world-api-adapter/).\n *\n * **Example**\n *\n * wMgr.getCurrentWorld()\n * .then(function(world, worldAdapter) {\n * console.log(world.id);\n * worldAdapter.getCurrentRunId();\n * });\n *\n * **Parameters**\n * @param {string} `userId` (Optional) The id of the user whose world is being accessed. Defaults to the user in the current session.\n * @param {string} `groupName` (Optional) The name of the group whose world is being accessed. Defaults to the group for the user in the current session.\n */\n getCurrentWorld: function (userId, groupName) {\n var session = this._auth.getCurrentUserSessionInfo();\n if (!userId) {\n userId = session.userId;\n }\n if (!groupName) {\n groupName = session.groupName;\n }\n return worldApi.getCurrentWorldForUser(userId, groupName);\n },\n\n /**\n * Returns the current run (object) and an instance of the [Run API Service](../run-api-service/).\n *\n * **Example**\n *\n * wMgr.getCurrentRun({model: 'myModel.py'})\n * .then(function(run, runService) {\n * console.log(run.id);\n * runService.do('startGame');\n * });\n *\n * **Parameters**\n * @param {string} `model` (Optional) The name of the model file. Required if not already passed in as `run.model` when the World Manager is created.\n */\n getCurrentRun: function (model) {\n var dtd = $.Deferred();\n var session = this._auth.getCurrentUserSessionInfo();\n var curUserId = session.userId;\n var curGroupName = session.groupName;\n\n function getAndRestoreLatestRun(world) {\n if (!world) {\n return dtd.reject({ error: 'The user is not part of any world!' });\n }\n\n var currentWorldId = world.id;\n var runOpts = $.extend(true, _this.options, { model: model });\n var strategy = buildStrategy(currentWorldId, dtd);\n var opt = $.extend(true, {}, {\n strategy: strategy,\n run: runOpts\n });\n var rm = new RunManager(opt);\n\n return rm.getRun()\n .then(function (run) {\n dtd.resolve(run, rm.runService, rm);\n });\n }\n\n this.getCurrentWorld(curUserId, curGroupName)\n .then(getAndRestoreLatestRun);\n\n return dtd.promise();\n }\n };\n\n $.extend(this, api);\n};\n","'use strict';\n\nvar classFrom = require('../../util/inherit');\nvar ConditionalStrategy = require('./conditional-creation-strategy');\n\nvar __super = ConditionalStrategy.prototype;\n\nvar Strategy = classFrom(ConditionalStrategy, {\n constructor: function (runService, options) {\n __super.constructor.call(this, runService, this.createIf, options);\n },\n\n createIf: function (run, headers) {\n // always create a new run!\n return true;\n }\n});\n\nmodule.exports = Strategy;\n","'use strict';\n\nvar makeSeq = require('../../util/make-sequence');\nvar Base = require('./identity-strategy');\nvar SessionManager = require('../../store/session-manager');\nvar classFrom = require('../../util/inherit');\nvar AuthManager = require('../auth-manager');\n\nvar keyNames = require('../key-names');\n\nvar defaults = {\n sessionKey: keyNames.STRATEGY_SESSION_KEY,\n path: ''\n};\n\nfunction setRunInSession(sessionKey, run, sessionManager) {\n sessionManager.getStore().set(sessionKey, JSON.stringify({ runId: run.id }));\n}\n\n/**\n* Conditional Creation Strategy\n* This strategy will try to get the run stored in the cookie and\n* evaluate if needs to create a new run by calling the 'condition' function\n*/\n\n/* jshint eqnull: true */\nvar Strategy = classFrom(Base, {\n constructor: function Strategy(runService, condition, options) {\n\n if (condition == null) {\n throw new Error('Conditional strategy needs a condition to createte a run');\n }\n\n this._auth = new AuthManager();\n this.run = makeSeq(runService);\n this.condition = typeof condition !== 'function' ? function () { return condition; } : condition;\n this.options = $.extend(true, {}, defaults, options);\n this.sessionManager = new SessionManager(options);\n this.runOptions = this.options.run;\n },\n\n runOptionsWithScope: function () {\n var userSession = this._auth.getCurrentUserSessionInfo();\n return $.extend({\n scope: { group: userSession.groupName }\n }, this.runOptions);\n },\n\n reset: function (runServiceOptions) {\n var _this = this;\n var opt = this.runOptionsWithScope();\n\n return this.run\n .create(opt, runServiceOptions)\n .then(function (run) {\n setRunInSession(_this.options.sessionKey, run, _this.sessionManager);\n run.freshlyCreated = true;\n return run;\n })\n .start();\n },\n\n getRun: function () {\n var sessionStore = this.sessionManager.getStore();\n var runSession = JSON.parse(sessionStore.get(this.options.sessionKey));\n\n if (runSession && runSession.runId) {\n return this._loadAndCheck(runSession).fail(function () {\n return this.reset(); //if it got the wrong cookie for e.g.\n }.bind(this));\n } else {\n return this.reset();\n }\n },\n\n _loadAndCheck: function (runSession) {\n var shouldCreate = false;\n var _this = this;\n\n return this.run\n .load(runSession.runId, null, {\n success: function (run, msg, headers) {\n shouldCreate = _this.condition.call(_this, run, headers);\n }\n })\n .then(function (run) {\n if (shouldCreate) {\n var opt = _this.runOptionsWithScope();\n // we need to do this, on the original runService (ie not sequencialized)\n // so we don't get in the middle of the queue\n return _this.run.original.create(opt)\n .then(function (run) {\n setRunInSession(_this.options.sessionKey, run, _this.sessionManager);\n run.freshlyCreated = true;\n return run;\n });\n }\n\n return run;\n })\n .start();\n }\n});\n\nmodule.exports = Strategy;\n","'use strict';\n\nvar classFrom = require('../../util/inherit');\nvar Base = {};\n\n// Interface that all strategies need to implement\nmodule.exports = classFrom(Base, {\n constructor: function (runService, options) {\n this.runService = runService;\n },\n\n reset: function () {\n // return a newly created run\n return $.Deferred().resolve().promise();\n },\n\n getRun: function () {\n // return a usable run\n return $.Deferred().resolve(this.runService).promise();\n }\n});\n","'use strict';\n\nvar classFrom = require('../../util/inherit');\nvar ConditionalStrategy = require('./conditional-creation-strategy');\n\nvar __super = ConditionalStrategy.prototype;\n\n/*\n* create a new run only if nothing is stored in the cookie\n* this is useful for baseRuns.\n*/\nvar Strategy = classFrom(ConditionalStrategy, {\n constructor: function (runService, options) {\n __super.constructor.call(this, runService, this.createIf, options);\n },\n\n createIf: function (run, headers) {\n // if we are here, it means that the run exists... so we don't need a new one\n return false;\n }\n});\n\nmodule.exports = Strategy;\n","'use strict';\nvar classFrom = require('../../util/inherit');\nvar ConditionalStrategy = require('./conditional-creation-strategy');\n\nvar __super = ConditionalStrategy.prototype;\n\nvar Strategy = classFrom(ConditionalStrategy, {\n constructor: function (runService, options) {\n __super.constructor.call(this, runService, this.createIf, options);\n },\n\n createIf: function (run, headers) {\n return headers.getResponseHeader('pragma') === 'persistent';\n }\n});\n\nmodule.exports = Strategy;\n","'use strict';\nvar classFrom = require('../../util/inherit');\nvar ConditionalStrategy = require('./conditional-creation-strategy');\n\nvar __super = ConditionalStrategy.prototype;\n\nvar Strategy = classFrom(ConditionalStrategy, {\n constructor: function (runService, options) {\n __super.constructor.call(this, runService, this.createIf, options);\n },\n\n createIf: function (run, headers) {\n return headers.getResponseHeader('pragma') === 'persistent' || run.initialized;\n }\n});\n\nmodule.exports = Strategy;\n","'use strict';\n\n/**\n * ## Channel Service\n *\n * The Epicenter platform provides a push channel, which allows you to publish and subscribe to messages within a [project](../../../glossary/#projects), [group](../../../glossary/#groups), or [multiplayer world](../../../glossary/#world). There are two main use cases for the channel: event notifications and chat messages.\n *\n * The Channel Service is a building block for this functionality. It creates a publish-subscribe object, allowing you to publish messages, subscribe to messages, or unsubscribe from messages for a given 'topic' on a `$.cometd` transport instance.\n *\n * Typically, you use the [Epicenter Channel Manager](../epicenter-channel-manager/) to create or retrieve channels, then use the Channel Service `subscribe()` and `publish()` methods to listen to or update data. (For additional background on Epicenter's push channel, see the introductory notes on the [Push Channel API](../../../rest_apis/multiplayer/channel/) page.)\n *\n * You'll need to include the `epicenter-multiplayer-dependencies.js` library in addition to the `epicenter.js` library in your project to use the Channel Service. See [Including Epicenter.js](../../#include).\n *\n * To use the Channel Service, instantiate it, then make calls to any of the methods you need.\n *\n * var cs = new F.service.Channel();\n * cs.publish('/acme-simulations/supply-chain-game/fall-seminar/run/variables', { price: 50 });\n *\n * The parameters for instantiating a Channel Service include:\n *\n * * `options` The options object to configure the Channel Service.\n * * `options.base` The base topic. This is added as a prefix to all further topics you publish or subscribe to while working with this Channel Service.\n * * `options.topicResolver` A function that processes all 'topics' passed into the `publish` and `subscribe` methods. This is useful if you want to implement your own serialize functions for converting custom objects to topic names. Returns a String. By default, it just echoes the topic.\n * * `options.transport` The instance of `$.cometd` to hook onto. See http://docs.cometd.org/reference/javascript.html for additional background on cometd.\n */\nvar Channel = function (options) {\n var defaults = {\n\n /**\n * The base topic. This is added as a prefix to all further topics you publish or subscribe to while working with this Channel Service.\n * @type {string}\n */\n base: '',\n\n /**\n * A function that processes all 'topics' passed into the `publish` and `subscribe` methods. This is useful if you want to implement your own serialize functions for converting custom objects to topic names. By default, it just echoes the topic.\n *\n * **Parameters**\n *\n * * `topic` Topic to parse.\n *\n * **Return Value**\n *\n * * *String*: This function should return a string topic.\n *\n * @type {function}\n */\n topicResolver: function (topic) {\n return topic;\n },\n\n /**\n * The instance of `$.cometd` to hook onto.\n * @type {object}\n */\n transport: null\n };\n this.channelOptions = $.extend(true, {}, defaults, options);\n};\n\nvar makeName = function (channelName, topic) {\n //Replace trailing/double slashes\n var newName = (channelName ? (channelName + '/' + topic) : topic).replace(/\\/\\//g, '/').replace(/\\/$/,'');\n return newName;\n};\n\n\nChannel.prototype = $.extend(Channel.prototype, {\n\n // future functionality:\n // // Set the context for the callback\n // cs.subscribe('run', function () { this.innerHTML = 'Triggered'}, document.body);\n //\n // // Control the order of operations by setting the `priority`\n // cs.subscribe('run', cb, this, {priority: 9});\n //\n // // Only execute the callback, `cb`, if the value of the `price` variable is 50\n // cs.subscribe('run/variables/price', cb, this, {priority: 30, value: 50});\n //\n // // Only execute the callback, `cb`, if the value of the `price` variable is greater than 50\n // subscribe('run/variables/price', cb, this, {priority: 30, value: '>50'});\n //\n // // Only execute the callback, `cb`, if the value of the `price` variable is even\n // subscribe('run/variables/price', cb, this, {priority: 30, value: function (val) {return val % 2 === 0}});\n\n\n /**\n * Subscribe to changes on a topic.\n *\n * The topic should include the full path of the account id (**Team ID** for team projects), project id, and group name. (In most cases, it is simpler to use the [Epicenter Channel Manager](../epicenter-channel-manager/) instead, in which case this is configured for you.)\n *\n * **Examples**\n *\n * var cb = function(val) { console.log(val.data); };\n *\n * // Subscribe to changes on a top-level 'run' topic\n * cs.subscribe('/acme-simulations/supply-chain-game/fall-seminar/run', cb);\n *\n * // Subscribe to changes on children of the 'run' topic. Note this will also be triggered for changes to run.x.y.z.\n * cs.subscribe('/acme-simulations/supply-chain-game/fall-seminar/run/*', cb);\n *\n * // Subscribe to changes on both the top-level 'run' topic and its children\n * cs.subscribe(['/acme-simulations/supply-chain-game/fall-seminar/run',\n * '/acme-simulations/supply-chain-game/fall-seminar/run/*'], cb);\n *\n * // Subscribe to changes on a particular variable\n * subscribe('/acme-simulations/supply-chain-game/fall-seminar/run/variables/price', cb);\n *\n *\n * **Return Value**\n *\n * * *String* Returns a token you can later use to unsubscribe.\n *\n * **Parameters**\n * @param {String|Array} `topic` List of topics to listen for changes on.\n * @param {Function} `callback` Callback function to execute. Callback is called with signature `(evt, payload, metadata)`.\n * @param {Object} `context` Context in which the `callback` is executed.\n * @param {Object} `options` (Optional) Overrides for configuration options.\n * @param {Number} `options.priority` Used to control order of operations. Defaults to 0. Can be any +ve or -ve number.\n * @param {String|Number|Function} `options.value` The `callback` is only triggered if this condition matches. See examples for details.\n *\n */\n subscribe: function (topic, callback, context, options) {\n\n var topics = [].concat(topic);\n var me = this;\n var subscriptionIds = [];\n var opts = me.channelOptions;\n\n opts.transport.batch(function () {\n $.each(topics, function (index, topic) {\n topic = makeName(opts.base, opts.topicResolver(topic));\n subscriptionIds.push(opts.transport.subscribe(topic, callback));\n });\n });\n return (subscriptionIds[1] ? subscriptionIds : subscriptionIds[0]);\n },\n\n /**\n * Publish data to a topic.\n *\n * **Examples**\n *\n * // Send data to all subscribers of the 'run' topic\n * cs.publish('/acme-simulations/supply-chain-game/fall-seminar/run', { completed: false });\n *\n * // Send data to all subscribers of the 'run/variables' topic\n * cs.publish('/acme-simulations/supply-chain-game/fall-seminar/run/variables', { price: 50 });\n *\n * **Parameters**\n *\n * @param {String} `topic` Topic to publish to.\n * @param {*} `data` Data to publish to topic.\n *\n */\n publish: function (topic, data) {\n var topics = [].concat(topic);\n var me = this;\n var returnObjs = [];\n var opts = me.channelOptions;\n\n\n opts.transport.batch(function () {\n $.each(topics, function (index, topic) {\n topic = makeName(opts.base, opts.topicResolver(topic));\n if (topic.charAt(topic.length - 1) === '*') {\n topic = topic.replace(/\\*+$/, '');\n console.warn('You can cannot publish to channels with wildcards. Publishing to ', topic, 'instead');\n }\n returnObjs.push(opts.transport.publish(topic, data));\n });\n });\n return (returnObjs[1] ? returnObjs : returnObjs[0]);\n },\n\n /**\n * Unsubscribe from changes to a topic.\n *\n * **Example**\n *\n * cs.unsubscribe('sampleToken');\n *\n * **Parameters**\n * @param {String} `token` The token for topic is returned when you initially subscribe. Pass it here to unsubscribe from that topic.\n */\n unsubscribe: function (token) {\n this.channelOptions.transport.unsubscribe(token);\n return token;\n },\n\n /**\n * Start listening for events on this instance. Signature is same as for jQuery Events: http://api.jquery.com/on/.\n *\n * Supported events are: `connect`, `disconnect`, `subscribe`, `unsubscribe`, `publish`, `error`.\n *\n * **Parameters**\n *\n * @param {string} `event` The event type. See more detail at jQuery Events: http://api.jquery.com/on/.\n */\n on: function (event) {\n $(this).on.apply($(this), arguments);\n },\n\n /**\n * Stop listening for events on this instance. Signature is same as for jQuery Events: http://api.jquery.com/off/.\n *\n * **Parameters**\n *\n * @param {string} `event` The event type. See more detail at jQuery Events: http://api.jquery.com/off/.\n */\n off: function (event) {\n $(this).off.apply($(this), arguments);\n },\n\n /**\n * Trigger events and execute handlers. Signature is same as for jQuery Events: http://api.jquery.com/trigger/.\n *\n * **Parameters**\n *\n * @param {string} `event` The event type. See more detail at jQuery Events: http://api.jquery.com/trigger/.\n */\n trigger: function (event) {\n $(this).trigger.apply($(this), arguments);\n }\n\n});\n\nmodule.exports = Channel;\n","'use strict';\n\n/**\n * ## Epicenter Channel Manager\n *\n * The Epicenter platform provides a push channel, which allows you to publish and subscribe to messages within a [project](../../../glossary/#projects), [group](../../../glossary/#groups), or [multiplayer world](../../../glossary/#world). There are two main use cases for the channel: event notifications and chat messages.\n *\n * The Epicenter Channel Manager is a wrapper around the (more generic) [Channel Manager](../channel-manager/), to instantiate it with Epicenter-specific defaults. If you are interested in including a notification or chat feature in your project, using an Epicenter Channel Manager is probably the easiest way to get started.\n *\n * You'll need to include the `epicenter-multiplayer-dependencies.js` library in addition to the `epicenter.js` library in your project to use the Epicenter Channel Manager. See [Including Epicenter.js](../../#include).\n *\n * To use the Epicenter Channel Manager: instantiate it, get the channel of the scope you want ([user](../../../glossary/#users), [world](../../../glossary/#world), or [group](../../../glossary/#groups)), then use the channel's `subscribe()` and `publish()` methods to subscribe to topics or publish data to topics.\n *\n * var cm = new F.manager.ChannelManager();\n * var gc = cm.getGroupChannel();\n * gc.subscribe('broadcasts', callback);\n *\n * For additional background on Epicenter's push channel, see the introductory notes on the [Push Channel API](../../../rest_apis/multiplayer/channel/) page.\n *\n * The parameters for instantiating an Epicenter Channel Manager include:\n *\n * * `options` Object with details about the Epicenter project for this Epicenter Channel Manager instance.\n * * `options.account` The Epicenter account id (**Team ID** for team projects, **User ID** for personal projects).\n * * `options.project` Epicenter project id.\n * * `options.userName` Epicenter userName used for authentication.\n * * `options.userId` Epicenter user id used for authentication. Optional; `options.userName` is preferred.\n * * `options.token` Epicenter token used for authentication. (You can retrieve this using `authManager.getToken()` from the [Authorization Manager](../auth-manager/).)\n * * `options.allowAllChannels` If not included or if set to `false`, all channel paths are validated; if your project requires [Push Channel Authorization](../../../updating_your_settings/), you should use this option. If you want to allow other channel paths, set to `true`; this is not common.\n */\n\nvar ChannelManager = require('./channel-manager');\nvar classFrom = require('../util/inherit');\nvar urlService = require('../service/url-config-service');\nvar SessionManager = require('../store/session-manager');\n\nvar AuthManager = require('./auth-manager');\n\nvar validTypes = {\n project: true,\n group: true,\n world: true,\n user: true,\n data: true,\n general: true,\n chat: true\n};\nvar session = new AuthManager();\nvar getFromSettingsOrSessionOrError = function (value, sessionKeyName, settings) {\n if (!value) {\n var userInfo = session.getCurrentUserSessionInfo();\n if (settings && settings[sessionKeyName]) {\n value = settings[sessionKeyName];\n } else if (userInfo[sessionKeyName]) {\n value = userInfo[sessionKeyName];\n } else {\n throw new Error(sessionKeyName + ' not found. Please log-in again, or specify ' + sessionKeyName + ' explicitly');\n }\n }\n return value;\n};\nvar __super = ChannelManager.prototype;\nvar EpicenterChannelManager = classFrom(ChannelManager, {\n constructor: function (options) {\n this.sessionManager = new SessionManager();\n var defaultCometOptions = this.sessionManager.getMergedOptions(options);\n\n var urlOpts = urlService(defaultCometOptions.server);\n if (!defaultCometOptions.url) {\n //Default epicenter cometd endpoint\n defaultCometOptions.url = urlOpts.protocol + '://' + urlOpts.host + '/channel/subscribe';\n }\n\n if (defaultCometOptions.handshake === undefined) {\n var userName = defaultCometOptions.userName;\n var userId = defaultCometOptions.userId;\n var token = defaultCometOptions.token;\n if ((userName || userId) && token) {\n var userProp = userName ? 'userName' : 'userId';\n var ext = {\n authorization: 'Bearer ' + token\n };\n ext[userProp] = userName ? userName : userId;\n\n defaultCometOptions.handshake = {\n ext: ext\n };\n }\n }\n\n this.options = defaultCometOptions;\n return __super.constructor.call(this, defaultCometOptions);\n },\n\n /**\n * Creates and returns a channel, that is, an instance of a [Channel Service](../channel-service/).\n *\n * This method enforces Epicenter-specific channel naming: all channels requested must be in the form `/{type}/{account id}/{project id}/{...}`, where `type` is one of `run`, `data`, `user`, `world`, or `chat`.\n *\n * **Example**\n *\n * var cm = new F.manager.EpicenterChannelManager();\n * var channel = cm.getChannel('/group/acme/supply-chain-game/');\n *\n * channel.subscribe('topic', callback);\n * channel.publish('topic', { myData: 100 });\n *\n * **Parameters**\n * @param {Object|String} `options` (Optional) If string, assumed to be the base channel url. If object, assumed to be configuration options for the constructor.\n */\n getChannel: function (options) {\n if (options && typeof options !== 'object') {\n options = {\n base: options\n };\n }\n var channelOpts = $.extend({}, this.options, options);\n var base = channelOpts.base;\n if (!base) {\n throw new Error('No base topic was provided');\n }\n\n if (!channelOpts.allowAllChannels) {\n var baseParts = base.split('/');\n var channelType = baseParts[1];\n if (baseParts.length < 4) {\n throw new Error('Invalid channel base name, it must be in the form /{type}/{account id}/{project id}/{...}');\n }\n if (!validTypes[channelType]) {\n throw new Error('Invalid channel type');\n }\n }\n return __super.getChannel.apply(this, arguments);\n },\n\n /**\n * Create and return a publish/subscribe channel (from the underlying [Channel Manager](../channel-manager/)) for the given [group](../../../glossary/#groups). The group must exist in the account (team) and project provided.\n *\n * There are no notifications from Epicenter on this channel; all messages are user-originated.\n *\n * **Example**\n *\n * var cm = new F.manager.ChannelManager();\n * var gc = cm.getGroupChannel();\n * gc.subscribe('broadcasts', callback);\n *\n * **Return Value**\n *\n * * *Channel* Returns the channel (an instance of the [Channel Service](../channel-service/)).\n *\n * **Parameters**\n *\n * @param {String} `groupName` (Optional) Group to broadcast to. If not provided, picks up group from current session if end user is logged in.\n */\n getGroupChannel: function (groupName) {\n groupName = getFromSettingsOrSessionOrError(groupName, 'groupName', this.options);\n var account = getFromSettingsOrSessionOrError('', 'account', this.options);\n var project = getFromSettingsOrSessionOrError('', 'project', this.options);\n\n var baseTopic = ['/group', account, project, groupName].join('/');\n return __super.getChannel.call(this, { base: baseTopic });\n },\n\n /**\n * Create and return a publish/subscribe channel (from the underlying [Channel Manager](../channel-manager/)) for the given [world](../../../glossary/#world).\n *\n * This is typically used together with the [World Manager](../world-manager).\n *\n * **Example**\n *\n * var cm = new F.manager.ChannelManager();\n * var worldManager = new F.manager.WorldManager({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * group: 'team1',\n * run: { model: 'model.eqn' }\n * });\n * worldManager.getCurrentWorld().then(function (worldObject, worldAdapter) {\n * var worldChannel = cm.getWorldChannel(worldObject);\n * worldChannel.subscribe('', function (data) {\n * console.log(data);\n * });\n * });\n *\n * **Return Value**\n *\n * * *Channel* Returns the channel (an instance of the [Channel Service](../channel-service/)).\n *\n * **Parameters**\n *\n * @param {String|Object} `world` The world object or id.\n * @param {String} `groupName` (Optional) Group the world exists in. If not provided, picks up group from current session if end user is logged in.\n */\n getWorldChannel: function (world, groupName) {\n var worldid = ($.isPlainObject(world) && world.id) ? world.id : world;\n if (!worldid) {\n throw new Error('Please specify a world id');\n }\n groupName = getFromSettingsOrSessionOrError(groupName, 'groupName', this.options);\n var account = getFromSettingsOrSessionOrError('', 'account', this.options);\n var project = getFromSettingsOrSessionOrError('', 'project', this.options);\n\n var baseTopic = ['/world', account, project, groupName, worldid].join('/');\n return __super.getChannel.call(this, { base: baseTopic });\n },\n\n /**\n * Create and return a publish/subscribe channel (from the underlying [Channel Manager](../channel-manager/)) for the current [end user](../../../glossary/#users) in that user's current [world](../../../glossary/#world).\n *\n * This is typically used together with the [World Manager](../world-manager). Note that this channel only gets notifications for worlds currently in memory. (See more background on [persistence](../../../run_persistence).)\n *\n * **Example**\n *\n * var cm = new F.manager.ChannelManager();\n * var worldManager = new F.manager.WorldManager({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * group: 'team1',\n * run: { model: 'model.eqn' }\n * });\n * worldManager.getCurrentWorld().then(function (worldObject, worldAdapter) {\n * var userChannel = cm.getUserChannel(worldObject);\n * userChannel.subscribe('', function (data) {\n * console.log(data);\n * });\n * });\n *\n *\n * **Return Value**\n *\n * * *Channel* Returns the channel (an instance of the [Channel Service](../channel-service/)).\n *\n * **Parameters**\n *\n * @param {String|Object} `world` World object or id.\n * @param {String|Object} `user` (Optional) User object or id. If not provided, picks up user id from current session if end user is logged in.\n * @param {String} `groupName` (Optional) Group the world exists in. If not provided, picks up group from current session if end user is logged in.\n */\n getUserChannel: function (world, user, groupName) {\n var worldid = ($.isPlainObject(world) && world.id) ? world.id : world;\n if (!worldid) {\n throw new Error('Please specify a world id');\n }\n var userid = ($.isPlainObject(user) && user.id) ? user.id : user;\n userid = getFromSettingsOrSessionOrError(userid, 'userId', this.options);\n groupName = getFromSettingsOrSessionOrError(groupName, 'groupName', this.options);\n\n var account = getFromSettingsOrSessionOrError('', 'account', this.options);\n var project = getFromSettingsOrSessionOrError('', 'project', this.options);\n\n var baseTopic = ['/user', account, project, groupName, worldid, userid].join('/');\n return __super.getChannel.call(this, { base: baseTopic });\n },\n\n /**\n * Create and return a publish/subscribe channel (from the underlying [Channel Manager](../channel-manager/)) that automatically tracks the presence of an [end user](../../../glossary/#users), that is, whether the end user is currently online in this group and world. Notifications are automatically sent when the end user comes online, and when the end user goes offline (not present for more than 2 minutes). Useful in multiplayer games for letting each end user know whether other users in their shared world are also online.\n *\n * **Example**\n *\n * var cm = new F.manager.ChannelManager();\n * var worldManager = new F.manager.WorldManager({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * model: 'model.eqn'\n * });\n * worldManager.getCurrentWorld().then(function (worldObject, worldService) {\n * var presenceChannel = cm.getPresenceChannel(worldObject);\n * presenceChannel.on('presence', function (evt, notification) {\n * console.log(notification.online, notification.userId);\n * });\n * });\n *\n *\n * **Return Value**\n *\n * * *Channel* Returns the channel (an instance of the [Channel Service](../channel-service/)).\n *\n * **Parameters**\n *\n * @param {String|Object} `world` World object or id.\n * @param {String|Object} `userid` (Optional) User object or id. If not provided, picks up user id from current session if end user is logged in.\n * @param {String} `groupName` (Optional) Group the world exists in. If not provided, picks up group from current session if end user is logged in.\n */\n getPresenceChannel: function (world, userid, groupName) {\n var worldid = ($.isPlainObject(world) && world.id) ? world.id : world;\n if (!worldid) {\n throw new Error('Please specify a world id');\n }\n userid = getFromSettingsOrSessionOrError(userid, 'userId', this.options);\n groupName = getFromSettingsOrSessionOrError(groupName, 'groupName', this.options);\n\n var account = getFromSettingsOrSessionOrError('', 'account', this.options);\n var project = getFromSettingsOrSessionOrError('', 'project', this.options);\n\n var baseTopic = ['/user', account, project, groupName, worldid].join('/');\n var channel = __super.getChannel.call(this, { base: baseTopic });\n\n var lastPingTime = { };\n\n var PING_INTERVAL = 6000;\n channel.subscribe('internal-ping-channel', function (notification) {\n var incomingUserId = notification.data.user;\n if (!lastPingTime[incomingUserId] && incomingUserId !== userid) {\n channel.trigger.call(channel, 'presence', { userId: incomingUserId, online: true });\n }\n lastPingTime[incomingUserId] = (new Date()).valueOf();\n });\n\n setInterval(function () {\n channel.publish('internal-ping-channel', { user: userid });\n\n $.each(lastPingTime, function (key, value) {\n var now = (new Date()).valueOf();\n if (value && value + (PING_INTERVAL * 2) < now) {\n lastPingTime[key] = null;\n channel.trigger.call(channel, 'presence', { userId: key, online: false });\n }\n });\n }, PING_INTERVAL);\n\n return channel;\n },\n\n /**\n * Create and return a publish/subscribe channel (from the underlying [Channel Manager](../channel-manager/)) for the given collection. (The collection name is specified in the `root` argument when the [Data Service](../data-api-service/) is instantiated.) Must be one of the collections in this account (team) and project.\n *\n * There are automatic notifications from Epicenter on this channel when data is created, updated, or deleted in this collection. See more on [automatic messages to the data channel](../../../rest_apis/multiplayer/channel/#data-messages).\n *\n * **Example**\n *\n * var cm = new F.manager.ChannelManager();\n * var dc = cm.getDataChannel('survey-responses');\n * dc.subscribe('', function(data, meta) {\n * console.log(data);\n *\n * // meta.date is time of change,\n * // meta.subType is the kind of change: new, update, or delete\n * // meta.path is the full path to the changed data\n * console.log(meta);\n * });\n *\n * **Return Value**\n *\n * * *Channel* Returns the channel (an instance of the [Channel Service](../channel-service/)).\n *\n * **Parameters**\n *\n * @param {String} `collection` Name of collection whose automatic notifications you want to receive.\n */\n getDataChannel: function (collection) {\n if (!collection) {\n throw new Error('Please specify a collection to listen on.');\n }\n var account = getFromSettingsOrSessionOrError('', 'account', this.options);\n var project = getFromSettingsOrSessionOrError('', 'project', this.options);\n var baseTopic = ['/data', account, project, collection].join('/');\n var channel = __super.getChannel.call(this, { base: baseTopic });\n\n //TODO: Fix after Epicenter bug is resolved\n var oldsubs = channel.subscribe;\n channel.subscribe = function (topic, callback, context, options) {\n var callbackWithCleanData = function (payload) {\n var meta = {\n path: payload.channel,\n subType: payload.data.subType,\n date: payload.data.date\n };\n var actualData = payload.data.data;\n if (actualData.data) { //Delete notifications are one data-level behind of course\n actualData = actualData.data;\n }\n\n callback.call(context, actualData, meta);\n };\n return oldsubs.call(channel, topic, callbackWithCleanData, context, options);\n };\n\n return channel;\n }\n});\n\nmodule.exports = EpicenterChannelManager;\n","'use strict';\n\nmodule.exports = {\n _pick: function (obj, props) {\n var res = {};\n for (var p in obj) {\n if (props.indexOf(p) !== -1) {\n res[p] = obj[p];\n }\n }\n\n return res;\n }\n};\n","'use strict';\n\nvar keyNames = require('../managers/key-names');\nvar StorageFactory = require('./store-factory');\nvar optionUtils = require('../util/option-utils');\n\nvar EPI_SESSION_KEY = keyNames.EPI_SESSION_KEY;\nvar defaults = {\n /**\n * Where to store user access tokens for temporary access. Defaults to storing in a cookie in the browser.\n * @type {string}\n */\n store: { synchronous: true }\n};\n\nvar SessionManager = function (managerOptions) {\n managerOptions = managerOptions || {};\n function getBaseOptions(overrides) {\n overrides = overrides || {};\n var libOptions = optionUtils.getOptions();\n var finalOptions = $.extend(true, {}, defaults, libOptions, managerOptions, overrides);\n return finalOptions;\n }\n\n function getStore(overrides) {\n var baseOptions = getBaseOptions(overrides);\n var storeOpts = baseOptions.store || {};\n if (storeOpts.root === undefined && baseOptions.account && baseOptions.project && !baseOptions.isLocal) {\n storeOpts.root = '/app/' + baseOptions.account + '/' + baseOptions.project;\n }\n return new StorageFactory(storeOpts);\n }\n\n var publicAPI = {\n saveSession: function (userInfo, options) {\n var serialized = JSON.stringify(userInfo);\n getStore(options).set(EPI_SESSION_KEY, serialized);\n },\n getSession: function (options) {\n // var session = getStore(options).get(EPI_SESSION_KEY) || '{}';\n // return JSON.parse(session);\n var store = getStore(options);\n var finalOpts = store.serviceOptions;\n var serialized = store.get(EPI_SESSION_KEY) || '{}';\n var session = JSON.parse(serialized);\n // If the url contains the project and account\n // validate the account and project in the session\n // and override project, groupName, groupId and isFac\n // Otherwise (i.e. localhost) use the saved session values\n var account = finalOpts.account;\n var project = finalOpts.project;\n if (account && session.account !== account) {\n // This means that the token was not used to login to the same account\n return {};\n }\n if (session.groups && account && project) {\n var group = session.groups[project] || { groupId: '', groupName: '', isFac: false };\n $.extend(session, { project: project }, group);\n }\n return session;\n },\n removeSession: function (options) {\n var store = getStore(options);\n Object.keys(keyNames).forEach(function (cookieKey) {\n var cookieName = keyNames[cookieKey];\n store.remove(cookieName);\n });\n return true;\n },\n getStore: function (options) {\n return getStore(options);\n },\n\n getMergedOptions: function () {\n var args = Array.prototype.slice.call(arguments);\n var overrides = $.extend.apply($, [true, {}].concat(args));\n var baseOptions = getBaseOptions(overrides);\n var session = this.getSession(overrides);\n\n var sessionDefaults = {\n /**\n * For projects that require authentication, pass in the user access token (defaults to empty string). If the user is already logged in to Epicenter, the user access token is already set in a cookie and automatically loaded from there. (See [more background on access tokens](../../../project_access/)).\n * @see [Authentication API Service](../auth-api-service/) for getting tokens.\n * @type {String}\n */\n //jshint camelcase: false\n //jscs:disable\n token: session.auth_token,\n /**\n * The group name. If left undefined, taken from the cookie session.\n * @type {String}\n */\n group: session.groupName,\n /**\n * The group id. If left undefined, taken from the cookie session.\n * @type {String}\n */\n groupId: session.groupId,\n userId: session.userId\n };\n return $.extend(true, sessionDefaults, baseOptions);\n }\n };\n $.extend(this, publicAPI);\n};\n\nmodule.exports = SessionManager;","'use strict';\n\nvar ConfigService = require('./configuration-service');\nvar SessionManager = require('../store/session-manager');\nvar objectAssign = require('object-assign');\n\nvar serviceUtils = {\n /*\n * Gets the default options for a api service.\n * It will merge:\n * - The Session options (Using the Session Manager)\n * - The Authorization Header from the token option\n * - The full url from the endpoint option\n * With the supplied overrides and defaults\n *\n */\n getDefaultOptions: function (defaults) {\n var rest = Array.prototype.slice.call(arguments, 1);\n var sessionManager = new SessionManager();\n var serviceOptions = sessionManager.getMergedOptions.apply(sessionManager, [defaults].concat(rest));\n\n serviceOptions.transport = objectAssign({}, serviceOptions.transport, {\n url: this.getApiUrl(serviceOptions.apiEndpoint, serviceOptions)\n });\n\n if (serviceOptions.token) {\n serviceOptions.transport.headers = {\n 'Authorization': 'Bearer ' + serviceOptions.token\n };\n }\n return serviceOptions;\n },\n\n getApiUrl: function (apiEndpoint, serviceOptions) {\n var urlConfig = new ConfigService(serviceOptions).get('server');\n return urlConfig.getAPIPath(apiEndpoint);\n }\n};\n\nmodule.exports = serviceUtils;","module.exports = {\n 'new-if-initialized': require('./new-if-initialized-strategy'),\n 'new-if-persisted': require('./new-if-persisted-strategy'),\n 'new-if-missing': require('./new-if-missing-strategy'),\n 'always-new': require('./always-new-strategy'),\n 'multiplayer': require('./multiplayer-strategy'),\n 'persistent-single-player': require('./persistent-single-player-strategy'),\n 'none': require('./identity-strategy')\n};\n","'use strict';\n\n\nmodule.exports = {\n reset: function (params, options, manager) {\n return manager.reset(options);\n }\n};\n","'use strict';\n\nvar Channel = require('../service/channel-service');\nvar SessionManager = require('../store/session-manager');\n\n/**\n * ## Channel Manager\n *\n * There are two main use cases for the channel: event notifications and chat messages.\n *\n * The Channel Manager is a wrapper around the default [cometd JavaScript library](http://docs.cometd.org/2/reference/javascript.html), `$.cometd`. It provides a few nice features that `$.cometd` doesn't, including:\n *\n * * Automatic re-subscription to channels if you lose your connection\n * * Online / Offline notifications\n * * 'Events' for cometd notifications (instead of having to listen on specific meta channels)\n *\n * While you can work directly with the Channel Manager through Node.js (for example, `require('manager/channel-manager')`) -- or even work directly with `$.cometd` and Epicenter's underlying [Push Channel API](../../../rest_apis/multiplayer/channel/) -- most often it will be easiest to work with the [Epicenter Channel Manager](../epicenter-channel-manager/). The Epicenter Channel Manager is a wrapper that instantiates a Channel Manager with Epicenter-specific defaults.\n *\n * You'll need to include the `epicenter-multiplayer-dependencies.js` library in addition to the `epicenter.js` library in your project to use the Channel Manager. (See [Including Epicenter.js](../../#include).)\n *\n * To use the Channel Manager in client-side JavaScript, instantiate the [Epicenter Channel Manager](../epicenter-channel-manager/), get the channel, then use the channel's `subscribe()` and `publish()` methods to subscribe to topics or publish data to topics.\n *\n * var cm = new F.manager.ChannelManager();\n * var channel = cm.getChannel();\n *\n * channel.subscribe('topic', callback);\n * channel.publish('topic', { myData: 100 });\n *\n * The parameters for instantiating a Channel Manager include:\n *\n * * `options` The options object to configure the Channel Manager. Besides the common options listed here, see http://docs.cometd.org/reference/javascript.html for other supported options.\n * * `options.url` The Cometd endpoint URL.\n * * `options.websocketEnabled` Whether websocket support is active (boolean).\n * * `options.channel` Other defaults to pass on to instances of the underlying Channel Service. See [Channel Service](../channel-service/) for details.\n *\n */\nvar ChannelManager = function (options) {\n if (!$.cometd) {\n throw new Error('Cometd library not found. Please include epicenter-multiplayer-dependencies.js');\n }\n if (!options || !options.url) {\n throw new Error('Please provide an url for the cometd server');\n }\n\n var defaults = {\n /**\n * The Cometd endpoint URL.\n * @type {string}\n */\n url: '',\n\n /**\n * The log level for the channel (logs to console).\n * @type {string}\n */\n logLevel: 'info',\n\n /**\n * Whether websocket support is active. Defaults to `false`; Epicenter doesn't currently support communication through websockets.\n * @type {boolean}\n */\n websocketEnabled: false,\n\n /**\n * If false each instance of Channel will have a separate cometd connection to server, which could be noisy. Set to true to re-use the same connection across instances.\n * @type {boolean}\n */\n shareConnection: false,\n\n /**\n * Other defaults to pass on to instances of the underlying [Channel Service](../channel-service/), which are created through `getChannel()`.\n * @type {object}\n */\n channel: {\n\n },\n\n /**\n * Options to pass to the channel handshake.\n *\n * For example, the [Epicenter Channel Manager](../epicenter-channel-manager/) passes `ext` and authorization information. More information on possible options is in the details of the underlying [Push Channel API](../../../rest_apis/multiplayer/channel/).\n *\n * @type {object}\n */\n handshake: undefined\n };\n this.sessionManager = new SessionManager();\n var defaultCometOptions = this.sessionManager.getMergedOptions(defaults, options);\n this.currentSubscriptions = [];\n this.options = defaultCometOptions;\n\n if (defaultCometOptions.shareConnection && ChannelManager.prototype._cometd) {\n this.cometd = ChannelManager.prototype._cometd;\n return this;\n }\n var cometd = new $.Cometd();\n ChannelManager.prototype._cometd = cometd;\n\n cometd.websocketEnabled = defaultCometOptions.websocketEnabled;\n\n this.isConnected = false;\n var connectionBroken = function (message) {\n $(this).trigger('disconnect', message);\n };\n var connectionSucceeded = function (message) {\n $(this).trigger('connect', message);\n };\n var me = this;\n\n cometd.configure(defaultCometOptions);\n\n cometd.addListener('/meta/connect', function (message) {\n var wasConnected = this.isConnected;\n this.isConnected = (message.successful === true);\n if (!wasConnected && this.isConnected) { //Connecting for the first time\n connectionSucceeded.call(this, message);\n } else if (wasConnected && !this.isConnected) { //Only throw disconnected message fro the first disconnect, not once per try\n connectionBroken.call(this, message);\n }\n }.bind(this));\n\n cometd.addListener('/meta/disconnect', connectionBroken);\n\n cometd.addListener('/meta/handshake', function (message) {\n if (message.successful) {\n //http://docs.cometd.org/reference/javascript_subscribe.html#javascript_subscribe_meta_channels\n // ^ \"dynamic subscriptions are cleared (like any other subscription) and the application needs to figure out which dynamic subscription must be performed again\"\n cometd.batch(function () {\n $(me.currentSubscriptions).each(function (index, subs) {\n cometd.resubscribe(subs);\n });\n });\n }\n });\n\n //Other interesting events for reference\n cometd.addListener('/meta/subscribe', function (message) {\n $(me).trigger('subscribe', message);\n });\n cometd.addListener('/meta/unsubscribe', function (message) {\n $(me).trigger('unsubscribe', message);\n });\n cometd.addListener('/meta/publish', function (message) {\n $(me).trigger('publish', message);\n });\n cometd.addListener('/meta/unsuccessful', function (message) {\n $(me).trigger('error', message);\n });\n\n cometd.handshake(defaultCometOptions.handshake);\n\n this.cometd = cometd;\n};\n\n\nChannelManager.prototype = $.extend(ChannelManager.prototype, {\n\n /**\n * Creates and returns a channel, that is, an instance of a [Channel Service](../channel-service/).\n *\n * **Example**\n *\n * var cm = new F.manager.ChannelManager();\n * var channel = cm.getChannel();\n *\n * channel.subscribe('topic', callback);\n * channel.publish('topic', { myData: 100 });\n *\n * **Parameters**\n * @param {Object|String} `options` (Optional) If string, assumed to be the base channel url. If object, assumed to be configuration options for the constructor.\n */\n getChannel: function (options) {\n //If you just want to pass in a string\n if (options && !$.isPlainObject(options)) {\n options = {\n base: options\n };\n }\n var defaults = {\n transport: this.cometd\n };\n var channel = new Channel($.extend(true, {}, this.options.channel, defaults, options));\n\n\n //Wrap subs and unsubs so we can use it to re-attach handlers after being disconnected\n var subs = channel.subscribe;\n channel.subscribe = function () {\n var subid = subs.apply(channel, arguments);\n this.currentSubscriptions = this.currentSubscriptions.concat(subid);\n return subid;\n }.bind(this);\n\n\n var unsubs = channel.unsubscribe;\n channel.unsubscribe = function () {\n var removed = unsubs.apply(channel, arguments);\n for (var i = 0; i < this.currentSubscriptions.length; i++) {\n if (this.currentSubscriptions[i].id === removed.id) {\n this.currentSubscriptions.splice(i, 1);\n }\n }\n return removed;\n }.bind(this);\n\n return channel;\n },\n\n /**\n * Start listening for events on this instance. Signature is same as for jQuery Events: http://api.jquery.com/on/.\n *\n * Supported events are: `connect`, `disconnect`, `subscribe`, `unsubscribe`, `publish`, `error`.\n *\n * **Parameters**\n *\n * @param {string} `event` The event type. See more detail at jQuery Events: http://api.jquery.com/on/.\n */\n on: function (event) {\n $(this).on.apply($(this), arguments);\n },\n\n /**\n * Stop listening for events on this instance. Signature is same as for jQuery Events: http://api.jquery.com/off/.\n *\n * **Parameters**\n *\n * @param {string} `event` The event type. See more detail at jQuery Events: http://api.jquery.com/off/.\n */\n off: function (event) {\n $(this).off.apply($(this), arguments);\n },\n\n /**\n * Trigger events and execute handlers. Signature is same as for jQuery Events: http://api.jquery.com/trigger/.\n *\n * **Parameters**\n *\n * @param {string} `event` The event type. See more detail at jQuery Events: http://api.jquery.com/trigger/.\n */\n trigger: function (event) {\n $(this).trigger.apply($(this), arguments);\n }\n});\n\nmodule.exports = ChannelManager;\n","'use strict';\n\nmodule.exports = {\n EPI_SESSION_KEY: 'epicenterjs.session',\n STRATEGY_SESSION_KEY: 'epicenter-scenario'\n};","/*!\n * The buffer module from node.js, for the browser.\n *\n * @author Feross Aboukhadijeh \n * @license MIT\n */\n/* eslint-disable no-proto */\n\n'use strict'\n\nvar base64 = require('base64-js')\nvar ieee754 = require('ieee754')\nvar isArray = require('isarray')\n\nexports.Buffer = Buffer\nexports.SlowBuffer = SlowBuffer\nexports.INSPECT_MAX_BYTES = 50\n\n/**\n * If `Buffer.TYPED_ARRAY_SUPPORT`:\n * === true Use Uint8Array implementation (fastest)\n * === false Use Object implementation (most compatible, even IE6)\n *\n * Browsers that support typed arrays are IE 10+, Firefox 4+, Chrome 7+, Safari 5.1+,\n * Opera 11.6+, iOS 4.2+.\n *\n * Due to various browser bugs, sometimes the Object implementation will be used even\n * when the browser supports typed arrays.\n *\n * Note:\n *\n * - Firefox 4-29 lacks support for adding new properties to `Uint8Array` instances,\n * See: https://bugzilla.mozilla.org/show_bug.cgi?id=695438.\n *\n * - Chrome 9-10 is missing the `TypedArray.prototype.subarray` function.\n *\n * - IE10 has a broken `TypedArray.prototype.subarray` function which returns arrays of\n * incorrect length in some situations.\n\n * We detect these buggy browsers and set `Buffer.TYPED_ARRAY_SUPPORT` to `false` so they\n * get the Object implementation, which is slower but behaves correctly.\n */\nBuffer.TYPED_ARRAY_SUPPORT = global.TYPED_ARRAY_SUPPORT !== undefined\n ? global.TYPED_ARRAY_SUPPORT\n : typedArraySupport()\n\n/*\n * Export kMaxLength after typed array support is determined.\n */\nexports.kMaxLength = kMaxLength()\n\nfunction typedArraySupport () {\n try {\n var arr = new Uint8Array(1)\n arr.__proto__ = {__proto__: Uint8Array.prototype, foo: function () { return 42 }}\n return arr.foo() === 42 && // typed array instances can be augmented\n typeof arr.subarray === 'function' && // chrome 9-10 lack `subarray`\n arr.subarray(1, 1).byteLength === 0 // ie10 has broken `subarray`\n } catch (e) {\n return false\n }\n}\n\nfunction kMaxLength () {\n return Buffer.TYPED_ARRAY_SUPPORT\n ? 0x7fffffff\n : 0x3fffffff\n}\n\nfunction createBuffer (that, length) {\n if (kMaxLength() < length) {\n throw new RangeError('Invalid typed array length')\n }\n if (Buffer.TYPED_ARRAY_SUPPORT) {\n // Return an augmented `Uint8Array` instance, for best performance\n that = new Uint8Array(length)\n that.__proto__ = Buffer.prototype\n } else {\n // Fallback: Return an object instance of the Buffer class\n if (that === null) {\n that = new Buffer(length)\n }\n that.length = length\n }\n\n return that\n}\n\n/**\n * The Buffer constructor returns instances of `Uint8Array` that have their\n * prototype changed to `Buffer.prototype`. Furthermore, `Buffer` is a subclass of\n * `Uint8Array`, so the returned instances will have all the node `Buffer` methods\n * and the `Uint8Array` methods. Square bracket notation works as expected -- it\n * returns a single octet.\n *\n * The `Uint8Array` prototype remains unmodified.\n */\n\nfunction Buffer (arg, encodingOrOffset, length) {\n if (!Buffer.TYPED_ARRAY_SUPPORT && !(this instanceof Buffer)) {\n return new Buffer(arg, encodingOrOffset, length)\n }\n\n // Common case.\n if (typeof arg === 'number') {\n if (typeof encodingOrOffset === 'string') {\n throw new Error(\n 'If encoding is specified then the first argument must be a string'\n )\n }\n return allocUnsafe(this, arg)\n }\n return from(this, arg, encodingOrOffset, length)\n}\n\nBuffer.poolSize = 8192 // not used by this implementation\n\n// TODO: Legacy, not needed anymore. Remove in next major version.\nBuffer._augment = function (arr) {\n arr.__proto__ = Buffer.prototype\n return arr\n}\n\nfunction from (that, value, encodingOrOffset, length) {\n if (typeof value === 'number') {\n throw new TypeError('\"value\" argument must not be a number')\n }\n\n if (typeof ArrayBuffer !== 'undefined' && value instanceof ArrayBuffer) {\n return fromArrayBuffer(that, value, encodingOrOffset, length)\n }\n\n if (typeof value === 'string') {\n return fromString(that, value, encodingOrOffset)\n }\n\n return fromObject(that, value)\n}\n\n/**\n * Functionally equivalent to Buffer(arg, encoding) but throws a TypeError\n * if value is a number.\n * Buffer.from(str[, encoding])\n * Buffer.from(array)\n * Buffer.from(buffer)\n * Buffer.from(arrayBuffer[, byteOffset[, length]])\n **/\nBuffer.from = function (value, encodingOrOffset, length) {\n return from(null, value, encodingOrOffset, length)\n}\n\nif (Buffer.TYPED_ARRAY_SUPPORT) {\n Buffer.prototype.__proto__ = Uint8Array.prototype\n Buffer.__proto__ = Uint8Array\n if (typeof Symbol !== 'undefined' && Symbol.species &&\n Buffer[Symbol.species] === Buffer) {\n // Fix subarray() in ES2016. See: https://github.com/feross/buffer/pull/97\n Object.defineProperty(Buffer, Symbol.species, {\n value: null,\n configurable: true\n })\n }\n}\n\nfunction assertSize (size) {\n if (typeof size !== 'number') {\n throw new TypeError('\"size\" argument must be a number')\n }\n}\n\nfunction alloc (that, size, fill, encoding) {\n assertSize(size)\n if (size <= 0) {\n return createBuffer(that, size)\n }\n if (fill !== undefined) {\n // Only pay attention to encoding if it's a string. This\n // prevents accidentally sending in a number that would\n // be interpretted as a start offset.\n return typeof encoding === 'string'\n ? createBuffer(that, size).fill(fill, encoding)\n : createBuffer(that, size).fill(fill)\n }\n return createBuffer(that, size)\n}\n\n/**\n * Creates a new filled Buffer instance.\n * alloc(size[, fill[, encoding]])\n **/\nBuffer.alloc = function (size, fill, encoding) {\n return alloc(null, size, fill, encoding)\n}\n\nfunction allocUnsafe (that, size) {\n assertSize(size)\n that = createBuffer(that, size < 0 ? 0 : checked(size) | 0)\n if (!Buffer.TYPED_ARRAY_SUPPORT) {\n for (var i = 0; i < size; ++i) {\n that[i] = 0\n }\n }\n return that\n}\n\n/**\n * Equivalent to Buffer(num), by default creates a non-zero-filled Buffer instance.\n * */\nBuffer.allocUnsafe = function (size) {\n return allocUnsafe(null, size)\n}\n/**\n * Equivalent to SlowBuffer(num), by default creates a non-zero-filled Buffer instance.\n */\nBuffer.allocUnsafeSlow = function (size) {\n return allocUnsafe(null, size)\n}\n\nfunction fromString (that, string, encoding) {\n if (typeof encoding !== 'string' || encoding === '') {\n encoding = 'utf8'\n }\n\n if (!Buffer.isEncoding(encoding)) {\n throw new TypeError('\"encoding\" must be a valid string encoding')\n }\n\n var length = byteLength(string, encoding) | 0\n that = createBuffer(that, length)\n\n that.write(string, encoding)\n return that\n}\n\nfunction fromArrayLike (that, array) {\n var length = checked(array.length) | 0\n that = createBuffer(that, length)\n for (var i = 0; i < length; i += 1) {\n that[i] = array[i] & 255\n }\n return that\n}\n\nfunction fromArrayBuffer (that, array, byteOffset, length) {\n array.byteLength // this throws if `array` is not a valid ArrayBuffer\n\n if (byteOffset < 0 || array.byteLength < byteOffset) {\n throw new RangeError('\\'offset\\' is out of bounds')\n }\n\n if (array.byteLength < byteOffset + (length || 0)) {\n throw new RangeError('\\'length\\' is out of bounds')\n }\n\n if (byteOffset === undefined && length === undefined) {\n array = new Uint8Array(array)\n } else if (length === undefined) {\n array = new Uint8Array(array, byteOffset)\n } else {\n array = new Uint8Array(array, byteOffset, length)\n }\n\n if (Buffer.TYPED_ARRAY_SUPPORT) {\n // Return an augmented `Uint8Array` instance, for best performance\n that = array\n that.__proto__ = Buffer.prototype\n } else {\n // Fallback: Return an object instance of the Buffer class\n that = fromArrayLike(that, array)\n }\n return that\n}\n\nfunction fromObject (that, obj) {\n if (Buffer.isBuffer(obj)) {\n var len = checked(obj.length) | 0\n that = createBuffer(that, len)\n\n if (that.length === 0) {\n return that\n }\n\n obj.copy(that, 0, 0, len)\n return that\n }\n\n if (obj) {\n if ((typeof ArrayBuffer !== 'undefined' &&\n obj.buffer instanceof ArrayBuffer) || 'length' in obj) {\n if (typeof obj.length !== 'number' || isnan(obj.length)) {\n return createBuffer(that, 0)\n }\n return fromArrayLike(that, obj)\n }\n\n if (obj.type === 'Buffer' && isArray(obj.data)) {\n return fromArrayLike(that, obj.data)\n }\n }\n\n throw new TypeError('First argument must be a string, Buffer, ArrayBuffer, Array, or array-like object.')\n}\n\nfunction checked (length) {\n // Note: cannot use `length < kMaxLength` here because that fails when\n // length is NaN (which is otherwise coerced to zero.)\n if (length >= kMaxLength()) {\n throw new RangeError('Attempt to allocate Buffer larger than maximum ' +\n 'size: 0x' + kMaxLength().toString(16) + ' bytes')\n }\n return length | 0\n}\n\nfunction SlowBuffer (length) {\n if (+length != length) { // eslint-disable-line eqeqeq\n length = 0\n }\n return Buffer.alloc(+length)\n}\n\nBuffer.isBuffer = function isBuffer (b) {\n return !!(b != null && b._isBuffer)\n}\n\nBuffer.compare = function compare (a, b) {\n if (!Buffer.isBuffer(a) || !Buffer.isBuffer(b)) {\n throw new TypeError('Arguments must be Buffers')\n }\n\n if (a === b) return 0\n\n var x = a.length\n var y = b.length\n\n for (var i = 0, len = Math.min(x, y); i < len; ++i) {\n if (a[i] !== b[i]) {\n x = a[i]\n y = b[i]\n break\n }\n }\n\n if (x < y) return -1\n if (y < x) return 1\n return 0\n}\n\nBuffer.isEncoding = function isEncoding (encoding) {\n switch (String(encoding).toLowerCase()) {\n case 'hex':\n case 'utf8':\n case 'utf-8':\n case 'ascii':\n case 'binary':\n case 'base64':\n case 'raw':\n case 'ucs2':\n case 'ucs-2':\n case 'utf16le':\n case 'utf-16le':\n return true\n default:\n return false\n }\n}\n\nBuffer.concat = function concat (list, length) {\n if (!isArray(list)) {\n throw new TypeError('\"list\" argument must be an Array of Buffers')\n }\n\n if (list.length === 0) {\n return Buffer.alloc(0)\n }\n\n var i\n if (length === undefined) {\n length = 0\n for (i = 0; i < list.length; ++i) {\n length += list[i].length\n }\n }\n\n var buffer = Buffer.allocUnsafe(length)\n var pos = 0\n for (i = 0; i < list.length; ++i) {\n var buf = list[i]\n if (!Buffer.isBuffer(buf)) {\n throw new TypeError('\"list\" argument must be an Array of Buffers')\n }\n buf.copy(buffer, pos)\n pos += buf.length\n }\n return buffer\n}\n\nfunction byteLength (string, encoding) {\n if (Buffer.isBuffer(string)) {\n return string.length\n }\n if (typeof ArrayBuffer !== 'undefined' && typeof ArrayBuffer.isView === 'function' &&\n (ArrayBuffer.isView(string) || string instanceof ArrayBuffer)) {\n return string.byteLength\n }\n if (typeof string !== 'string') {\n string = '' + string\n }\n\n var len = string.length\n if (len === 0) return 0\n\n // Use a for loop to avoid recursion\n var loweredCase = false\n for (;;) {\n switch (encoding) {\n case 'ascii':\n case 'binary':\n case 'raw':\n case 'raws':\n return len\n case 'utf8':\n case 'utf-8':\n case undefined:\n return utf8ToBytes(string).length\n case 'ucs2':\n case 'ucs-2':\n case 'utf16le':\n case 'utf-16le':\n return len * 2\n case 'hex':\n return len >>> 1\n case 'base64':\n return base64ToBytes(string).length\n default:\n if (loweredCase) return utf8ToBytes(string).length // assume utf8\n encoding = ('' + encoding).toLowerCase()\n loweredCase = true\n }\n }\n}\nBuffer.byteLength = byteLength\n\nfunction slowToString (encoding, start, end) {\n var loweredCase = false\n\n // No need to verify that \"this.length <= MAX_UINT32\" since it's a read-only\n // property of a typed array.\n\n // This behaves neither like String nor Uint8Array in that we set start/end\n // to their upper/lower bounds if the value passed is out of range.\n // undefined is handled specially as per ECMA-262 6th Edition,\n // Section 13.3.3.7 Runtime Semantics: KeyedBindingInitialization.\n if (start === undefined || start < 0) {\n start = 0\n }\n // Return early if start > this.length. Done here to prevent potential uint32\n // coercion fail below.\n if (start > this.length) {\n return ''\n }\n\n if (end === undefined || end > this.length) {\n end = this.length\n }\n\n if (end <= 0) {\n return ''\n }\n\n // Force coersion to uint32. This will also coerce falsey/NaN values to 0.\n end >>>= 0\n start >>>= 0\n\n if (end <= start) {\n return ''\n }\n\n if (!encoding) encoding = 'utf8'\n\n while (true) {\n switch (encoding) {\n case 'hex':\n return hexSlice(this, start, end)\n\n case 'utf8':\n case 'utf-8':\n return utf8Slice(this, start, end)\n\n case 'ascii':\n return asciiSlice(this, start, end)\n\n case 'binary':\n return binarySlice(this, start, end)\n\n case 'base64':\n return base64Slice(this, start, end)\n\n case 'ucs2':\n case 'ucs-2':\n case 'utf16le':\n case 'utf-16le':\n return utf16leSlice(this, start, end)\n\n default:\n if (loweredCase) throw new TypeError('Unknown encoding: ' + encoding)\n encoding = (encoding + '').toLowerCase()\n loweredCase = true\n }\n }\n}\n\n// The property is used by `Buffer.isBuffer` and `is-buffer` (in Safari 5-7) to detect\n// Buffer instances.\nBuffer.prototype._isBuffer = true\n\nfunction swap (b, n, m) {\n var i = b[n]\n b[n] = b[m]\n b[m] = i\n}\n\nBuffer.prototype.swap16 = function swap16 () {\n var len = this.length\n if (len % 2 !== 0) {\n throw new RangeError('Buffer size must be a multiple of 16-bits')\n }\n for (var i = 0; i < len; i += 2) {\n swap(this, i, i + 1)\n }\n return this\n}\n\nBuffer.prototype.swap32 = function swap32 () {\n var len = this.length\n if (len % 4 !== 0) {\n throw new RangeError('Buffer size must be a multiple of 32-bits')\n }\n for (var i = 0; i < len; i += 4) {\n swap(this, i, i + 3)\n swap(this, i + 1, i + 2)\n }\n return this\n}\n\nBuffer.prototype.toString = function toString () {\n var length = this.length | 0\n if (length === 0) return ''\n if (arguments.length === 0) return utf8Slice(this, 0, length)\n return slowToString.apply(this, arguments)\n}\n\nBuffer.prototype.equals = function equals (b) {\n if (!Buffer.isBuffer(b)) throw new TypeError('Argument must be a Buffer')\n if (this === b) return true\n return Buffer.compare(this, b) === 0\n}\n\nBuffer.prototype.inspect = function inspect () {\n var str = ''\n var max = exports.INSPECT_MAX_BYTES\n if (this.length > 0) {\n str = this.toString('hex', 0, max).match(/.{2}/g).join(' ')\n if (this.length > max) str += ' ... '\n }\n return ''\n}\n\nBuffer.prototype.compare = function compare (target, start, end, thisStart, thisEnd) {\n if (!Buffer.isBuffer(target)) {\n throw new TypeError('Argument must be a Buffer')\n }\n\n if (start === undefined) {\n start = 0\n }\n if (end === undefined) {\n end = target ? target.length : 0\n }\n if (thisStart === undefined) {\n thisStart = 0\n }\n if (thisEnd === undefined) {\n thisEnd = this.length\n }\n\n if (start < 0 || end > target.length || thisStart < 0 || thisEnd > this.length) {\n throw new RangeError('out of range index')\n }\n\n if (thisStart >= thisEnd && start >= end) {\n return 0\n }\n if (thisStart >= thisEnd) {\n return -1\n }\n if (start >= end) {\n return 1\n }\n\n start >>>= 0\n end >>>= 0\n thisStart >>>= 0\n thisEnd >>>= 0\n\n if (this === target) return 0\n\n var x = thisEnd - thisStart\n var y = end - start\n var len = Math.min(x, y)\n\n var thisCopy = this.slice(thisStart, thisEnd)\n var targetCopy = target.slice(start, end)\n\n for (var i = 0; i < len; ++i) {\n if (thisCopy[i] !== targetCopy[i]) {\n x = thisCopy[i]\n y = targetCopy[i]\n break\n }\n }\n\n if (x < y) return -1\n if (y < x) return 1\n return 0\n}\n\nfunction arrayIndexOf (arr, val, byteOffset, encoding) {\n var indexSize = 1\n var arrLength = arr.length\n var valLength = val.length\n\n if (encoding !== undefined) {\n encoding = String(encoding).toLowerCase()\n if (encoding === 'ucs2' || encoding === 'ucs-2' ||\n encoding === 'utf16le' || encoding === 'utf-16le') {\n if (arr.length < 2 || val.length < 2) {\n return -1\n }\n indexSize = 2\n arrLength /= 2\n valLength /= 2\n byteOffset /= 2\n }\n }\n\n function read (buf, i) {\n if (indexSize === 1) {\n return buf[i]\n } else {\n return buf.readUInt16BE(i * indexSize)\n }\n }\n\n var foundIndex = -1\n for (var i = byteOffset; i < arrLength; ++i) {\n if (read(arr, i) === read(val, foundIndex === -1 ? 0 : i - foundIndex)) {\n if (foundIndex === -1) foundIndex = i\n if (i - foundIndex + 1 === valLength) return foundIndex * indexSize\n } else {\n if (foundIndex !== -1) i -= i - foundIndex\n foundIndex = -1\n }\n }\n\n return -1\n}\n\nBuffer.prototype.indexOf = function indexOf (val, byteOffset, encoding) {\n if (typeof byteOffset === 'string') {\n encoding = byteOffset\n byteOffset = 0\n } else if (byteOffset > 0x7fffffff) {\n byteOffset = 0x7fffffff\n } else if (byteOffset < -0x80000000) {\n byteOffset = -0x80000000\n }\n byteOffset >>= 0\n\n if (this.length === 0) return -1\n if (byteOffset >= this.length) return -1\n\n // Negative offsets start from the end of the buffer\n if (byteOffset < 0) byteOffset = Math.max(this.length + byteOffset, 0)\n\n if (typeof val === 'string') {\n val = Buffer.from(val, encoding)\n }\n\n if (Buffer.isBuffer(val)) {\n // special case: looking for empty string/buffer always fails\n if (val.length === 0) {\n return -1\n }\n return arrayIndexOf(this, val, byteOffset, encoding)\n }\n if (typeof val === 'number') {\n if (Buffer.TYPED_ARRAY_SUPPORT && Uint8Array.prototype.indexOf === 'function') {\n return Uint8Array.prototype.indexOf.call(this, val, byteOffset)\n }\n return arrayIndexOf(this, [ val ], byteOffset, encoding)\n }\n\n throw new TypeError('val must be string, number or Buffer')\n}\n\nBuffer.prototype.includes = function includes (val, byteOffset, encoding) {\n return this.indexOf(val, byteOffset, encoding) !== -1\n}\n\nfunction hexWrite (buf, string, offset, length) {\n offset = Number(offset) || 0\n var remaining = buf.length - offset\n if (!length) {\n length = remaining\n } else {\n length = Number(length)\n if (length > remaining) {\n length = remaining\n }\n }\n\n // must be an even number of digits\n var strLen = string.length\n if (strLen % 2 !== 0) throw new Error('Invalid hex string')\n\n if (length > strLen / 2) {\n length = strLen / 2\n }\n for (var i = 0; i < length; ++i) {\n var parsed = parseInt(string.substr(i * 2, 2), 16)\n if (isNaN(parsed)) return i\n buf[offset + i] = parsed\n }\n return i\n}\n\nfunction utf8Write (buf, string, offset, length) {\n return blitBuffer(utf8ToBytes(string, buf.length - offset), buf, offset, length)\n}\n\nfunction asciiWrite (buf, string, offset, length) {\n return blitBuffer(asciiToBytes(string), buf, offset, length)\n}\n\nfunction binaryWrite (buf, string, offset, length) {\n return asciiWrite(buf, string, offset, length)\n}\n\nfunction base64Write (buf, string, offset, length) {\n return blitBuffer(base64ToBytes(string), buf, offset, length)\n}\n\nfunction ucs2Write (buf, string, offset, length) {\n return blitBuffer(utf16leToBytes(string, buf.length - offset), buf, offset, length)\n}\n\nBuffer.prototype.write = function write (string, offset, length, encoding) {\n // Buffer#write(string)\n if (offset === undefined) {\n encoding = 'utf8'\n length = this.length\n offset = 0\n // Buffer#write(string, encoding)\n } else if (length === undefined && typeof offset === 'string') {\n encoding = offset\n length = this.length\n offset = 0\n // Buffer#write(string, offset[, length][, encoding])\n } else if (isFinite(offset)) {\n offset = offset | 0\n if (isFinite(length)) {\n length = length | 0\n if (encoding === undefined) encoding = 'utf8'\n } else {\n encoding = length\n length = undefined\n }\n // legacy write(string, encoding, offset, length) - remove in v0.13\n } else {\n throw new Error(\n 'Buffer.write(string, encoding, offset[, length]) is no longer supported'\n )\n }\n\n var remaining = this.length - offset\n if (length === undefined || length > remaining) length = remaining\n\n if ((string.length > 0 && (length < 0 || offset < 0)) || offset > this.length) {\n throw new RangeError('Attempt to write outside buffer bounds')\n }\n\n if (!encoding) encoding = 'utf8'\n\n var loweredCase = false\n for (;;) {\n switch (encoding) {\n case 'hex':\n return hexWrite(this, string, offset, length)\n\n case 'utf8':\n case 'utf-8':\n return utf8Write(this, string, offset, length)\n\n case 'ascii':\n return asciiWrite(this, string, offset, length)\n\n case 'binary':\n return binaryWrite(this, string, offset, length)\n\n case 'base64':\n // Warning: maxLength not taken into account in base64Write\n return base64Write(this, string, offset, length)\n\n case 'ucs2':\n case 'ucs-2':\n case 'utf16le':\n case 'utf-16le':\n return ucs2Write(this, string, offset, length)\n\n default:\n if (loweredCase) throw new TypeError('Unknown encoding: ' + encoding)\n encoding = ('' + encoding).toLowerCase()\n loweredCase = true\n }\n }\n}\n\nBuffer.prototype.toJSON = function toJSON () {\n return {\n type: 'Buffer',\n data: Array.prototype.slice.call(this._arr || this, 0)\n }\n}\n\nfunction base64Slice (buf, start, end) {\n if (start === 0 && end === buf.length) {\n return base64.fromByteArray(buf)\n } else {\n return base64.fromByteArray(buf.slice(start, end))\n }\n}\n\nfunction utf8Slice (buf, start, end) {\n end = Math.min(buf.length, end)\n var res = []\n\n var i = start\n while (i < end) {\n var firstByte = buf[i]\n var codePoint = null\n var bytesPerSequence = (firstByte > 0xEF) ? 4\n : (firstByte > 0xDF) ? 3\n : (firstByte > 0xBF) ? 2\n : 1\n\n if (i + bytesPerSequence <= end) {\n var secondByte, thirdByte, fourthByte, tempCodePoint\n\n switch (bytesPerSequence) {\n case 1:\n if (firstByte < 0x80) {\n codePoint = firstByte\n }\n break\n case 2:\n secondByte = buf[i + 1]\n if ((secondByte & 0xC0) === 0x80) {\n tempCodePoint = (firstByte & 0x1F) << 0x6 | (secondByte & 0x3F)\n if (tempCodePoint > 0x7F) {\n codePoint = tempCodePoint\n }\n }\n break\n case 3:\n secondByte = buf[i + 1]\n thirdByte = buf[i + 2]\n if ((secondByte & 0xC0) === 0x80 && (thirdByte & 0xC0) === 0x80) {\n tempCodePoint = (firstByte & 0xF) << 0xC | (secondByte & 0x3F) << 0x6 | (thirdByte & 0x3F)\n if (tempCodePoint > 0x7FF && (tempCodePoint < 0xD800 || tempCodePoint > 0xDFFF)) {\n codePoint = tempCodePoint\n }\n }\n break\n case 4:\n secondByte = buf[i + 1]\n thirdByte = buf[i + 2]\n fourthByte = buf[i + 3]\n if ((secondByte & 0xC0) === 0x80 && (thirdByte & 0xC0) === 0x80 && (fourthByte & 0xC0) === 0x80) {\n tempCodePoint = (firstByte & 0xF) << 0x12 | (secondByte & 0x3F) << 0xC | (thirdByte & 0x3F) << 0x6 | (fourthByte & 0x3F)\n if (tempCodePoint > 0xFFFF && tempCodePoint < 0x110000) {\n codePoint = tempCodePoint\n }\n }\n }\n }\n\n if (codePoint === null) {\n // we did not generate a valid codePoint so insert a\n // replacement char (U+FFFD) and advance only 1 byte\n codePoint = 0xFFFD\n bytesPerSequence = 1\n } else if (codePoint > 0xFFFF) {\n // encode to utf16 (surrogate pair dance)\n codePoint -= 0x10000\n res.push(codePoint >>> 10 & 0x3FF | 0xD800)\n codePoint = 0xDC00 | codePoint & 0x3FF\n }\n\n res.push(codePoint)\n i += bytesPerSequence\n }\n\n return decodeCodePointsArray(res)\n}\n\n// Based on http://stackoverflow.com/a/22747272/680742, the browser with\n// the lowest limit is Chrome, with 0x10000 args.\n// We go 1 magnitude less, for safety\nvar MAX_ARGUMENTS_LENGTH = 0x1000\n\nfunction decodeCodePointsArray (codePoints) {\n var len = codePoints.length\n if (len <= MAX_ARGUMENTS_LENGTH) {\n return String.fromCharCode.apply(String, codePoints) // avoid extra slice()\n }\n\n // Decode in chunks to avoid \"call stack size exceeded\".\n var res = ''\n var i = 0\n while (i < len) {\n res += String.fromCharCode.apply(\n String,\n codePoints.slice(i, i += MAX_ARGUMENTS_LENGTH)\n )\n }\n return res\n}\n\nfunction asciiSlice (buf, start, end) {\n var ret = ''\n end = Math.min(buf.length, end)\n\n for (var i = start; i < end; ++i) {\n ret += String.fromCharCode(buf[i] & 0x7F)\n }\n return ret\n}\n\nfunction binarySlice (buf, start, end) {\n var ret = ''\n end = Math.min(buf.length, end)\n\n for (var i = start; i < end; ++i) {\n ret += String.fromCharCode(buf[i])\n }\n return ret\n}\n\nfunction hexSlice (buf, start, end) {\n var len = buf.length\n\n if (!start || start < 0) start = 0\n if (!end || end < 0 || end > len) end = len\n\n var out = ''\n for (var i = start; i < end; ++i) {\n out += toHex(buf[i])\n }\n return out\n}\n\nfunction utf16leSlice (buf, start, end) {\n var bytes = buf.slice(start, end)\n var res = ''\n for (var i = 0; i < bytes.length; i += 2) {\n res += String.fromCharCode(bytes[i] + bytes[i + 1] * 256)\n }\n return res\n}\n\nBuffer.prototype.slice = function slice (start, end) {\n var len = this.length\n start = ~~start\n end = end === undefined ? len : ~~end\n\n if (start < 0) {\n start += len\n if (start < 0) start = 0\n } else if (start > len) {\n start = len\n }\n\n if (end < 0) {\n end += len\n if (end < 0) end = 0\n } else if (end > len) {\n end = len\n }\n\n if (end < start) end = start\n\n var newBuf\n if (Buffer.TYPED_ARRAY_SUPPORT) {\n newBuf = this.subarray(start, end)\n newBuf.__proto__ = Buffer.prototype\n } else {\n var sliceLen = end - start\n newBuf = new Buffer(sliceLen, undefined)\n for (var i = 0; i < sliceLen; ++i) {\n newBuf[i] = this[i + start]\n }\n }\n\n return newBuf\n}\n\n/*\n * Need to make sure that buffer isn't trying to write out of bounds.\n */\nfunction checkOffset (offset, ext, length) {\n if ((offset % 1) !== 0 || offset < 0) throw new RangeError('offset is not uint')\n if (offset + ext > length) throw new RangeError('Trying to access beyond buffer length')\n}\n\nBuffer.prototype.readUIntLE = function readUIntLE (offset, byteLength, noAssert) {\n offset = offset | 0\n byteLength = byteLength | 0\n if (!noAssert) checkOffset(offset, byteLength, this.length)\n\n var val = this[offset]\n var mul = 1\n var i = 0\n while (++i < byteLength && (mul *= 0x100)) {\n val += this[offset + i] * mul\n }\n\n return val\n}\n\nBuffer.prototype.readUIntBE = function readUIntBE (offset, byteLength, noAssert) {\n offset = offset | 0\n byteLength = byteLength | 0\n if (!noAssert) {\n checkOffset(offset, byteLength, this.length)\n }\n\n var val = this[offset + --byteLength]\n var mul = 1\n while (byteLength > 0 && (mul *= 0x100)) {\n val += this[offset + --byteLength] * mul\n }\n\n return val\n}\n\nBuffer.prototype.readUInt8 = function readUInt8 (offset, noAssert) {\n if (!noAssert) checkOffset(offset, 1, this.length)\n return this[offset]\n}\n\nBuffer.prototype.readUInt16LE = function readUInt16LE (offset, noAssert) {\n if (!noAssert) checkOffset(offset, 2, this.length)\n return this[offset] | (this[offset + 1] << 8)\n}\n\nBuffer.prototype.readUInt16BE = function readUInt16BE (offset, noAssert) {\n if (!noAssert) checkOffset(offset, 2, this.length)\n return (this[offset] << 8) | this[offset + 1]\n}\n\nBuffer.prototype.readUInt32LE = function readUInt32LE (offset, noAssert) {\n if (!noAssert) checkOffset(offset, 4, this.length)\n\n return ((this[offset]) |\n (this[offset + 1] << 8) |\n (this[offset + 2] << 16)) +\n (this[offset + 3] * 0x1000000)\n}\n\nBuffer.prototype.readUInt32BE = function readUInt32BE (offset, noAssert) {\n if (!noAssert) checkOffset(offset, 4, this.length)\n\n return (this[offset] * 0x1000000) +\n ((this[offset + 1] << 16) |\n (this[offset + 2] << 8) |\n this[offset + 3])\n}\n\nBuffer.prototype.readIntLE = function readIntLE (offset, byteLength, noAssert) {\n offset = offset | 0\n byteLength = byteLength | 0\n if (!noAssert) checkOffset(offset, byteLength, this.length)\n\n var val = this[offset]\n var mul = 1\n var i = 0\n while (++i < byteLength && (mul *= 0x100)) {\n val += this[offset + i] * mul\n }\n mul *= 0x80\n\n if (val >= mul) val -= Math.pow(2, 8 * byteLength)\n\n return val\n}\n\nBuffer.prototype.readIntBE = function readIntBE (offset, byteLength, noAssert) {\n offset = offset | 0\n byteLength = byteLength | 0\n if (!noAssert) checkOffset(offset, byteLength, this.length)\n\n var i = byteLength\n var mul = 1\n var val = this[offset + --i]\n while (i > 0 && (mul *= 0x100)) {\n val += this[offset + --i] * mul\n }\n mul *= 0x80\n\n if (val >= mul) val -= Math.pow(2, 8 * byteLength)\n\n return val\n}\n\nBuffer.prototype.readInt8 = function readInt8 (offset, noAssert) {\n if (!noAssert) checkOffset(offset, 1, this.length)\n if (!(this[offset] & 0x80)) return (this[offset])\n return ((0xff - this[offset] + 1) * -1)\n}\n\nBuffer.prototype.readInt16LE = function readInt16LE (offset, noAssert) {\n if (!noAssert) checkOffset(offset, 2, this.length)\n var val = this[offset] | (this[offset + 1] << 8)\n return (val & 0x8000) ? val | 0xFFFF0000 : val\n}\n\nBuffer.prototype.readInt16BE = function readInt16BE (offset, noAssert) {\n if (!noAssert) checkOffset(offset, 2, this.length)\n var val = this[offset + 1] | (this[offset] << 8)\n return (val & 0x8000) ? val | 0xFFFF0000 : val\n}\n\nBuffer.prototype.readInt32LE = function readInt32LE (offset, noAssert) {\n if (!noAssert) checkOffset(offset, 4, this.length)\n\n return (this[offset]) |\n (this[offset + 1] << 8) |\n (this[offset + 2] << 16) |\n (this[offset + 3] << 24)\n}\n\nBuffer.prototype.readInt32BE = function readInt32BE (offset, noAssert) {\n if (!noAssert) checkOffset(offset, 4, this.length)\n\n return (this[offset] << 24) |\n (this[offset + 1] << 16) |\n (this[offset + 2] << 8) |\n (this[offset + 3])\n}\n\nBuffer.prototype.readFloatLE = function readFloatLE (offset, noAssert) {\n if (!noAssert) checkOffset(offset, 4, this.length)\n return ieee754.read(this, offset, true, 23, 4)\n}\n\nBuffer.prototype.readFloatBE = function readFloatBE (offset, noAssert) {\n if (!noAssert) checkOffset(offset, 4, this.length)\n return ieee754.read(this, offset, false, 23, 4)\n}\n\nBuffer.prototype.readDoubleLE = function readDoubleLE (offset, noAssert) {\n if (!noAssert) checkOffset(offset, 8, this.length)\n return ieee754.read(this, offset, true, 52, 8)\n}\n\nBuffer.prototype.readDoubleBE = function readDoubleBE (offset, noAssert) {\n if (!noAssert) checkOffset(offset, 8, this.length)\n return ieee754.read(this, offset, false, 52, 8)\n}\n\nfunction checkInt (buf, value, offset, ext, max, min) {\n if (!Buffer.isBuffer(buf)) throw new TypeError('\"buffer\" argument must be a Buffer instance')\n if (value > max || value < min) throw new RangeError('\"value\" argument is out of bounds')\n if (offset + ext > buf.length) throw new RangeError('Index out of range')\n}\n\nBuffer.prototype.writeUIntLE = function writeUIntLE (value, offset, byteLength, noAssert) {\n value = +value\n offset = offset | 0\n byteLength = byteLength | 0\n if (!noAssert) {\n var maxBytes = Math.pow(2, 8 * byteLength) - 1\n checkInt(this, value, offset, byteLength, maxBytes, 0)\n }\n\n var mul = 1\n var i = 0\n this[offset] = value & 0xFF\n while (++i < byteLength && (mul *= 0x100)) {\n this[offset + i] = (value / mul) & 0xFF\n }\n\n return offset + byteLength\n}\n\nBuffer.prototype.writeUIntBE = function writeUIntBE (value, offset, byteLength, noAssert) {\n value = +value\n offset = offset | 0\n byteLength = byteLength | 0\n if (!noAssert) {\n var maxBytes = Math.pow(2, 8 * byteLength) - 1\n checkInt(this, value, offset, byteLength, maxBytes, 0)\n }\n\n var i = byteLength - 1\n var mul = 1\n this[offset + i] = value & 0xFF\n while (--i >= 0 && (mul *= 0x100)) {\n this[offset + i] = (value / mul) & 0xFF\n }\n\n return offset + byteLength\n}\n\nBuffer.prototype.writeUInt8 = function writeUInt8 (value, offset, noAssert) {\n value = +value\n offset = offset | 0\n if (!noAssert) checkInt(this, value, offset, 1, 0xff, 0)\n if (!Buffer.TYPED_ARRAY_SUPPORT) value = Math.floor(value)\n this[offset] = (value & 0xff)\n return offset + 1\n}\n\nfunction objectWriteUInt16 (buf, value, offset, littleEndian) {\n if (value < 0) value = 0xffff + value + 1\n for (var i = 0, j = Math.min(buf.length - offset, 2); i < j; ++i) {\n buf[offset + i] = (value & (0xff << (8 * (littleEndian ? i : 1 - i)))) >>>\n (littleEndian ? i : 1 - i) * 8\n }\n}\n\nBuffer.prototype.writeUInt16LE = function writeUInt16LE (value, offset, noAssert) {\n value = +value\n offset = offset | 0\n if (!noAssert) checkInt(this, value, offset, 2, 0xffff, 0)\n if (Buffer.TYPED_ARRAY_SUPPORT) {\n this[offset] = (value & 0xff)\n this[offset + 1] = (value >>> 8)\n } else {\n objectWriteUInt16(this, value, offset, true)\n }\n return offset + 2\n}\n\nBuffer.prototype.writeUInt16BE = function writeUInt16BE (value, offset, noAssert) {\n value = +value\n offset = offset | 0\n if (!noAssert) checkInt(this, value, offset, 2, 0xffff, 0)\n if (Buffer.TYPED_ARRAY_SUPPORT) {\n this[offset] = (value >>> 8)\n this[offset + 1] = (value & 0xff)\n } else {\n objectWriteUInt16(this, value, offset, false)\n }\n return offset + 2\n}\n\nfunction objectWriteUInt32 (buf, value, offset, littleEndian) {\n if (value < 0) value = 0xffffffff + value + 1\n for (var i = 0, j = Math.min(buf.length - offset, 4); i < j; ++i) {\n buf[offset + i] = (value >>> (littleEndian ? i : 3 - i) * 8) & 0xff\n }\n}\n\nBuffer.prototype.writeUInt32LE = function writeUInt32LE (value, offset, noAssert) {\n value = +value\n offset = offset | 0\n if (!noAssert) checkInt(this, value, offset, 4, 0xffffffff, 0)\n if (Buffer.TYPED_ARRAY_SUPPORT) {\n this[offset + 3] = (value >>> 24)\n this[offset + 2] = (value >>> 16)\n this[offset + 1] = (value >>> 8)\n this[offset] = (value & 0xff)\n } else {\n objectWriteUInt32(this, value, offset, true)\n }\n return offset + 4\n}\n\nBuffer.prototype.writeUInt32BE = function writeUInt32BE (value, offset, noAssert) {\n value = +value\n offset = offset | 0\n if (!noAssert) checkInt(this, value, offset, 4, 0xffffffff, 0)\n if (Buffer.TYPED_ARRAY_SUPPORT) {\n this[offset] = (value >>> 24)\n this[offset + 1] = (value >>> 16)\n this[offset + 2] = (value >>> 8)\n this[offset + 3] = (value & 0xff)\n } else {\n objectWriteUInt32(this, value, offset, false)\n }\n return offset + 4\n}\n\nBuffer.prototype.writeIntLE = function writeIntLE (value, offset, byteLength, noAssert) {\n value = +value\n offset = offset | 0\n if (!noAssert) {\n var limit = Math.pow(2, 8 * byteLength - 1)\n\n checkInt(this, value, offset, byteLength, limit - 1, -limit)\n }\n\n var i = 0\n var mul = 1\n var sub = 0\n this[offset] = value & 0xFF\n while (++i < byteLength && (mul *= 0x100)) {\n if (value < 0 && sub === 0 && this[offset + i - 1] !== 0) {\n sub = 1\n }\n this[offset + i] = ((value / mul) >> 0) - sub & 0xFF\n }\n\n return offset + byteLength\n}\n\nBuffer.prototype.writeIntBE = function writeIntBE (value, offset, byteLength, noAssert) {\n value = +value\n offset = offset | 0\n if (!noAssert) {\n var limit = Math.pow(2, 8 * byteLength - 1)\n\n checkInt(this, value, offset, byteLength, limit - 1, -limit)\n }\n\n var i = byteLength - 1\n var mul = 1\n var sub = 0\n this[offset + i] = value & 0xFF\n while (--i >= 0 && (mul *= 0x100)) {\n if (value < 0 && sub === 0 && this[offset + i + 1] !== 0) {\n sub = 1\n }\n this[offset + i] = ((value / mul) >> 0) - sub & 0xFF\n }\n\n return offset + byteLength\n}\n\nBuffer.prototype.writeInt8 = function writeInt8 (value, offset, noAssert) {\n value = +value\n offset = offset | 0\n if (!noAssert) checkInt(this, value, offset, 1, 0x7f, -0x80)\n if (!Buffer.TYPED_ARRAY_SUPPORT) value = Math.floor(value)\n if (value < 0) value = 0xff + value + 1\n this[offset] = (value & 0xff)\n return offset + 1\n}\n\nBuffer.prototype.writeInt16LE = function writeInt16LE (value, offset, noAssert) {\n value = +value\n offset = offset | 0\n if (!noAssert) checkInt(this, value, offset, 2, 0x7fff, -0x8000)\n if (Buffer.TYPED_ARRAY_SUPPORT) {\n this[offset] = (value & 0xff)\n this[offset + 1] = (value >>> 8)\n } else {\n objectWriteUInt16(this, value, offset, true)\n }\n return offset + 2\n}\n\nBuffer.prototype.writeInt16BE = function writeInt16BE (value, offset, noAssert) {\n value = +value\n offset = offset | 0\n if (!noAssert) checkInt(this, value, offset, 2, 0x7fff, -0x8000)\n if (Buffer.TYPED_ARRAY_SUPPORT) {\n this[offset] = (value >>> 8)\n this[offset + 1] = (value & 0xff)\n } else {\n objectWriteUInt16(this, value, offset, false)\n }\n return offset + 2\n}\n\nBuffer.prototype.writeInt32LE = function writeInt32LE (value, offset, noAssert) {\n value = +value\n offset = offset | 0\n if (!noAssert) checkInt(this, value, offset, 4, 0x7fffffff, -0x80000000)\n if (Buffer.TYPED_ARRAY_SUPPORT) {\n this[offset] = (value & 0xff)\n this[offset + 1] = (value >>> 8)\n this[offset + 2] = (value >>> 16)\n this[offset + 3] = (value >>> 24)\n } else {\n objectWriteUInt32(this, value, offset, true)\n }\n return offset + 4\n}\n\nBuffer.prototype.writeInt32BE = function writeInt32BE (value, offset, noAssert) {\n value = +value\n offset = offset | 0\n if (!noAssert) checkInt(this, value, offset, 4, 0x7fffffff, -0x80000000)\n if (value < 0) value = 0xffffffff + value + 1\n if (Buffer.TYPED_ARRAY_SUPPORT) {\n this[offset] = (value >>> 24)\n this[offset + 1] = (value >>> 16)\n this[offset + 2] = (value >>> 8)\n this[offset + 3] = (value & 0xff)\n } else {\n objectWriteUInt32(this, value, offset, false)\n }\n return offset + 4\n}\n\nfunction checkIEEE754 (buf, value, offset, ext, max, min) {\n if (offset + ext > buf.length) throw new RangeError('Index out of range')\n if (offset < 0) throw new RangeError('Index out of range')\n}\n\nfunction writeFloat (buf, value, offset, littleEndian, noAssert) {\n if (!noAssert) {\n checkIEEE754(buf, value, offset, 4, 3.4028234663852886e+38, -3.4028234663852886e+38)\n }\n ieee754.write(buf, value, offset, littleEndian, 23, 4)\n return offset + 4\n}\n\nBuffer.prototype.writeFloatLE = function writeFloatLE (value, offset, noAssert) {\n return writeFloat(this, value, offset, true, noAssert)\n}\n\nBuffer.prototype.writeFloatBE = function writeFloatBE (value, offset, noAssert) {\n return writeFloat(this, value, offset, false, noAssert)\n}\n\nfunction writeDouble (buf, value, offset, littleEndian, noAssert) {\n if (!noAssert) {\n checkIEEE754(buf, value, offset, 8, 1.7976931348623157E+308, -1.7976931348623157E+308)\n }\n ieee754.write(buf, value, offset, littleEndian, 52, 8)\n return offset + 8\n}\n\nBuffer.prototype.writeDoubleLE = function writeDoubleLE (value, offset, noAssert) {\n return writeDouble(this, value, offset, true, noAssert)\n}\n\nBuffer.prototype.writeDoubleBE = function writeDoubleBE (value, offset, noAssert) {\n return writeDouble(this, value, offset, false, noAssert)\n}\n\n// copy(targetBuffer, targetStart=0, sourceStart=0, sourceEnd=buffer.length)\nBuffer.prototype.copy = function copy (target, targetStart, start, end) {\n if (!start) start = 0\n if (!end && end !== 0) end = this.length\n if (targetStart >= target.length) targetStart = target.length\n if (!targetStart) targetStart = 0\n if (end > 0 && end < start) end = start\n\n // Copy 0 bytes; we're done\n if (end === start) return 0\n if (target.length === 0 || this.length === 0) return 0\n\n // Fatal error conditions\n if (targetStart < 0) {\n throw new RangeError('targetStart out of bounds')\n }\n if (start < 0 || start >= this.length) throw new RangeError('sourceStart out of bounds')\n if (end < 0) throw new RangeError('sourceEnd out of bounds')\n\n // Are we oob?\n if (end > this.length) end = this.length\n if (target.length - targetStart < end - start) {\n end = target.length - targetStart + start\n }\n\n var len = end - start\n var i\n\n if (this === target && start < targetStart && targetStart < end) {\n // descending copy from end\n for (i = len - 1; i >= 0; --i) {\n target[i + targetStart] = this[i + start]\n }\n } else if (len < 1000 || !Buffer.TYPED_ARRAY_SUPPORT) {\n // ascending copy from start\n for (i = 0; i < len; ++i) {\n target[i + targetStart] = this[i + start]\n }\n } else {\n Uint8Array.prototype.set.call(\n target,\n this.subarray(start, start + len),\n targetStart\n )\n }\n\n return len\n}\n\n// Usage:\n// buffer.fill(number[, offset[, end]])\n// buffer.fill(buffer[, offset[, end]])\n// buffer.fill(string[, offset[, end]][, encoding])\nBuffer.prototype.fill = function fill (val, start, end, encoding) {\n // Handle string cases:\n if (typeof val === 'string') {\n if (typeof start === 'string') {\n encoding = start\n start = 0\n end = this.length\n } else if (typeof end === 'string') {\n encoding = end\n end = this.length\n }\n if (val.length === 1) {\n var code = val.charCodeAt(0)\n if (code < 256) {\n val = code\n }\n }\n if (encoding !== undefined && typeof encoding !== 'string') {\n throw new TypeError('encoding must be a string')\n }\n if (typeof encoding === 'string' && !Buffer.isEncoding(encoding)) {\n throw new TypeError('Unknown encoding: ' + encoding)\n }\n } else if (typeof val === 'number') {\n val = val & 255\n }\n\n // Invalid ranges are not set to a default, so can range check early.\n if (start < 0 || this.length < start || this.length < end) {\n throw new RangeError('Out of range index')\n }\n\n if (end <= start) {\n return this\n }\n\n start = start >>> 0\n end = end === undefined ? this.length : end >>> 0\n\n if (!val) val = 0\n\n var i\n if (typeof val === 'number') {\n for (i = start; i < end; ++i) {\n this[i] = val\n }\n } else {\n var bytes = Buffer.isBuffer(val)\n ? val\n : utf8ToBytes(new Buffer(val, encoding).toString())\n var len = bytes.length\n for (i = 0; i < end - start; ++i) {\n this[i + start] = bytes[i % len]\n }\n }\n\n return this\n}\n\n// HELPER FUNCTIONS\n// ================\n\nvar INVALID_BASE64_RE = /[^+\\/0-9A-Za-z-_]/g\n\nfunction base64clean (str) {\n // Node strips out invalid characters like \\n and \\t from the string, base64-js does not\n str = stringtrim(str).replace(INVALID_BASE64_RE, '')\n // Node converts strings with length < 2 to ''\n if (str.length < 2) return ''\n // Node allows for non-padded base64 strings (missing trailing ===), base64-js does not\n while (str.length % 4 !== 0) {\n str = str + '='\n }\n return str\n}\n\nfunction stringtrim (str) {\n if (str.trim) return str.trim()\n return str.replace(/^\\s+|\\s+$/g, '')\n}\n\nfunction toHex (n) {\n if (n < 16) return '0' + n.toString(16)\n return n.toString(16)\n}\n\nfunction utf8ToBytes (string, units) {\n units = units || Infinity\n var codePoint\n var length = string.length\n var leadSurrogate = null\n var bytes = []\n\n for (var i = 0; i < length; ++i) {\n codePoint = string.charCodeAt(i)\n\n // is surrogate component\n if (codePoint > 0xD7FF && codePoint < 0xE000) {\n // last char was a lead\n if (!leadSurrogate) {\n // no lead yet\n if (codePoint > 0xDBFF) {\n // unexpected trail\n if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD)\n continue\n } else if (i + 1 === length) {\n // unpaired lead\n if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD)\n continue\n }\n\n // valid lead\n leadSurrogate = codePoint\n\n continue\n }\n\n // 2 leads in a row\n if (codePoint < 0xDC00) {\n if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD)\n leadSurrogate = codePoint\n continue\n }\n\n // valid surrogate pair\n codePoint = (leadSurrogate - 0xD800 << 10 | codePoint - 0xDC00) + 0x10000\n } else if (leadSurrogate) {\n // valid bmp char, but last char was a lead\n if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD)\n }\n\n leadSurrogate = null\n\n // encode utf8\n if (codePoint < 0x80) {\n if ((units -= 1) < 0) break\n bytes.push(codePoint)\n } else if (codePoint < 0x800) {\n if ((units -= 2) < 0) break\n bytes.push(\n codePoint >> 0x6 | 0xC0,\n codePoint & 0x3F | 0x80\n )\n } else if (codePoint < 0x10000) {\n if ((units -= 3) < 0) break\n bytes.push(\n codePoint >> 0xC | 0xE0,\n codePoint >> 0x6 & 0x3F | 0x80,\n codePoint & 0x3F | 0x80\n )\n } else if (codePoint < 0x110000) {\n if ((units -= 4) < 0) break\n bytes.push(\n codePoint >> 0x12 | 0xF0,\n codePoint >> 0xC & 0x3F | 0x80,\n codePoint >> 0x6 & 0x3F | 0x80,\n codePoint & 0x3F | 0x80\n )\n } else {\n throw new Error('Invalid code point')\n }\n }\n\n return bytes\n}\n\nfunction asciiToBytes (str) {\n var byteArray = []\n for (var i = 0; i < str.length; ++i) {\n // Node's code seems to be doing this and not & 0x7F..\n byteArray.push(str.charCodeAt(i) & 0xFF)\n }\n return byteArray\n}\n\nfunction utf16leToBytes (str, units) {\n var c, hi, lo\n var byteArray = []\n for (var i = 0; i < str.length; ++i) {\n if ((units -= 2) < 0) break\n\n c = str.charCodeAt(i)\n hi = c >> 8\n lo = c % 256\n byteArray.push(lo)\n byteArray.push(hi)\n }\n\n return byteArray\n}\n\nfunction base64ToBytes (str) {\n return base64.toByteArray(base64clean(str))\n}\n\nfunction blitBuffer (src, dst, offset, length) {\n for (var i = 0; i < length; ++i) {\n if ((i + offset >= dst.length) || (i >= src.length)) break\n dst[i + offset] = src[i]\n }\n return i\n}\n\nfunction isnan (val) {\n return val !== val // eslint-disable-line no-self-compare\n}\n","'use strict';\n\nvar ConfigService = require('../service/configuration-service');\n\nvar urlConfig = new ConfigService().get('server');\nvar customDefaults = {};\nvar libDefaults = {\n /**\n * The account id. In the Epicenter UI, this is the **Team ID** (for team projects) or **User ID** (for personal projects). Defaults to empty string. If left undefined, taken from the URL.\n * @type {String}\n */\n account: urlConfig.accountPath,\n /**\n * The account id. In the Epicenter UI, this is the **Team ID** (for team projects) or **User ID** (for personal projects). Defaults to empty string. If left undefined, taken from the URL.\n * @type {String}\n */\n project: urlConfig.projectPath,\n isLocal: urlConfig.isLocalhost(),\n store: {}\n};\n\nvar optionUtils = {\n /**\n * Gets the final options by overriding the global options set with\n * optionUtils#setDefaults() and the lib defaults.\n * @param {object} `options` The final options object.\n */\n getOptions: function (options) {\n return $.extend(true, {}, libDefaults, customDefaults, options);\n },\n /**\n * Sets the global defaults for the optionUtils#getOptions() method.\n * @param {object} `defaults` The defaults object.\n */\n setDefaults: function (defaults) {\n customDefaults = defaults;\n }\n};\nmodule.exports = optionUtils;\n","'use strict';\n\nvar classFrom = require('../../util/inherit');\nvar IdentityStrategy = require('./identity-strategy');\nvar StorageFactory = require('../../store/store-factory');\nvar StateApi = require('../../service/state-api-adapter');\nvar AuthManager = require('../auth-manager');\n\nvar keyNames = require('../key-names');\n\nvar defaults = {\n store: {\n synchronous: true\n }\n};\n\nvar Strategy = classFrom(IdentityStrategy, {\n constructor: function Strategy(runService, options) {\n this.run = runService;\n this.options = $.extend(true, {}, defaults, options);\n this.runOptions = this.options.run;\n this._store = new StorageFactory(this.options.store);\n this.stateApi = new StateApi();\n this._auth = new AuthManager();\n\n this._loadAndCheck = this._loadAndCheck.bind(this);\n this._restoreRun = this._restoreRun.bind(this);\n this._getAllRuns = this._getAllRuns.bind(this);\n this._loadRun = this._loadRun.bind(this);\n },\n\n reset: function (runServiceOptions) {\n var session = this._auth.getCurrentUserSessionInfo();\n var opt = $.extend({\n scope: { group: session.groupName }\n }, this.runOptions);\n\n return this.run\n .create(opt, runServiceOptions)\n .then(function (run) {\n run.freshlyCreated = true;\n return run;\n });\n },\n\n getRun: function () {\n return this._getAllRuns()\n .then(this._loadAndCheck);\n },\n\n _getAllRuns: function () {\n var session = JSON.parse(this._store.get(keyNames.EPI_SESSION_KEY) || '{}');\n return this.run.query({\n 'user.id': session.userId || '0000',\n 'scope.group': session.groupName\n });\n },\n\n _loadAndCheck: function (runs) {\n if (!runs || !runs.length) {\n return this.reset();\n }\n\n var dateComp = function (a, b) { return new Date(b.date) - new Date(a.date); };\n var latestRun = runs.sort(dateComp)[0];\n var _this = this;\n var shouldReplay = false;\n\n return this.run.load(latestRun.id, null, {\n success: function (run, msg, headers) {\n shouldReplay = headers.getResponseHeader('pragma') === 'persistent';\n }\n }).then(function (run) {\n return shouldReplay ? _this._restoreRun(run.id) : run;\n });\n },\n\n _restoreRun: function (runId) {\n var _this = this;\n return this.stateApi.replay({ runId: runId })\n .then(function (resp) {\n return _this._loadRun(resp.run);\n });\n },\n\n _loadRun: function (id, options) {\n return this.run.load(id, null, options);\n }\n\n});\n\nmodule.exports = Strategy;\n","'use strict';\n\nvar classFrom = require('../../util/inherit');\n\nvar IdentityStrategy = require('./identity-strategy');\nvar WorldApiAdapter = require('../../service/world-api-adapter');\nvar AuthManager = require('../auth-manager');\n\nvar defaults = {\n store: {\n synchronous: true\n }\n};\n\nvar Strategy = classFrom(IdentityStrategy, {\n\n constructor: function (runService, options) {\n this.runService = runService;\n this.options = $.extend(true, {}, defaults, options);\n this._auth = new AuthManager();\n this._loadRun = this._loadRun.bind(this);\n this.worldApi = new WorldApiAdapter(this.options.run);\n },\n\n reset: function () {\n var session = this._auth.getCurrentUserSessionInfo();\n var curUserId = session.userId;\n var curGroupName = session.groupName;\n\n return this.worldApi\n .getCurrentWorldForUser(curUserId, curGroupName)\n .then(function (world) {\n return this.worldApi.newRunForWorld(world.id);\n }.bind(this));\n },\n\n getRun: function () {\n var session = this._auth.getCurrentUserSessionInfo();\n var curUserId = session.userId;\n var curGroupName = session.groupName;\n var worldApi = this.worldApi;\n var model = this.options.model;\n var _this = this;\n var dtd = $.Deferred();\n\n if (!curUserId) {\n return dtd.reject({ statusCode: 400, error: 'We need an authenticated user to join a multiplayer world. (ERR: no userId in session)' }, session).promise();\n }\n\n var loadRunFromWorld = function (world) {\n if (!world) {\n return dtd.reject({ statusCode: 404, error: 'The user is not in any world.' }, { options: this.options, session: session });\n }\n\n return worldApi.getCurrentRunId({ model: model, filter: world.id })\n .then(_this._loadRun)\n .then(dtd.resolve)\n .fail(dtd.reject);\n };\n\n var serverError = function (error) {\n // is this possible?\n dtd.reject(error, session, this.options);\n };\n\n this.worldApi\n .getCurrentWorldForUser(curUserId, curGroupName)\n .then(loadRunFromWorld)\n .fail(serverError);\n\n return dtd.promise();\n },\n\n _loadRun: function (id, options) {\n return this.runService.load(id, null, options);\n }\n});\n\nmodule.exports = Strategy;\n","'use strict';\n/* eslint-disable no-unused-vars */\nvar hasOwnProperty = Object.prototype.hasOwnProperty;\nvar propIsEnumerable = Object.prototype.propertyIsEnumerable;\n\nfunction toObject(val) {\n\tif (val === null || val === undefined) {\n\t\tthrow new TypeError('Object.assign cannot be called with null or undefined');\n\t}\n\n\treturn Object(val);\n}\n\nfunction shouldUseNative() {\n\ttry {\n\t\tif (!Object.assign) {\n\t\t\treturn false;\n\t\t}\n\n\t\t// Detect buggy property enumeration order in older V8 versions.\n\n\t\t// https://bugs.chromium.org/p/v8/issues/detail?id=4118\n\t\tvar test1 = new String('abc'); // eslint-disable-line\n\t\ttest1[5] = 'de';\n\t\tif (Object.getOwnPropertyNames(test1)[0] === '5') {\n\t\t\treturn false;\n\t\t}\n\n\t\t// https://bugs.chromium.org/p/v8/issues/detail?id=3056\n\t\tvar test2 = {};\n\t\tfor (var i = 0; i < 10; i++) {\n\t\t\ttest2['_' + String.fromCharCode(i)] = i;\n\t\t}\n\t\tvar order2 = Object.getOwnPropertyNames(test2).map(function (n) {\n\t\t\treturn test2[n];\n\t\t});\n\t\tif (order2.join('') !== '0123456789') {\n\t\t\treturn false;\n\t\t}\n\n\t\t// https://bugs.chromium.org/p/v8/issues/detail?id=3056\n\t\tvar test3 = {};\n\t\t'abcdefghijklmnopqrst'.split('').forEach(function (letter) {\n\t\t\ttest3[letter] = letter;\n\t\t});\n\t\tif (Object.keys(Object.assign({}, test3)).join('') !==\n\t\t\t\t'abcdefghijklmnopqrst') {\n\t\t\treturn false;\n\t\t}\n\n\t\treturn true;\n\t} catch (e) {\n\t\t// We don't expect any of the above to throw, but better to be safe.\n\t\treturn false;\n\t}\n}\n\nmodule.exports = shouldUseNative() ? Object.assign : function (target, source) {\n\tvar from;\n\tvar to = toObject(target);\n\tvar symbols;\n\n\tfor (var s = 1; s < arguments.length; s++) {\n\t\tfrom = Object(arguments[s]);\n\n\t\tfor (var key in from) {\n\t\t\tif (hasOwnProperty.call(from, key)) {\n\t\t\t\tto[key] = from[key];\n\t\t\t}\n\t\t}\n\n\t\tif (Object.getOwnPropertySymbols) {\n\t\t\tsymbols = Object.getOwnPropertySymbols(from);\n\t\t\tfor (var i = 0; i < symbols.length; i++) {\n\t\t\t\tif (propIsEnumerable.call(from, symbols[i])) {\n\t\t\t\t\tto[symbols[i]] = from[symbols[i]];\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\treturn to;\n};\n","'use strict'\n\nexports.toByteArray = toByteArray\nexports.fromByteArray = fromByteArray\n\nvar lookup = []\nvar revLookup = []\nvar Arr = typeof Uint8Array !== 'undefined' ? Uint8Array : Array\n\nfunction init () {\n var code = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'\n for (var i = 0, len = code.length; i < len; ++i) {\n lookup[i] = code[i]\n revLookup[code.charCodeAt(i)] = i\n }\n\n revLookup['-'.charCodeAt(0)] = 62\n revLookup['_'.charCodeAt(0)] = 63\n}\n\ninit()\n\nfunction toByteArray (b64) {\n var i, j, l, tmp, placeHolders, arr\n var len = b64.length\n\n if (len % 4 > 0) {\n throw new Error('Invalid string. Length must be a multiple of 4')\n }\n\n // the number of equal signs (place holders)\n // if there are two placeholders, than the two characters before it\n // represent one byte\n // if there is only one, then the three characters before it represent 2 bytes\n // this is just a cheap hack to not do indexOf twice\n placeHolders = b64[len - 2] === '=' ? 2 : b64[len - 1] === '=' ? 1 : 0\n\n // base64 is 4/3 + up to two characters of the original data\n arr = new Arr(len * 3 / 4 - placeHolders)\n\n // if there are placeholders, only get up to the last complete 4 chars\n l = placeHolders > 0 ? len - 4 : len\n\n var L = 0\n\n for (i = 0, j = 0; i < l; i += 4, j += 3) {\n tmp = (revLookup[b64.charCodeAt(i)] << 18) | (revLookup[b64.charCodeAt(i + 1)] << 12) | (revLookup[b64.charCodeAt(i + 2)] << 6) | revLookup[b64.charCodeAt(i + 3)]\n arr[L++] = (tmp >> 16) & 0xFF\n arr[L++] = (tmp >> 8) & 0xFF\n arr[L++] = tmp & 0xFF\n }\n\n if (placeHolders === 2) {\n tmp = (revLookup[b64.charCodeAt(i)] << 2) | (revLookup[b64.charCodeAt(i + 1)] >> 4)\n arr[L++] = tmp & 0xFF\n } else if (placeHolders === 1) {\n tmp = (revLookup[b64.charCodeAt(i)] << 10) | (revLookup[b64.charCodeAt(i + 1)] << 4) | (revLookup[b64.charCodeAt(i + 2)] >> 2)\n arr[L++] = (tmp >> 8) & 0xFF\n arr[L++] = tmp & 0xFF\n }\n\n return arr\n}\n\nfunction tripletToBase64 (num) {\n return lookup[num >> 18 & 0x3F] + lookup[num >> 12 & 0x3F] + lookup[num >> 6 & 0x3F] + lookup[num & 0x3F]\n}\n\nfunction encodeChunk (uint8, start, end) {\n var tmp\n var output = []\n for (var i = start; i < end; i += 3) {\n tmp = (uint8[i] << 16) + (uint8[i + 1] << 8) + (uint8[i + 2])\n output.push(tripletToBase64(tmp))\n }\n return output.join('')\n}\n\nfunction fromByteArray (uint8) {\n var tmp\n var len = uint8.length\n var extraBytes = len % 3 // if we have 1 byte left, pad 2 bytes\n var output = ''\n var parts = []\n var maxChunkLength = 16383 // must be multiple of 3\n\n // go through the array every three bytes, we'll deal with trailing stuff later\n for (var i = 0, len2 = len - extraBytes; i < len2; i += maxChunkLength) {\n parts.push(encodeChunk(uint8, i, (i + maxChunkLength) > len2 ? len2 : (i + maxChunkLength)))\n }\n\n // pad the end with zeros, but make sure to not forget the extra bytes\n if (extraBytes === 1) {\n tmp = uint8[len - 1]\n output += lookup[tmp >> 2]\n output += lookup[(tmp << 4) & 0x3F]\n output += '=='\n } else if (extraBytes === 2) {\n tmp = (uint8[len - 2] << 8) + (uint8[len - 1])\n output += lookup[tmp >> 10]\n output += lookup[(tmp >> 4) & 0x3F]\n output += lookup[(tmp << 2) & 0x3F]\n output += '='\n }\n\n parts.push(output)\n\n return parts.join('')\n}\n","exports.read = function (buffer, offset, isLE, mLen, nBytes) {\n var e, m\n var eLen = nBytes * 8 - mLen - 1\n var eMax = (1 << eLen) - 1\n var eBias = eMax >> 1\n var nBits = -7\n var i = isLE ? (nBytes - 1) : 0\n var d = isLE ? -1 : 1\n var s = buffer[offset + i]\n\n i += d\n\n e = s & ((1 << (-nBits)) - 1)\n s >>= (-nBits)\n nBits += eLen\n for (; nBits > 0; e = e * 256 + buffer[offset + i], i += d, nBits -= 8) {}\n\n m = e & ((1 << (-nBits)) - 1)\n e >>= (-nBits)\n nBits += mLen\n for (; nBits > 0; m = m * 256 + buffer[offset + i], i += d, nBits -= 8) {}\n\n if (e === 0) {\n e = 1 - eBias\n } else if (e === eMax) {\n return m ? NaN : ((s ? -1 : 1) * Infinity)\n } else {\n m = m + Math.pow(2, mLen)\n e = e - eBias\n }\n return (s ? -1 : 1) * m * Math.pow(2, e - mLen)\n}\n\nexports.write = function (buffer, value, offset, isLE, mLen, nBytes) {\n var e, m, c\n var eLen = nBytes * 8 - mLen - 1\n var eMax = (1 << eLen) - 1\n var eBias = eMax >> 1\n var rt = (mLen === 23 ? Math.pow(2, -24) - Math.pow(2, -77) : 0)\n var i = isLE ? 0 : (nBytes - 1)\n var d = isLE ? 1 : -1\n var s = value < 0 || (value === 0 && 1 / value < 0) ? 1 : 0\n\n value = Math.abs(value)\n\n if (isNaN(value) || value === Infinity) {\n m = isNaN(value) ? 1 : 0\n e = eMax\n } else {\n e = Math.floor(Math.log(value) / Math.LN2)\n if (value * (c = Math.pow(2, -e)) < 1) {\n e--\n c *= 2\n }\n if (e + eBias >= 1) {\n value += rt / c\n } else {\n value += rt * Math.pow(2, 1 - eBias)\n }\n if (value * c >= 2) {\n e++\n c /= 2\n }\n\n if (e + eBias >= eMax) {\n m = 0\n e = eMax\n } else if (e + eBias >= 1) {\n m = (value * c - 1) * Math.pow(2, mLen)\n e = e + eBias\n } else {\n m = value * Math.pow(2, eBias - 1) * Math.pow(2, mLen)\n e = 0\n }\n }\n\n for (; mLen >= 8; buffer[offset + i] = m & 0xff, i += d, m /= 256, mLen -= 8) {}\n\n e = (e << mLen) | m\n eLen += mLen\n for (; eLen > 0; buffer[offset + i] = e & 0xff, i += d, e /= 256, eLen -= 8) {}\n\n buffer[offset + i - d] |= s * 128\n}\n","var toString = {}.toString;\n\nmodule.exports = Array.isArray || function (arr) {\n return toString.call(arr) == '[object Array]';\n};\n"]} +======= +{"version":3,"sources":["node_modules/browser-pack/_prelude.js","src/api-version.json","src/app.js","src/env-load.js","src/util/query-util.js","src/util/make-sequence.js","src/util/run-util.js","src/util/inherit.js","src/transport/http-transport-factory.js","src/transport/ajax-http-transport.js","src/service/url-config-service.js","src/service/configuration-service.js","src/service/run-api-service.js","src/service/admin-file-service.js","src/service/variables-api-service.js","src/service/auth-api-service.js","src/service/data-api-service.js","src/service/state-api-adapter.js","src/service/world-api-adapter.js","src/service/user-api-adapter.js","src/service/member-api-adapter.js","src/service/asset-api-adapter.js","src/store/cookie-store.js","src/store/store-factory.js","src/managers/scenario-manager.js","src/managers/run-manager.js","src/managers/auth-manager.js","src/managers/world-manager.js","src/managers/epicenter-channel-manager.js","src/service/channel-service.js","src/managers/run-strategies/always-new-strategy.js","src/managers/run-strategies/conditional-creation-strategy.js","src/managers/run-strategies/identity-strategy.js","src/managers/run-strategies/new-if-missing-strategy.js","src/managers/run-strategies/new-if-persisted-strategy.js","src/managers/run-strategies/new-if-initialized-strategy.js","src/util/object-util.js","src/service/introspection-api-service.js","src/store/session-manager.js","src/managers/special-operations.js","src/managers/run-strategies/strategies-map.js","node_modules/buffer/index.js","src/managers/channel-manager.js","src/managers/key-names.js","src/util/option-utils.js","src/managers/run-strategies/multiplayer-strategy.js","src/managers/run-strategies/persistent-single-player-strategy.js","node_modules/isarray/index.js","node_modules/ieee754/index.js","node_modules/base64-js/lib/b64.js"],"names":["F","util","factory","transport","store","service","manager","strategy","load","require","query","makeSequence","run","classFrom","Transport","Ajax","URL","Config","Run","File","Variables","Data","Auth","World","State","User","Member","Asset","Cookie","Store","ScenarioManager","RunManager","AuthManager","WorldManager","identity","ChannelManager","Channel","version","api","global","module","exports","urlConfigService","envLoad","callback","envPromise","host","urlService","envPath","isLocalhost","infoUrl","$","ajax","url","async","done","res","extend","fail","protocol","toMatrixFormat","qs","undefined","String","returnArray","OPERATORS","each","key","value","inArray","trim","charAt","push","mtrx","join","toQueryFormat","isArray","isPlainObject","JSON","stringify","result","qsToObject","qsArray","split","returnObj","index","qKey","qVal","indexOf","mergeQS","qs1","qs2","obj1","this","obj2","addTrailingSlash","length","_w","val","then","p","Deferred","resolve","promise","seq","next","cur","list","splice","Array","prototype","slice","apply","arguments","seed","MakeSeq","obj","__calls","original","fn","start","_this","funcMaker","bind","args","Function","concat","prop","qutil","MAX_URL_LENGTH","normalizeOperations","operations","returnList","ops","_concat","arr","_normalizePlainObjects","opn","arg","_normalizeStructuredObjects","operation","name","params","_normalizeObject","_normalizeLiterals","_normalizeArrays","splitGetFactory","httpOptions","options","http","getValue","getFinalUrl","data","replace","queryParams","questionIdx","include","encodeURI","dtd","paramsCopy","urlNoIncludes","diff","oldSuccess","success","noop","oldError","error","currIncludes","includeOpts","currLength","encodeURIComponent","variable","pop","varLenght","reqs","map","reqParams","get","when","isValid","reject","firstResponse","isObject","isRunAPI","variables","aggregateRun","idx","aggregatedRuns","runs","idxRun","id","aggregatedVariables","vars","inherit","C","P","__super","constructor","dest","call","current","j","base","props","staticProps","parent","child","hasOwnProperty","qutils","config","defaults","contentType","headers","statusCode","404","parameterParser","xhrFields","withCredentials","transportOptions","d","isFunction","connect","method","connectOptions","type","ALLOWED_TO_BE_FUNCTIONS","logLevel","console","log","oldSuccessFn","response","ajaxStatus","ajaxReq","beforeSend","xhr","settings","requestUrl","publicAPI","ajaxOptions","splitGet","post","patch","put","delete","delimiter","head","epiVersion","window","location","pathname","UrlConfigService","path","API_PROTOCOL","HOST_API_MAPPING","forio.com","foriodev.com","publicExports","appPath","accountPath","accnt","projectPath","prj","versionPath","getAPIPath","PROJECT_APIS","apiPath","envConf","serviceOptions","server","setEnv","env","property","set","ConfigService","rutil","_pick","TransportFactory","VariablesService","IntrospectionService","SessionManager","token","account","project","filter","autoRestore","sessionManager","getMergedOptions","urlConfig","getFilterURL","addAutoRestoreHeader","isFilterRunId","autorestoreOpts","X-AutoRestore","Authorization","setFilterOrThrowError","Error","publicAsyncAPI","create","createOptions","runApiParams","model","outputModifier","runID","filters","save","attributes","do","opsArgs","postOptions","prms","serial","opParams","me","$d","doSingleOp","op","shift","parallel","queue","i","publicSyncAPI","getCurrentConfig","vs","runService","introspection","folderType","getContents","filePath","writeToFile","contents","fileName","boundary","body","remove","rename","newName","getURL","attrs","userName","password","login","resp","status","statusMessage","postParams","logout","root","q","saveAs","keys","apiEndpoint","parseRunIdOrError","runId","replay","replayOptions","action","clone","apiBase","assignmentEndpoint","projectEndpoint","group","setIdFilterOrThrowError","validateModelOrThrowError","worldApiParams","validParams","update","whitelist","updateOptions","deleteOptions","updateConfig","getOptions","getWorldsForUser","userId","worldId","addUsers","users","u","updateUser","user","patchOptions","removeUser","getCurrentRunId","getCurrentWorldForUser","groupName","worlds","sort","a","b","Date","lastModified","currentWorld","deleteRun","newRunForWorld","currentRunOptions","autoAssign","opt","maxUsers","getProjectSettings","toQFilter","toIdFilters","getFilters","threshold","getById","groupId","getFinalParams","patchUserActiveField","active","getGroupsForUser","isString","objParams","getParms","getGroupDetails","makeUserActive","makeUserInactive","scope","fullUrl","processData","assetApiParams","scopeConfig","validateFilename","filename","validateUrlParams","partKeys","buildUrl","parts","upload","toLowerCase","FormData","urlOptions","getServiceOptions","files","fullPathFiles","file","assetUrl","document","cookie","newCookie","hostname","domain","setOptions","cookieReg","RegExp","exec","decodeURIComponent","remOptions","destroy","aKeys","nIdx","cookieKey","RunService","validFilter","saved","getRuns","loadVariables","meta","_getService","archive","getRun","patchRunService","patched","orig","reservedOps","Object","specialOperations","StrategyCtor","strategiesMap","reset","runServiceOptions","isLocal","authAdapter","AuthAdapter","MemberAdapter","Buffer","requiresGroup","_findUserInGroup","members","adapterOptions","outSuccess","outError","decodeToken","encoded","decode","atob","toString","parse","handleGroupError","message","statusText","handleSuccess","access_token","userInfo","oldGroups","getSession","groups","userGroupOpts","auth","isTeamMember","parent_account_id","sessionInfo","auth_token","user_id","getUserGroups","memberInfo","userGroups","filteredGroups","grep","resGroup","groupData","isFac","role","sessionInfoWithGroup","saveSession","removeCookieFn","removeSession","getToken","session","memberAdapter","getCurrentUserSessionInfo","addGroups","extendedGroup","validProps","buildStrategy","worldApi","WorldApi","world","_auth","getCurrentWorld","getCurrentRun","getAndRestoreLatestRun","currentWorldId","runOpts","rm","curUserId","curGroupName","validTypes","general","chat","getFromSettingsOrSessionOrError","sessionKeyName","EpicenterChannelManager","defaultCometOptions","urlOpts","handshake","userProp","ext","authorization","getChannel","channelOpts","allowAllChannels","baseParts","channelType","getGroupChannel","baseTopic","getWorldChannel","worldid","getUserChannel","userid","getPresenceChannel","channel","lastPingTime","PING_INTERVAL","subscribe","notification","incomingUserId","trigger","online","valueOf","setInterval","publish","now","getDataChannel","collection","oldsubs","topic","context","callbackWithCleanData","payload","subType","date","actualData","topicResolver","channelOptions","makeName","channelName","topics","subscriptionIds","opts","batch","returnObjs","warn","unsubscribe","on","event","off","ConditionalStrategy","Strategy","createIf","setRunInSession","sessionKey","sessionStore","makeSeq","Base","SessionStore","UrlService","keyNames","STRATEGY_SESSION_KEY","condition","runOptions","runOptionsWithScope","userSession","freshlyCreated","runSession","_loadAndCheck","shouldCreate","msg","getResponseHeader","initialized","commandWrapper","command","introspect","reanimate","StorageFactory","optionUtils","EPI_SESSION_KEY","synchronous","managerOptions","getBaseOptions","overrides","libOptions","finalOptions","getStore","baseOptions","storeOpts","serialized","finalOpts","sessionDefaults","new-if-initialized","new-if-persisted","new-if-missing","always-new","multiplayer","persistent-single-player","none","typedArraySupport","Uint8Array","__proto__","foo","subarray","byteLength","e","kMaxLength","TYPED_ARRAY_SUPPORT","createBuffer","that","RangeError","encodingOrOffset","allocUnsafe","from","TypeError","ArrayBuffer","fromArrayBuffer","fromString","fromObject","assertSize","size","alloc","fill","encoding","checked","string","isEncoding","write","fromArrayLike","array","byteOffset","isBuffer","len","copy","buffer","isnan","SlowBuffer","isView","loweredCase","utf8ToBytes","base64ToBytes","slowToString","end","hexSlice","utf8Slice","asciiSlice","binarySlice","base64Slice","utf16leSlice","swap","n","m","arrayIndexOf","read","buf","indexSize","readUInt16BE","arrLength","valLength","foundIndex","hexWrite","offset","Number","remaining","strLen","parsed","parseInt","substr","isNaN","utf8Write","blitBuffer","asciiWrite","asciiToBytes","binaryWrite","base64Write","ucs2Write","utf16leToBytes","base64","fromByteArray","Math","min","firstByte","codePoint","bytesPerSequence","secondByte","thirdByte","fourthByte","tempCodePoint","decodeCodePointsArray","codePoints","MAX_ARGUMENTS_LENGTH","fromCharCode","ret","out","toHex","bytes","checkOffset","checkInt","max","objectWriteUInt16","littleEndian","objectWriteUInt32","checkIEEE754","writeFloat","noAssert","ieee754","writeDouble","base64clean","str","stringtrim","INVALID_BASE64_RE","units","Infinity","leadSurrogate","charCodeAt","byteArray","c","hi","lo","toByteArray","src","dst","INSPECT_MAX_BYTES","poolSize","_augment","Symbol","species","defineProperty","configurable","allocUnsafeSlow","_isBuffer","compare","x","y","pos","swap16","swap32","equals","inspect","match","target","thisStart","thisEnd","thisCopy","targetCopy","includes","isFinite","toJSON","_arr","newBuf","sliceLen","readUIntLE","mul","readUIntBE","readUInt8","readUInt16LE","readUInt32LE","readUInt32BE","readIntLE","pow","readIntBE","readInt8","readInt16LE","readInt16BE","readInt32LE","readInt32BE","readFloatLE","readFloatBE","readDoubleLE","readDoubleBE","writeUIntLE","maxBytes","writeUIntBE","writeUInt8","floor","writeUInt16LE","writeUInt16BE","writeUInt32LE","writeUInt32BE","writeIntLE","limit","sub","writeIntBE","writeInt8","writeInt16LE","writeInt16BE","writeInt32LE","writeInt32BE","writeFloatLE","writeFloatBE","writeDoubleLE","writeDoubleBE","targetStart","code","cometd","websocketEnabled","shareConnection","currentSubscriptions","_cometd","Cometd","isConnected","connectionBroken","connectionSucceeded","configure","addListener","wasConnected","successful","subs","resubscribe","subid","unsubs","removed","customDefaults","libDefaults","setDefaults","IdentityStrategy","WorldApiAdapter","_loadRun","loadRunFromWorld","serverError","StateApi","_store","stateApi","_restoreRun","_getAllRuns","user.id","scope.group","dateComp","latestRun","shouldReplay","isLE","mLen","nBytes","eLen","eMax","eBias","nBits","s","NaN","rt","abs","LN2","init","lookup","revLookup","b64","l","tmp","placeHolders","Arr","L","tripletToBase64","num","encodeChunk","uint8","output","extraBytes","maxChunkLength","len2"],"mappings":"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","file":"bundle.js","sourcesContent":["(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require==\"function\"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error(\"Cannot find module '\"+o+\"'\");throw f.code=\"MODULE_NOT_FOUND\",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require==\"function\"&&require;for(var o=0;o\n * https://github.com/forio/epicenter-js-libs\n */\n\nvar F = {\n util: {},\n factory: {},\n transport: {},\n store: {},\n service: {},\n manager: {\n strategy: {}\n },\n\n};\n\nF.load = require('./env-load');\nF.load();\n\nF.util.query = require('./util/query-util');\nF.util.makeSequence = require('./util/make-sequence');\nF.util.run = require('./util/run-util');\nF.util.classFrom = require('./util/inherit');\n\nF.factory.Transport = require('./transport/http-transport-factory');\nF.transport.Ajax = require('./transport/ajax-http-transport');\n\nF.service.URL = require('./service/url-config-service');\nF.service.Config = require('./service/configuration-service');\nF.service.Run = require('./service/run-api-service');\nF.service.File = require('./service/admin-file-service');\nF.service.Variables = require('./service/variables-api-service');\nF.service.Data = require('./service/data-api-service');\nF.service.Auth = require('./service/auth-api-service');\nF.service.World = require('./service/world-api-adapter');\nF.service.State = require('./service/state-api-adapter');\nF.service.User = require('./service/user-api-adapter');\nF.service.Member = require('./service/member-api-adapter');\nF.service.Asset = require('./service/asset-api-adapter');\n\nF.store.Cookie = require('./store/cookie-store');\nF.factory.Store = require('./store/store-factory');\n\nF.manager.ScenarioManager = require('./managers/scenario-manager');\nF.manager.RunManager = require('./managers/run-manager');\nF.manager.AuthManager = require('./managers/auth-manager');\nF.manager.WorldManager = require('./managers/world-manager');\n\nF.manager.strategy['always-new'] = require('./managers/run-strategies/always-new-strategy');\nF.manager.strategy['conditional-creation'] = require('./managers/run-strategies/conditional-creation-strategy');\nF.manager.strategy.identity = require('./managers/run-strategies/identity-strategy');\nF.manager.strategy['new-if-missing'] = require('./managers/run-strategies/new-if-missing-strategy');\nF.manager.strategy['new-if-missing'] = require('./managers/run-strategies/new-if-missing-strategy');\nF.manager.strategy['new-if-persisted'] = require('./managers/run-strategies/new-if-persisted-strategy');\nF.manager.strategy['new-if-initialized'] = require('./managers/run-strategies/new-if-initialized-strategy');\n\nF.manager.ChannelManager = require('./managers/epicenter-channel-manager');\nF.service.Channel = require('./service/channel-service');\n\nF.version = '<%= version %>';\nF.api = require('./api-version.json');\n\nglobal.F = F;\nmodule.exports = F;\n","'use strict';\n\nvar urlConfigService = require('./service/url-config-service');\n\nvar envLoad = function (callback) {\n var envPromise;\n var host;\n var urlService = urlConfigService();\n var envPath = '/epicenter/v1/config';\n if (urlService.isLocalhost()) {\n host = 'https://forio.com';\n } else {\n host = '';\n }\n var infoUrl = host + envPath;\n envPromise = $.ajax({ url: infoUrl, async: false });\n envPromise.done(function (res) {\n var api = res.api;\n $.extend(urlConfigService, api);\n }).fail(function (res) {\n // Epicenter/webserver not properly configured\n // fallback to api.forio.com\n $.extend(urlConfigService, { protocol: 'https', host: 'api.forio.com' });\n });\n return envPromise.done(callback).fail(callback);\n};\n\nmodule.exports = envLoad;\n","/**\n * Utilities for working with query strings\n*/\n'use strict';\n\nmodule.exports = (function () {\n\n return {\n /**\n * Converts to matrix format\n * @param {Object} qs Object to convert to query string\n * @return { string} Matrix-format query parameters\n */\n toMatrixFormat: function (qs) {\n if (qs === null || qs === undefined || qs === '') {\n return ';';\n }\n if (typeof qs === 'string' || qs instanceof String) {\n return qs;\n }\n\n var returnArray = [];\n var OPERATORS = ['<', '>', '!'];\n $.each(qs, function (key, value) {\n if (typeof value !== 'string' || $.inArray($.trim(value).charAt(0), OPERATORS) === -1) {\n value = '=' + value;\n }\n returnArray.push(key + value);\n });\n\n var mtrx = ';' + returnArray.join(';');\n return mtrx;\n },\n\n /**\n * Converts strings/arrays/objects to type 'a=b&b=c'\n * @param { string|Array|Object} qs\n * @return { string}\n */\n toQueryFormat: function (qs) {\n if (qs === null || qs === undefined) {\n return '';\n }\n if (typeof qs === 'string' || qs instanceof String) {\n return qs;\n }\n\n var returnArray = [];\n $.each(qs, function (key, value) {\n if ($.isArray(value)) {\n value = value.join(',');\n }\n if ($.isPlainObject(value)) {\n //Mostly for data api\n value = JSON.stringify(value);\n }\n returnArray.push(key + '=' + value);\n });\n\n var result = returnArray.join('&');\n return result;\n },\n\n /**\n * Converts strings of type 'a=b&b=c' to { a:b, b:c}\n * @param { string} qs\n * @return {object}\n */\n qsToObject: function (qs) {\n if (qs === null || qs === undefined || qs === '') {\n return {};\n }\n\n var qsArray = qs.split('&');\n var returnObj = {};\n $.each(qsArray, function (index, value) {\n var qKey = value.split('=')[0];\n var qVal = value.split('=')[1];\n\n if (qVal.indexOf(',') !== -1) {\n qVal = qVal.split(',');\n }\n\n returnObj[qKey] = qVal;\n });\n\n return returnObj;\n },\n\n /**\n * Normalizes and merges strings of type 'a=b', { b:c} to { a:b, b:c}\n * @param { string|Array|Object} qs1\n * @param { string|Array|Object} qs2\n * @return {Object}\n */\n mergeQS: function (qs1, qs2) {\n var obj1 = this.qsToObject(this.toQueryFormat(qs1));\n var obj2 = this.qsToObject(this.toQueryFormat(qs2));\n return $.extend(true, {}, obj1, obj2);\n },\n\n addTrailingSlash: function (url) {\n if (!url) {\n return '';\n }\n return (url.charAt(url.length - 1) === '/') ? url : (url + '/');\n }\n };\n}());\n\n\n\n","'use strict';\n/*jshint loopfunc:false */\n\nfunction _w(val) {\n if (val && val.then) {\n return val;\n }\n var p = $.Deferred();\n p.resolve(val);\n\n return p.promise();\n}\n\nfunction seq() {\n var list = Array.prototype.slice.apply(arguments);\n\n function next(p) {\n var cur = list.splice(0,1)[0];\n\n if (!cur) {\n return p;\n }\n\n return _w(cur(p)).then(next);\n }\n\n return function (seed) {\n return next(seed).fail(seq.fail);\n };\n}\n\nfunction MakeSeq(obj) {\n var res = {\n __calls: [],\n\n original: obj,\n\n then: function (fn) {\n this.__calls.push(fn);\n return this;\n },\n\n start: function () {\n var _this = this;\n\n // clean up\n this.then(function (run) {\n _this.__calls.length = 0;\n return run;\n });\n\n return seq.apply(null, this.__calls)();\n },\n\n fail: function (fn) {\n seq.fail = fn;\n return this;\n }\n };\n\n var funcMaker = function (p, obj) {\n var fn = obj[p].bind(obj);\n return function () {\n var args = Array.prototype.slice.apply(arguments);\n this.__calls.push(Function.bind.apply(fn, [null].concat(args)));\n return this;\n };\n };\n\n for (var prop in obj) {\n if (typeof obj[prop] === 'function') {\n res[prop] = funcMaker(prop, obj);\n } else {\n res[prop] = obj[prop];\n }\n }\n\n return res;\n}\n\nmodule.exports = MakeSeq;\n","/**\n * Utilities for working with the run service\n*/\n'use strict';\nvar qutil = require('./query-util');\nvar MAX_URL_LENGTH = 2048;\n\nmodule.exports = (function () {\n return {\n /**\n * returns operations of the form `[[op1,op2], [arg1, arg2]]`\n * @param {Object|Array|String} `operations` operations to perform\n * @param {Array} `args` arguments for operation\n * @return {String} Matrix-format query parameters\n */\n normalizeOperations: function (operations, args) {\n if (!args) {\n args = [];\n }\n var returnList = {\n ops: [],\n args: []\n };\n\n var _concat = function (arr) {\n return (arr !== null && arr !== undefined) ? [].concat(arr) : [];\n };\n\n //{ add: [1,2], subtract: [2,4] }\n var _normalizePlainObjects = function (operations, returnList) {\n if (!returnList) {\n returnList = { ops: [], args: [] };\n }\n $.each(operations, function (opn, arg) {\n returnList.ops.push(opn);\n returnList.args.push(_concat(arg));\n });\n return returnList;\n };\n //{ name: 'add', params: [1] }\n var _normalizeStructuredObjects = function (operation, returnList) {\n if (!returnList) {\n returnList = { ops: [], args: [] };\n }\n returnList.ops.push(operation.name);\n returnList.args.push(_concat(operation.params));\n return returnList;\n };\n\n var _normalizeObject = function (operation, returnList) {\n return ((operation.name) ? _normalizeStructuredObjects : _normalizePlainObjects)(operation, returnList);\n };\n\n var _normalizeLiterals = function (operation, args, returnList) {\n if (!returnList) {\n returnList = { ops: [], args: [] };\n }\n returnList.ops.push(operation);\n returnList.args.push(_concat(args));\n return returnList;\n };\n\n\n var _normalizeArrays = function (operations, arg, returnList) {\n if (!returnList) {\n returnList = { ops: [], args: [] };\n }\n $.each(operations, function (index, opn) {\n if ($.isPlainObject(opn)) {\n _normalizeObject(opn, returnList);\n } else {\n _normalizeLiterals(opn, args[index], returnList);\n }\n });\n return returnList;\n };\n\n if ($.isPlainObject(operations)) {\n _normalizeObject(operations, returnList);\n } else if ($.isArray(operations)) {\n _normalizeArrays(operations, args, returnList);\n } else {\n _normalizeLiterals(operations, args, returnList);\n }\n\n return returnList;\n },\n\n splitGetFactory: function (httpOptions) {\n return function (params, options) {\n var http = this;\n var getValue = function (name) {\n var value = options[name] || httpOptions[name];\n if (typeof value === 'function') {\n value = value();\n }\n return value;\n };\n var getFinalUrl = function (params) {\n var url = getValue('url', options);\n var data = params;\n // There is easy (or known) way to get the final URL jquery is going to send so\n // we're replicating it. The process might change at some point but it probably will not.\n // 1. Remove hash\n url = url.replace(/#.*$/, '');\n // 1. Append query string\n var queryParams = qutil.toQueryFormat(data);\n var questionIdx = url.indexOf('?');\n if (queryParams && questionIdx > -1) {\n return url + '&' + queryParams;\n } else if (queryParams) {\n return url + '?' + queryParams;\n }\n return url;\n };\n var url = getFinalUrl(params);\n // We must split the GET in multiple short URL's\n // The only property allowed to be split is \"include\"\n if (params && params.include && encodeURI(url).length > MAX_URL_LENGTH) {\n var dtd = $.Deferred();\n var paramsCopy = $.extend(true, {}, params);\n delete paramsCopy.include;\n var urlNoIncludes = getFinalUrl(paramsCopy);\n var diff = MAX_URL_LENGTH - urlNoIncludes.length;\n var oldSuccess = options.success || httpOptions.success || $.noop;\n var oldError = options.error || httpOptions.error || $.noop;\n // remove the original success and error callbacks\n options.success = $.noop;\n options.error = $.noop;\n\n var include = params.include;\n var currIncludes = [];\n var includeOpts = [currIncludes];\n var currLength = encodeURIComponent('?include=').length;\n var variable = include.pop();\n while (variable) {\n var varLenght = encodeURIComponent(variable).length;\n // Use a greedy approach for now, can be optimized to be solved in a more\n // efficient way\n // + 1 is the comma\n if (currLength + varLenght + 1 < diff) {\n currIncludes.push(variable);\n currLength += varLenght + 1;\n } else {\n currIncludes = [variable];\n includeOpts.push(currIncludes);\n currLength = '?include='.length + varLenght;\n }\n variable = include.pop();\n }\n var reqs = $.map(includeOpts, function (include) {\n var reqParams = $.extend({}, params, { include: include });\n return http.get(reqParams, options);\n });\n $.when.apply($, reqs).then(function () {\n // Each argument are arrays of the arguments of each done request\n // So the first argument of the first array of arguments is the data\n var isValid = arguments[0] && arguments[0][0];\n if (!isValid) {\n // Should never happen...\n oldError();\n return dtd.reject();\n }\n var firstResponse = arguments[0][0];\n var isObject = $.isPlainObject(firstResponse);\n var isRunAPI = (isObject && $.isPlainObject(firstResponse.variables)) || !isObject;\n if (isRunAPI) {\n if (isObject) {\n // aggregate the variables property only\n var aggregateRun = arguments[0][0];\n $.each(arguments, function (idx, args) {\n var run = args[0];\n $.extend(true, aggregateRun.variables, run.variables);\n });\n oldSuccess(aggregateRun, arguments[0][1], arguments[0][2]);\n dtd.resolve(aggregateRun, arguments[0][1], arguments[0][2]);\n } else {\n // array of runs\n // Agregate variables in each run\n var aggregatedRuns = {};\n $.each(arguments, function (idx, args) {\n var runs = args[0];\n if (!$.isArray(runs)) {\n return;\n }\n $.each(runs, function (idxRun, run) {\n if (run.id && !aggregatedRuns[run.id]) {\n run.variables = run.variables || {};\n aggregatedRuns[run.id] = run;\n } else if (run.id) {\n $.extend(true, aggregatedRuns[run.id].variables, run.variables);\n }\n });\n });\n // turn it into an array\n aggregatedRuns = $.map(aggregatedRuns, function (run) { return run; });\n oldSuccess(aggregatedRuns, arguments[0][1], arguments[0][2]);\n dtd.resolve(aggregatedRuns, arguments[0][1], arguments[0][2]);\n }\n } else {\n // is variables API\n // aggregate the response\n var aggregatedVariables = {};\n $.each(arguments, function (idx, args) {\n var vars = args[0];\n $.extend(true, aggregatedVariables, vars);\n });\n oldSuccess(aggregatedVariables, arguments[0][1], arguments[0][2]);\n dtd.resolve(aggregatedVariables, arguments[0][1], arguments[0][2]);\n }\n }, function () {\n oldError.apply(http, arguments);\n dtd.reject.apply(dtd, arguments);\n });\n return dtd.promise();\n } else {\n return http.get(params, options);\n }\n };\n }\n };\n}());\n","/**\n/* Inherit from a class (using prototype borrowing)\n*/\n'use strict';\n\nfunction inherit(C, P) {\n var F = function () {};\n F.prototype = P.prototype;\n C.prototype = new F();\n C.__super = P.prototype;\n C.prototype.constructor = C;\n}\n\n/**\n* Shallow copy of an object\n*/\nvar extend = function (dest /*, var_args*/) {\n var obj = Array.prototype.slice.call(arguments, 1);\n var current;\n for (var j = 0; j 1,\n * // where variables.price has been persisted (recorded)\n * // in the model.\n * rs.query({\n * 'saved': 'true',\n * '.price': '>1'\n * },\n * {\n * startrecord: 2,\n * endrecord: 5\n * });\n *\n * **Parameters**\n * @param {Object} `qs` Query object. Each key can be a property of the run or the name of variable that has been saved in the run (prefaced by `variables.`). Each value can be a literal value, or a comparison operator and value. (See [more on filtering](../../../rest_apis/aggregate_run_api/#filters) allowed in the underlying Run API.) Querying for variables is available for runs [in memory](../../../run_persistence/#runs-in-memory) and for runs [in the database](../../../run_persistence/#runs-in-memory) if the variables are persisted (e.g. that have been `record`ed in your Julia model).\n * @param {Object} `outputModifier` (Optional) Available fields include: `startrecord`, `endrecord`, `sort`, and `direction` (`asc` or `desc`).\n * @param {Object} `options` (Optional) Overrides for configuration options.\n */\n query: function (qs, outputModifier, options) {\n serviceOptions.filter = qs; //shouldn't be able to over-ride\n var httpOptions = $.extend(true, {}, serviceOptions, options);\n httpOptions = urlConfig.addAutoRestoreHeader(httpOptions);\n\n return http.splitGet(outputModifier, httpOptions);\n },\n\n /**\n * Returns particular runs, based on conditions specified in the `qs` object.\n *\n * Similar to `.query()`.\n *\n * **Parameters**\n * @param {Object} `filter` Filter object. Each key can be a property of the run or the name of variable that has been saved in the run (prefaced by `variables.`). Each value can be a literal value, or a comparison operator and value. (See [more on filtering](../../../rest_apis/aggregate_run_api/#filters) allowed in the underlying Run API.) Filtering for variables is available for runs [in memory](../../../run_persistence/#runs-in-memory) and for runs [in the database](../../../run_persistence/#runs-in-memory) if the variables are persisted (e.g. that have been `record`ed in your Julia model).\n * @param {Object} `outputModifier` (Optional) Available fields include: `startrecord`, `endrecord`, `sort`, and `direction` (`asc` or `desc`).\n * @param {Object} `options` (Optional) Overrides for configuration options.\n */\n filter: function (filter, outputModifier, options) {\n if ($.isPlainObject(serviceOptions.filter)) {\n $.extend(serviceOptions.filter, filter);\n } else {\n serviceOptions.filter = filter;\n }\n var httpOptions = $.extend(true, {}, serviceOptions, options);\n httpOptions = urlConfig.addAutoRestoreHeader(httpOptions);\n return http.splitGet(outputModifier, httpOptions);\n },\n\n /**\n * Get data for a specific run. This includes standard run data such as the account, model, project, and created and last modified dates. To request specific model variables, pass them as part of the `filters` parameter.\n *\n * Note that if the run is [in memory](../../../run_persistence/#runs-in-memory), any model variables are available; if the run is [in the database](../../../run_persistence/#runs-in-db), only model variables that have been persisted — that is, `record`ed in your Julia model — are available.\n *\n * **Example**\n *\n * rs.load('bb589677-d476-4971-a68e-0c58d191e450', { include: ['.price', '.sales'] });\n *\n * **Parameters**\n * @param {String} `runID` The run id.\n * @param {Object} `filters` (Optional) Object containing filters and operation modifiers. Use key `include` to list model variables that you want to include in the response. Other available fields include: `startrecord`, `endrecord`, `sort`, and `direction` (`asc` or `desc`).\n * @param {Object} `options` (Optional) Overrides for configuration options.\n */\n load: function (runID, filters, options) {\n if (runID) {\n serviceOptions.filter = runID; //shouldn't be able to over-ride\n }\n var httpOptions = $.extend(true, {}, serviceOptions, options);\n httpOptions = urlConfig.addAutoRestoreHeader(httpOptions);\n return http.get(filters, httpOptions);\n },\n\n\n /**\n * Save attributes (data, model variables) of the run.\n *\n * **Examples**\n *\n * // add 'completed' field to run record\n * rs.save({ completed: true });\n *\n * // update 'saved' field of run record, and update values of model variables for this run\n * rs.save({ saved: true, variables: { a: 23, b: 23 } });\n *\n * **Parameters**\n * @param {Object} `attributes` The run data and variables to save.\n * @param {Object} `attributes.variables` Model variables must be included in a `variables` field within the `attributes` object. (Otherwise they are treated as run data and added to the run record directly.)\n * @param {Object} `options` (Optional) Overrides for configuration options.\n */\n save: function (attributes, options) {\n var httpOptions = $.extend(true, {}, serviceOptions, options);\n setFilterOrThrowError(httpOptions);\n return http.patch(attributes, httpOptions);\n },\n\n /**\n * Call a method from the model.\n *\n * Depending on the language in which you have written your model, the method may need to be exposed (e.g. `export` for a Julia model) in the model file in order to be called through the API. See [Writing your Model](../../../writing_your_model/)).\n *\n * The `params` argument is normally an array of arguments to the `operation`. In the special case where `operation` only takes one argument, you are not required to put that argument into an array.\n *\n * Note that you can combine the `operation` and `params` arguments into a single object if you prefer, as in the last example.\n *\n * **Examples**\n *\n * // method \"solve\" takes no arguments\n * rs.do('solve');\n * // method \"echo\" takes one argument, a string\n * rs.do('echo', ['hello']);\n * // method \"echo\" takes one argument, a string\n * rs.do('echo', 'hello');\n * // method \"sumArray\" takes one argument, an array\n * rs.do('sumArray', [[4,2,1]]);\n * // method \"add\" takes two arguments, both integers\n * rs.do({ name:'add', params:[2,4] });\n *\n * **Parameters**\n * @param {String} `operation` Name of method.\n * @param {Array} `params` (Optional) Any parameters the operation takes, passed as an array. In the special case where `operation` only takes one argument, you are not required to put that argument into an array, and can just pass it directly.\n * @param {Object} `options` (Optional) Overrides for configuration options.\n */\n do: function (operation, params, options) {\n // console.log('do', operation, params);\n var opsArgs;\n var postOptions;\n if (options) {\n opsArgs = params;\n postOptions = options;\n } else {\n if ($.isPlainObject(params)) {\n opsArgs = null;\n postOptions = params;\n } else {\n opsArgs = params;\n }\n }\n var result = rutil.normalizeOperations(operation, opsArgs);\n var httpOptions = $.extend(true, {}, serviceOptions, postOptions);\n\n setFilterOrThrowError(httpOptions);\n\n var prms = (result.args[0].length && (result.args[0] !== null && result.args[0] !== undefined)) ? result.args[0] : [];\n return http.post({ arguments: prms }, $.extend(true, {}, httpOptions, {\n url: urlConfig.getFilterURL() + 'operations/' + result.ops[0] + '/'\n }));\n },\n\n /**\n * Call several methods from the model, sequentially.\n *\n * Depending on the language in which you have written your model, the methods may need to be exposed (e.g. `export` for a Julia model) in the model file in order to be called through the API. See [Writing your Model](../../../writing_your_model/)).\n *\n * **Examples**\n *\n * // methods \"initialize\" and \"solve\" do not take any arguments\n * rs.serial(['initialize', 'solve']);\n * // methods \"init\" and \"reset\" take two arguments each\n * rs.serial([ { name: 'init', params: [1,2] },\n * { name: 'reset', params: [2,3] }]);\n * // method \"init\" takes two arguments,\n * // method \"runmodel\" takes none\n * rs.serial([ { name: 'init', params: [1,2] },\n * { name: 'runmodel', params: [] }]);\n *\n * **Parameters**\n * @param {Array} `operations` If none of the methods take parameters, pass an array of the method names (strings). If any of the methods do take parameters, pass an array of objects, each of which contains a method name and its own (possibly empty) array of parameters.\n * @param {*} `params` Parameters to pass to operations.\n * @param {Object} `options` (Optional) Overrides for configuration options.\n */\n serial: function (operations, params, options) {\n var opParams = rutil.normalizeOperations(operations, params);\n var ops = opParams.ops;\n var args = opParams.args;\n var me = this;\n\n var $d = $.Deferred();\n var postOptions = $.extend(true, {}, serviceOptions, options);\n\n var doSingleOp = function () {\n var op = ops.shift();\n var arg = args.shift();\n\n me.do(op, arg, {\n success: function () {\n if (ops.length) {\n doSingleOp();\n } else {\n $d.resolve.apply(this, arguments);\n postOptions.success.apply(this, arguments);\n }\n },\n error: function () {\n $d.reject.apply(this, arguments);\n postOptions.error.apply(this, arguments);\n }\n });\n };\n\n doSingleOp();\n\n return $d.promise();\n },\n\n /**\n * Call several methods from the model, executing them in parallel.\n *\n * Depending on the language in which you have written your model, the methods may need to be exposed (e.g. `export` for a Julia model) in the model file in order to be called through the API. See [Writing your Model](../../../writing_your_model/)).\n *\n * **Example**\n *\n * // methods \"solve\" and \"reset\" do not take any arguments\n * rs.parallel(['solve', 'reset']);\n * // methods \"add\" and \"subtract\" take two arguments each\n * rs.parallel([ { name: 'add', params: [1,2] },\n * { name: 'subtract', params:[2,3] }]);\n * // methods \"add\" and \"subtract\" take two arguments each\n * rs.parallel({ add: [1,2], subtract: [2,4] });\n *\n * **Parameters**\n * @param {Array|Object} `operations` If none of the methods take parameters, pass an array of the method names (as strings). If any of the methods do take parameters, you have two options. You can pass an array of objects, each of which contains a method name and its own (possibly empty) array of parameters. Alternatively, you can pass a single object with the method name and a (possibly empty) array of parameters.\n * @param {*} `params` Parameters to pass to operations.\n * @param {Object} `options` (Optional) Overrides for configuration options.\n */\n parallel: function (operations, params, options) {\n var $d = $.Deferred();\n\n var opParams = rutil.normalizeOperations(operations, params);\n var ops = opParams.ops;\n var args = opParams.args;\n var postOptions = $.extend(true, {}, serviceOptions, options);\n\n var queue = [];\n for (var i = 0; i< ops.length; i++) {\n queue.push(\n this.do(ops[i], args[i])\n );\n }\n $.when.apply(this, queue)\n .done(function () {\n $d.resolve.apply(this, arguments);\n postOptions.success.apply(this.arguments);\n })\n .fail(function () {\n $d.reject.apply(this, arguments);\n postOptions.error.apply(this.arguments);\n });\n\n return $d.promise();\n }\n };\n\n var publicSyncAPI = {\n getCurrentConfig: function () {\n return serviceOptions;\n },\n /**\n * Returns a Variables Service instance. Use the variables instance to load, save, and query for specific model variables. See the [Variable API Service](../variables-api-service/) for more information.\n *\n * **Example**\n *\n * var vs = rs.variables();\n * vs.save({ sample_int: 4 });\n *\n * **Parameters**\n * @param {Object} `config` (Optional) Overrides for configuration options.\n */\n variables: function (config) {\n var vs = new VariablesService($.extend(true, {}, serviceOptions, config, {\n runService: this\n }));\n return vs;\n },\n\n introspection: function (config) {\n var introspection = new IntrospectionService($.extend(true, {}, serviceOptions, config));\n return introspection;\n }\n };\n\n $.extend(this, publicAsyncAPI);\n $.extend(this, publicSyncAPI);\n};\n","/**\n * ## File API Service\n *\n * This is used to upload/download files directly onto Epicenter, analogous to using the File Manager UI in Epicenter directly or SFTPing files in. The Asset API is typically used for all project use-cases, and it's unlikely this File Service will be used directly except by Admin tools (e.g. Flow Inspector).\n *\n * Partially implemented.\n */\n\n'use strict';\n\nvar ConfigService = require('./configuration-service');\nvar TransportFactory = require('../transport/http-transport-factory');\nvar SessionManager = require('../store/session-manager');\n\nmodule.exports = function (config) {\n var defaults = {\n /**\n * For projects that require authentication, pass in the user access token (defaults to empty string). If the user is already logged in to Epicenter, the user access token is already set in a cookie and automatically loaded from there. (See [more background on access tokens](../../../project_access/)).\n * @see [Authentication API Service](../auth-api-service/) for getting tokens.\n * @type {String}\n */\n token: undefined,\n\n /**\n * The account id. In the Epicenter UI, this is the **Team ID** (for team projects) or **User ID** (for personal projects). Defaults to empty string.\n * @type {String}\n */\n account: undefined,\n\n /**\n * The project id. Defaults to empty string.\n * @type {String}\n */\n project: undefined,\n\n /**\n * The folder type. One of Model|Static|Node\n * @type {String}\n */\n folderType: 'static',\n\n\n /**\n * Options to pass on to the underlying transport layer. All jquery.ajax options at http://api.jquery.com/jQuery.ajax/ are available. Defaults to empty object.\n * @type {Object}\n */\n transport: {}\n };\n\n this.sessionManager = new SessionManager();\n var serviceOptions = this.sessionManager.getMergedOptions(defaults, config);\n var urlConfig = new ConfigService(serviceOptions).get('server');\n if (serviceOptions.account) {\n urlConfig.accountPath = serviceOptions.account;\n }\n if (serviceOptions.project) {\n urlConfig.projectPath = serviceOptions.project;\n }\n\n var httpOptions = $.extend(true, {}, serviceOptions.transport, {\n url: urlConfig.getAPIPath('file')\n });\n\n if (serviceOptions.token) {\n httpOptions.headers = {\n 'Authorization': 'Bearer ' + serviceOptions.token\n };\n }\n var http = new TransportFactory(httpOptions);\n\n var publicAsyncAPI = {\n /**\n * Get a directory listing, or contents of a file\n * @param {String} `filePath` Path to the file\n * @param {Object} `options` (Optional) Overrides for configuration options.\n */\n getContents: function (filePath, options) {\n var path = serviceOptions.folderType + '/' + filePath;\n var httpOptions = $.extend(true, {}, serviceOptions, options, {\n url: urlConfig.getAPIPath('file') + path\n });\n return http.get('', httpOptions);\n },\n\n /**\n * Writes to the given file path; replaces the existing file if it exists\n * @param {String} `filePath` Path to the file\n * @param {String} `contents` Contents to write to file\n * @param {Object} `options` (Optional) Overrides for configuration options\n */\n writeToFile: function (filePath, contents, options) {\n filePath = filePath.split('/');\n var fileName = filePath.pop();\n filePath = filePath.join('/');\n var path = serviceOptions.folderType + '/' + filePath;\n var boundary = '---------------------------7da24f2e50046';\n\n var body = '--' + boundary + '\\r\\n' +\n 'Content-Disposition: form-data; name=\"file\";' +\n 'filename=\"' + fileName + '\"\\r\\n' +\n 'Content-type: text/html\\r\\n\\r\\n' +\n contents + '\\r\\n' +\n '--' + boundary + '--';\n\n var httpOptions = $.extend(true, {}, serviceOptions, options, {\n url: urlConfig.getAPIPath('file') + path,\n data: body,\n contentType: 'multipart/form-data; boundary=' + boundary\n });\n\n return http.put(body, httpOptions);\n },\n\n /**\n * Removes the file\n * @param {String} `filePath` Path to the file\n * @param {Object} `options` (Optional) Overrides for configuration options\n */\n remove: function (filePath, options) {\n var path = serviceOptions.folderType + '/' + filePath;\n var httpOptions = $.extend(true, {}, serviceOptions, options, {\n url: urlConfig.getAPIPath('file') + path\n });\n return http.delete(null, httpOptions);\n },\n\n /**\n * Rename the file\n * @param {String} filePath Path to the file\n * @param {Stirng} newName New name of file\n * @param {Object} options (Optional) Overrides for configuration options\n */\n rename: function (filePath, newName, options) {\n var path = serviceOptions.folderType + '/' + filePath;\n var httpOptions = $.extend(true, {}, serviceOptions, options, {\n url: urlConfig.getAPIPath('file') + path\n });\n return http.patch({ 'name': newName }, httpOptions);\n }\n };\n\n $.extend(this, publicAsyncAPI);\n};\n","/**\n *\n * ## Variables API Service\n *\n * Used in conjunction with the [Run API Service](../run-api-service/) to read, write, and search for specific model variables.\n *\n * var rm = new F.manager.RunManager({\n * run: {\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * model: 'supply-chain-model.jl'\n * }\n * });\n * rm.getRun()\n * .then(function() {\n * var vs = rm.run.variables();\n * vs.save({sample_int: 4});\n * });\n *\n */\n\n\n 'use strict';\n\n var TransportFactory = require('../transport/http-transport-factory');\n var rutil = require('../util/run-util');\n\nmodule.exports = function (config) {\n var defaults = {\n /**\n * The runs object to which the variable filters apply. Defaults to null.\n * @type {runService}\n */\n runService: null\n };\n var serviceOptions = $.extend({}, defaults, config);\n\n var getURL = function () {\n return serviceOptions.runService.urlConfig.getFilterURL() + 'variables/';\n };\n\n var addAutoRestoreHeader = function (options) {\n return serviceOptions.runService.urlConfig.addAutoRestoreHeader(options);\n };\n\n var httpOptions = {\n url: getURL\n };\n if (serviceOptions.token) {\n httpOptions.headers = {\n 'Authorization': 'Bearer ' + serviceOptions.token\n };\n }\n var http = new TransportFactory(httpOptions);\n http.splitGet = rutil.splitGetFactory(httpOptions);\n\n var publicAPI = {\n\n /**\n * Get values for a variable.\n *\n * **Example**\n *\n * vs.load('sample_int')\n * .then(function(val){\n * // val contains the value of sample_int\n * });\n *\n * **Parameters**\n * @param {String} `variable` Name of variable to load.\n * @param {Object} `outputModifier` (Optional) Available fields include: `startrecord`, `endrecord`, `sort`, and `direction` (`asc` or `desc`).\n * @param {Object} `options` (Optional) Overrides for configuration options.\n */\n load: function (variable, outputModifier, options) {\n var httpOptions = $.extend(true, {}, serviceOptions, options);\n httpOptions = addAutoRestoreHeader(httpOptions);\n return http.get(outputModifier, $.extend({}, httpOptions, {\n url: getURL() + variable + '/'\n }));\n },\n\n /**\n * Returns particular variables, based on conditions specified in the `query` object.\n *\n * **Example**\n *\n * vs.query(['price', 'sales'])\n * .then(function(val) {\n * // val is an object with the values of the requested variables: val.price, val.sales\n * });\n *\n * vs.query({ include:['price', 'sales'] });\n *\n * **Parameters**\n * @param {Object|Array} `query` The names of the variables requested.\n * @param {Object} `outputModifier` (Optional) Available fields include: `startrecord`, `endrecord`, `sort`, and `direction` (`asc` or `desc`).\n * @param {Object} `options` (Optional) Overrides for configuration options.\n *\n */\n query: function (query, outputModifier, options) {\n //Query and outputModifier are both querystrings in the url; only calling them out separately here to be consistent with the other calls\n var httpOptions = $.extend(true, {}, serviceOptions, options);\n httpOptions = addAutoRestoreHeader(httpOptions);\n\n if ($.isArray(query)) {\n query = { include: query };\n }\n $.extend(query, outputModifier);\n return http.splitGet(query, httpOptions);\n },\n\n /**\n * Save values to model variables. Overwrites existing values. Note that you can only update model variables if the run is [in memory](../../../run_persistence/#runs-in-memory). (An alternate way to update model variables is to call a method from the model and make sure that the method persists the variables. See `do`, `serial`, and `parallel` in the [Run API Service](../run-api-service/) for calling methods from the model.)\n *\n * **Example**\n *\n * vs.save('price', 4);\n * vs.save({ price: 4, quantity: 5, products: [2,3,4] });\n *\n * **Parameters**\n * @param {Object|String} `variable` An object composed of the model variables and the values to save. Alternatively, a string with the name of the variable.\n * @param {Object} `val` (Optional) If passing a string for `variable`, use this argument for the value to save.\n * @param {Object} `options` (Optional) Overrides for configuration options.\n */\n save: function (variable, val, options) {\n var attrs;\n if (typeof variable === 'object') {\n attrs = variable;\n options = val;\n } else {\n (attrs = {})[variable] = val;\n }\n var httpOptions = $.extend(true, {}, serviceOptions, options);\n\n return http.patch.call(this, attrs, httpOptions);\n }\n\n // Not Available until underlying API supports PUT. Otherwise save would be PUT and merge would be PATCH\n // *\n // * Save values to the api. Merges arrays, but otherwise same as save\n // * @param {Object|String} variable Object with attributes, or string key\n // * @param {Object} val Optional if prev parameter was a string, set value here\n // * @param {Object} options Overrides for configuration options\n // *\n // * @example\n // * vs.merge({ price: 4, quantity: 5, products: [2,3,4] })\n // * vs.merge('price', 4);\n\n // merge: function (variable, val, options) {\n // var attrs;\n // if (typeof variable === 'object') {\n // attrs = variable;\n // options = val;\n // } else {\n // (attrs = {})[variable] = val;\n // }\n // var httpOptions = $.extend(true, {}, serviceOptions, options);\n\n // return http.patch.call(this, attrs, httpOptions);\n // }\n };\n $.extend(this, publicAPI);\n};\n","/**\n *\n * ## Authentication API Service\n *\n * The Authentication API Service provides a method for logging in, which creates and returns a user access token.\n *\n * User access tokens are required for each call to Epicenter. (See [Project Access](../../../project_access/) for more information.)\n *\n * If you need additional functionality -- such as tracking session information, easily retrieving the user token, or getting the groups to which an end user belongs -- consider using the [Authorization Manager](../auth-manager/) instead.\n *\n * var auth = new F.service.Auth();\n * auth.login({ userName: 'jsmith@acmesimulations.com',\n * password: 'passw0rd' });\n */\n\n'use strict';\n\nvar ConfigService = require('./configuration-service');\nvar TransportFactory = require('../transport/http-transport-factory');\n\nmodule.exports = function (config) {\n var defaults = {\n /**\n * Email or username to use for logging in. Defaults to empty string.\n * @type {String}\n */\n userName: '',\n\n /**\n * Password for specified `userName`. Defaults to empty string.\n * @type {String}\n */\n password: '',\n\n /**\n * The account id for this `userName`. In the Epicenter UI, this is the **Team ID** (for team projects) or the **User ID** (for personal projects). Required if the `userName` is for an [end user](../../../glossary/#users). Defaults to empty string.\n * @type {String}\n */\n account: '',\n\n /**\n * Options to pass on to the underlying transport layer. All jquery.ajax options at http://api.jquery.com/jQuery.ajax/ are available. Defaults to empty object.\n * @type {Object}\n */\n transport: {}\n };\n var serviceOptions = $.extend({}, defaults, config);\n var urlConfig = new ConfigService(serviceOptions).get('server');\n\n var transportOptions = $.extend(true, {}, serviceOptions.transport, {\n url: urlConfig.getAPIPath('authentication')\n });\n var http = new TransportFactory(transportOptions);\n\n var publicAPI = {\n\n /**\n * Logs user in, returning the user access token.\n *\n * If no `userName` or `password` were provided in the initial configuration options, they are required in the `options` here. If no `account` was provided in the initial configuration options and the `userName` is for an [end user](../../../glossary/#users), the `account` is required as well.\n *\n * **Example**\n *\n * auth.login({\n * userName: 'jsmith',\n * password: 'passw0rd',\n * account: 'acme-simulations' })\n * .then(function (token) {\n * console.log(\"user access token is: \", token.access_token);\n * });\n *\n * **Parameters**\n * @param {Object} `options` (Optional) Overrides for configuration options.\n */\n login: function (options) {\n var httpOptions = $.extend(true, { success: $.noop }, serviceOptions, options);\n if (!httpOptions.userName || !httpOptions.password) {\n var resp = { status: 401, statusMessage: 'No username or password specified.' };\n if (options.error) {\n options.error.call(this, resp);\n }\n\n return $.Deferred().reject(resp).promise();\n }\n\n var postParams = {\n userName: httpOptions.userName,\n password: httpOptions.password,\n };\n if (httpOptions.account) {\n //pass in null for account under options if you don't want it to be sent\n postParams.account = httpOptions.account;\n }\n\n return http.post(postParams, httpOptions);\n },\n\n // (replace with /* */ comment block, to make visible in docs, once this is more than a noop)\n //\n // Logs user out from specified accounts.\n //\n // Epicenter logout is not implemented yet, so for now this is a dummy promise that gets automatically resolved.\n //\n // **Example**\n //\n // auth.logout();\n //\n // **Parameters**\n // @param {Object} `options` (Optional) Overrides for configuration options.\n //\n logout: function (options) {\n var dtd = $.Deferred();\n dtd.resolve();\n return dtd.promise();\n }\n };\n\n $.extend(this, publicAPI);\n};\n","/**\n * ## Data API Service\n *\n * The Data API Service allows you to create, access, and manipulate data related to any of your projects. Data are organized in collections. Each collection contains a document; each element of this top-level document is a JSON object. (See additional information on the underlying [Data API](../../../rest_apis/data_api/).)\n *\n * All API calls take in an \"options\" object as the last parameter. The options can be used to extend/override the Data API Service defaults. In particular, there are three required parameters when you instantiate the Data Service:\n *\n * * `account`: Epicenter account id (**Team ID** for team projects, **User ID** for personal projects).\n * * `project`: Epicenter project id.\n * * `root`: The the name of the collection. If you have multiple collections within each of your projects, you can also pass the collection name as an option for each call.\n *\n * var ds = new F.service.Data({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * root: 'survey-responses',\n * server: { host: 'api.forio.com' }\n * });\n * ds.saveAs('user1',\n * { 'question1': 2, 'question2': 10,\n * 'question3': false, 'question4': 'sometimes' } );\n * ds.saveAs('user2',\n * { 'question1': 3, 'question2': 8,\n * 'question3': true, 'question4': 'always' } );\n * ds.query('',{ 'question2': { '$gt': 9} });\n *\n * Note that in addition to the `account`, `project`, and `root`, the Data Service parameters optionally include a `server` object, whose `host` field contains the URI of the Forio server. This is automatically set, but you can pass it explicitly if desired. It is most commonly used for clarity when you are [hosting an Epicenter project on your own server](../../../how_to/self_hosting/).\n */\n\n'use strict';\n\nvar ConfigService = require('./configuration-service');\nvar qutil = require('../util/query-util');\nvar TransportFactory = require('../transport/http-transport-factory');\nvar SessionManager = require('../store/session-manager');\n\nmodule.exports = function (config) {\n var defaults = {\n /**\n * Name of collection. Defaults to `/`, that is, the root level of your project at `forio.com/app/your-account-id/your-project-id/`. Required.\n * @type {String}\n */\n root: '/',\n\n /**\n * The account id. In the Epicenter UI, this is the **Team ID** (for team projects) or **User ID** (for personal projects). Defaults to empty string. If left undefined, taken from the URL.\n * @type {String}\n */\n account: undefined,\n\n /**\n * The project id. Defaults to empty string. If left undefined, taken from the URL.\n * @type {String}\n */\n project: undefined,\n\n /**\n * For operations that require authentication, pass in the user access token (defaults to empty string). If the user is already logged in to Epicenter, the user access token is already set in a cookie and automatically loaded from there. (See [more background on access tokens](../../../project_access/)).\n * @see [Authentication API Service](../auth-api-service/) for getting tokens.\n * @type {String}\n */\n token: undefined,\n\n //Options to pass on to the underlying transport layer\n transport: {}\n };\n this.sessionManager = new SessionManager();\n var serviceOptions = this.sessionManager.getMergedOptions(defaults, config);\n\n var urlConfig = new ConfigService(serviceOptions).get('server');\n if (serviceOptions.account) {\n urlConfig.accountPath = serviceOptions.account;\n }\n if (serviceOptions.project) {\n urlConfig.projectPath = serviceOptions.project;\n }\n\n var getURL = function (key, root) {\n if (!root) {\n root = serviceOptions.root;\n }\n var url = urlConfig.getAPIPath('data') + qutil.addTrailingSlash(root);\n if (key) {\n url+= qutil.addTrailingSlash(key);\n }\n return url;\n };\n\n var httpOptions = $.extend(true, {}, serviceOptions.transport, {\n url: getURL\n });\n if (serviceOptions.token) {\n httpOptions.headers = {\n 'Authorization': 'Bearer ' + serviceOptions.token\n };\n }\n var http = new TransportFactory(httpOptions);\n\n var publicAPI = {\n\n /**\n * Search for data within a collection.\n *\n * Searching using comparison or logical operators (as opposed to exact matches) requires MongoDB syntax. See the underlying [Data API](../../../rest_apis/data_api/#searching) for additional details.\n *\n * **Examples**\n *\n * // request all data associated with document 'user1'\n * ds.query('user1');\n *\n * // exact matching:\n * // request all documents in collection where 'question2' is 9\n * ds.query('', { 'question2': 9});\n *\n * // comparison operators:\n * // request all documents in collection\n * // where 'question2' is greater than 9\n * ds.query('', { 'question2': { '$gt': 9} });\n *\n * // logical operators:\n * // request all documents in collection\n * // where 'question2' is less than 10, and 'question3' is false\n * ds.query('', { '$and': [ { 'question2': { '$lt':10} }, { 'question3': false }] });\n *\n * // regular expresssions: use any Perl-compatible regular expressions\n * // request all documents in collection\n * // where 'question5' contains the string '.*day'\n * ds.query('', { 'question5': { '$regex': '.*day' } });\n *\n * **Parameters**\n * @param {String} `key` The name of the document to search. Pass the empty string ('') to search the entire collection.\n * @param {Object} `query` The query object. For exact matching, this object contains the field name and field value to match. For matching based on comparison, this object contains the field name and the comparison expression. For matching based on logical operators, this object contains an expression using MongoDB syntax. See the underlying [Data API](../../../rest_apis/data_api/#searching) for additional examples.\n * @param {Object} `outputModifier` (Optional) Available fields include: `startrecord`, `endrecord`, `sort`, and `direction` (`asc` or `desc`).\n * @param {Object} `options` (Optional) Overrides for configuration options.\n *\n */\n query: function (key, query, outputModifier, options) {\n var params = $.extend(true, { q: query }, outputModifier);\n var httpOptions = $.extend(true, {}, serviceOptions, options);\n httpOptions.url = getURL(key, httpOptions.root);\n return http.get(params, httpOptions);\n },\n\n /**\n * Save data to an anonymous document within the collection.\n *\n * (Documents are top-level elements within a collection. Collections must be unique within this account (team or personal account) and project and are set with the `root` field in the `option` parameter. See the underlying [Data API](../../../rest_apis/data_api/) for additional background.)\n *\n * **Example**\n *\n * ds.save('question1', 'yes');\n * ds.save({question1:'yes', question2: 32 });\n * ds.save({ name:'John', className: 'CS101' }, { root: 'students' });\n *\n * **Parameters**\n *\n * @param {String|Object} `key` If `key` is a string, it is the id of the element to save (create) in this document. If `key` is an object, the object is the data to save (create) in this document. In both cases, the id for the document is generated automatically.\n * @param {Object} `value` (Optional) The data to save. If `key` is a string, this is the value to save. If `key` is an object, the value(s) to save are already part of `key` and this argument is not required.\n * @param {Object} `options` (Optional) Overrides for configuration options.\n */\n save: function (key, value, options) {\n var attrs;\n if (typeof key === 'object') {\n attrs = key;\n options = value;\n } else {\n (attrs = {})[key] = value;\n }\n var httpOptions = $.extend(true, {}, serviceOptions, options);\n httpOptions.url = getURL('', httpOptions.root);\n\n return http.post(attrs, httpOptions);\n },\n\n /**\n * Save data to a named document or element within the collection. The `root` of the collection must be specified separately in configuration options, either as part of the call or as part of the initialization of ds.\n *\n * (Documents are top-level elements within a collection. Collections must be unique within this account (team or personal account) and project and are set with the `root` field in the `option` parameter. See the underlying [Data API](../../../rest_apis/data_api/) for additional background.)\n *\n * **Example**\n *\n * ds.saveAs('user1',\n * { 'question1': 2, 'question2': 10,\n * 'question3': false, 'question4': 'sometimes' } );\n * ds.saveAs('student1',\n * { firstName: 'john', lastName: 'smith' },\n * { root: 'students' });\n * ds.saveAs('mgmt100/groupB',\n * { scenarioYear: '2015' },\n * { root: 'myclasses' });\n *\n * **Parameters**\n *\n * @param {String} `key` Id of the document.\n * @param {Object} `value` (Optional) The data to save, in key:value pairs.\n * @param {Object} `options` (Optional) Overrides for configuration options.\n */\n saveAs: function (key, value, options) {\n var httpOptions = $.extend(true, {}, serviceOptions, options);\n httpOptions.url = getURL(key, httpOptions.root);\n\n return http.put(value, httpOptions);\n },\n\n /**\n * Get data for a specific document or field.\n *\n * **Example**\n *\n * ds.load('user1');\n * ds.load('user1/question3');\n *\n * **Parameters**\n * @param {String|Object} `key` The id of the data to return. Can be the id of a document, or a path to data within that document.\n * @param {Object} `outputModifier` (Optional) Available fields include: `startrecord`, `endrecord`, `sort`, and `direction` (`asc` or `desc`).\n * @param {Object} `options` Overrides for configuration options.\n */\n load: function (key, outputModifier, options) {\n var httpOptions = $.extend(true, {}, serviceOptions, options);\n httpOptions.url = getURL(key, httpOptions.root);\n return http.get(outputModifier, httpOptions);\n },\n\n /**\n * Removes data from collection. Only documents (top-level elements in each collection) can be deleted.\n *\n * **Example**\n *\n * ds.remove('user1');\n *\n *\n * **Parameters**\n *\n * @param {String|Array} `keys` The id of the document to remove from this collection, or an array of such ids.\n * @param {Object} `options` (Optional) Overrides for configuration options.\n */\n remove: function (keys, options) {\n var httpOptions = $.extend(true, {}, serviceOptions, options);\n var params;\n if ($.isArray(keys)) {\n params = { id: keys };\n } else {\n params = '';\n httpOptions.url = getURL(keys, httpOptions.root);\n }\n return http.delete(params, httpOptions);\n }\n\n // Epicenter doesn't allow nuking collections\n // /**\n // * Removes collection being referenced\n // * @return null\n // */\n // destroy: function (options) {\n // return this.remove('', options);\n // }\n };\n\n $.extend(this, publicAPI);\n};\n","'use strict';\n/**\n * ## State API Adapter\n *\n * The State API Adapter allows you to replay or clone runs. It brings existing, persisted run data from the database back into memory, using the same run id (`replay`) or a new run id (`clone`). Runs must be in memory in order for you to update variables or call operations on them.\n *\n * Specifically, the State API Adapter works by \"re-running\" the run (user interactions) from the creation of the run up to the time it was last persisted in the database. This process uses the current version of the run's model. Therefore, if the model has changed since the original run was created, the retrieved run will use the new model — and may end up having different values or behavior as a result. Use with care!\n *\n * To use the State API Adapter, instantiate it and then call its methods:\n *\n * var sa = new F.service.State();\n * sa.replay({runId: '1842bb5c-83ad-4ba8-a955-bd13cc2fdb4f'});\n *\n * The constructor takes an optional `options` parameter in which you can specify the `account` and `project` if they are not already available in the current context.\n *\n */\n\nvar ConfigService = require('./configuration-service');\nvar TransportFactory = require('../transport/http-transport-factory');\nvar _pick = require('../util/object-util')._pick;\nvar SessionManager = require('../store/session-manager');\nvar apiEndpoint = 'model/state';\n\nmodule.exports = function (config) {\n\n var defaults = {\n\n };\n\n this.sessionManager = new SessionManager();\n var serviceOptions = this.sessionManager.getMergedOptions(defaults, config);\n var urlConfig = new ConfigService(serviceOptions).get('server');\n\n var transportOptions = $.extend(true, {}, serviceOptions.transport, {\n url: urlConfig.getAPIPath(apiEndpoint)\n });\n\n if (serviceOptions.token) {\n transportOptions.headers = {\n 'Authorization': 'Bearer ' + serviceOptions.token\n };\n }\n\n var http = new TransportFactory(transportOptions);\n var parseRunIdOrError = function (params) {\n if ($.isPlainObject(params) && params.runId) {\n return params.runId;\n } else {\n throw new Error('Please pass in a run id');\n }\n };\n\n var publicAPI = {\n /**\n * Replay a run. After this call, the run, with its original run id, is now available [in memory](../../../run_persistence/#runs-in-memory). (It continues to be persisted into the Epicenter database at regular intervals.)\n *\n * **Example**\n *\n * var sa = new F.service.State();\n * sa.replay({runId: '1842bb5c-83ad-4ba8-a955-bd13cc2fdb4f', stopBefore: 'calculateScore'});\n *\n * **Parameters**\n * @param {object} `params` Parameters object.\n * @param {string} `params.runId` The id of the run to bring back to memory.\n * @param {string} `params.stopBefore` (Optional) The run is advanced only up to the first occurrence of this method.\n * @param {array} `params.exclude` (Optional) Array of methods to exclude when advancing the run.\n * @param {object} `options` (Optional) Overrides for configuration options.\n */\n replay: function (params, options) {\n var runId = parseRunIdOrError(params);\n\n var replayOptions = $.extend(true, {},\n serviceOptions,\n options,\n { url: urlConfig.getAPIPath(apiEndpoint) + runId }\n );\n\n params = $.extend(true, { action: 'replay' }, _pick(params, ['stopBefore', 'exclude']));\n\n return http.post(params, replayOptions);\n },\n\n /**\n * Clone a given run and return a new run in the same state as the given run.\n *\n * The new run id is now available [in memory](../../../run_persistence/#runs-in-memory). The new run includes a copy of all of the data from the original run, EXCEPT:\n *\n * * The `saved` field in the new run record is not copied from the original run record. It defaults to `false`.\n * * The `initialized` field in the new run record is not copied from the original run record. It defaults to `false` but may change to `true` as the new run is advanced. For example, if there has been a call to the `step` function (for Vensim models), the `initialized` field is set to `true`.\n * * The `created` field in the new run record is the date and time at which the clone was created (not the time that the original run was created.)\n *\n * The original run remains only [in the database](../../../run_persistence/#runs-in-db).\n *\n * **Example**\n *\n * var sa = new F.service.State();\n * sa.clone({runId: '1842bb5c-83ad-4ba8-a955-bd13cc2fdb4f', stopBefore: 'calculateScore', exclude: ['interimCalculation'] });\n *\n * **Parameters**\n * @param {object} `params` Parameters object.\n * @param {string} `params.runId` The id of the run to clone from memory.\n * @param {string} `params.stopBefore` (Optional) The newly cloned run is advanced only up to the first occurrence of this method.\n * @param {array} `params.exclude` (Optional) Array of methods to exclude when advancing the newly cloned run.\n * @param {object} `options` (Optional) Overrides for configuration options.\n */\n clone: function (params, options) {\n var runId = parseRunIdOrError(params);\n\n var replayOptions = $.extend(true, {},\n serviceOptions,\n options,\n { url: urlConfig.getAPIPath(apiEndpoint) + runId }\n );\n\n params = $.extend(true, { action: 'clone' }, _pick(params, ['stopBefore', 'exclude']));\n\n return http.post(params, replayOptions);\n }\n };\n\n $.extend(this, publicAPI);\n};\n","/**\n * ## World API Adapter\n *\n * A [run](../../../glossary/#run) is a collection of end user interactions with a project and its model -- including setting variables, making decisions, and calling operations. For building multiplayer simulations you typically want multiple end users to share the same set of interactions, and work within a common state. Epicenter allows you to create \"worlds\" to handle such cases. Only [team projects](../../../glossary/#team) can be multiplayer.\n *\n * The World API Adapter allows you to create, access, and manipulate multiplayer worlds within your Epicenter project. You can use this to add and remove end users from the world, and to create, access, and remove their runs. Because of this, typically the World Adapter is used for facilitator pages in your project. (The related [World Manager](../world-manager/) provides an easy way to access runs and worlds for particular end users, so is typically used in pages that end users will interact with.)\n *\n * As with all the other [API Adapters](../../), all methods take in an \"options\" object as the last parameter. The options can be used to extend/override the World API Service defaults.\n *\n * To use the World Adapter, instantiate it and then access the methods provided. Instantiating requires the account id (**Team ID** in the Epicenter user interface), project id (**Project ID**), and group (**Group Name**).\n *\n * var wa = new F.service.World({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * group: 'team1' });\n * wa.create()\n * .then(function(world) {\n * // call methods, e.g. wa.addUsers()\n * });\n */\n\n'use strict';\n\nvar ConfigService = require('./configuration-service');\n// var qutil = require('../util/query-util');\nvar TransportFactory = require('../transport/http-transport-factory');\nvar SessionManager = require('../store/session-manager');\nvar _pick = require('../util/object-util')._pick;\n\nvar apiBase = 'multiplayer/';\nvar assignmentEndpoint = apiBase + 'assign';\nvar apiEndpoint = apiBase + 'world';\nvar projectEndpoint = apiBase + 'project';\n\nmodule.exports = function (config) {\n var defaults = {\n /**\n * For projects that require authentication, pass in the user access token (defaults to empty string). If the user is already logged in to Epicenter, the user access token is already set in a cookie and automatically loaded from there. (See [more background on access tokens](../../../project_access/)).\n * @see [Authentication API Service](../auth-api-service/) for getting tokens.\n * @type {String}\n */\n token: undefined,\n\n /**\n * The project id. If left undefined, taken from the URL.\n * @type {String}\n */\n project: undefined,\n\n /**\n * The account id. In the Epicenter UI, this is the **Team ID** (for team projects). If left undefined, taken from the URL.\n * @type {String}\n */\n account: undefined,\n\n /**\n * The group name. Defaults to undefined.\n * @type {String}\n */\n group: undefined,\n\n /**\n * The model file to use to create runs in this world. Defaults to undefined.\n * @type {String}\n */\n model: undefined,\n\n /**\n * Criteria by which to filter world. Currently only supports world-ids as filters.\n * @type {String}\n */\n filter: '',\n\n /**\n * Convenience alias for filter\n * @type {String}\n */\n id: '',\n\n /**\n * Options to pass on to the underlying transport layer. All jquery.ajax options at http://api.jquery.com/jQuery.ajax/ are available. Defaults to empty object.\n * @type {Object}\n */\n transport: {},\n\n /**\n * Called when the call completes successfully. Defaults to `$.noop`.\n * @type {function}\n */\n success: $.noop,\n\n /**\n * Called when the call fails. Defaults to `$.noop`.\n * @type {function}\n */\n error: $.noop\n };\n\n this.sessionManager = new SessionManager();\n var serviceOptions = this.sessionManager.getMergedOptions(defaults, config);\n if (serviceOptions.id) {\n serviceOptions.filter = serviceOptions.id;\n }\n\n var urlConfig = new ConfigService(serviceOptions).get('server');\n\n if (!serviceOptions.account) {\n serviceOptions.account = urlConfig.accountPath;\n }\n\n if (!serviceOptions.project) {\n serviceOptions.project = urlConfig.projectPath;\n }\n\n var transportOptions = $.extend(true, {}, serviceOptions.transport, {\n url: urlConfig.getAPIPath(apiEndpoint)\n });\n\n if (serviceOptions.token) {\n transportOptions.headers = {\n 'Authorization': 'Bearer ' + serviceOptions.token\n };\n }\n\n var http = new TransportFactory(transportOptions);\n\n var setIdFilterOrThrowError = function (options) {\n if (options.id) {\n serviceOptions.filter = options.id;\n }\n if (options.filter) {\n serviceOptions.filter = options.filter;\n }\n if (!serviceOptions.filter) {\n throw new Error('No world id specified to apply operations against. This could happen if the user is not assigned to a world and is trying to work with runs from that world.');\n }\n };\n\n var validateModelOrThrowError = function (options) {\n if (!options.model) {\n throw new Error('No model specified to get the current run');\n }\n };\n\n var publicAPI = {\n\n /**\n * Creates a new World.\n *\n * Using this method is rare. It is more common to create worlds automatically while you `autoAssign()` end users to worlds. (In this case, configuration data for the world, such as the roles, are read from the project-level world configuration information, for example by `getProjectSettings()`.)\n *\n * **Example**\n *\n * var wa = new F.service.World({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * group: 'team1' });\n * wa.create({\n * roles: ['VP Marketing', 'VP Sales', 'VP Engineering']\n * });\n *\n * **Parameters**\n * @param {object} `params` Parameters to create the world.\n * @param {string} `params.group` (Optional) The **Group Name** to create this world under. Only end users in this group are eligible to join the world. Optional here; required when instantiating the service (`new F.service.World()`).\n * @param {object} `params.roles` (Optional) The list of roles (strings) for this world. Some worlds have specific roles that **must** be filled by end users. Listing the roles allows you to autoassign users to worlds and ensure that all roles are filled in each world.\n * @param {object} `params.optionalRoles` (Optional) The list of optional roles (strings) for this world. Some worlds have specific roles that **may** be filled by end users. Listing the optional roles as part of the world object allows you to autoassign users to worlds and ensure that all roles are filled in each world.\n * @param {integer} `params.minUsers` (Optional) The minimum number of users for the world. Including this number allows you to autoassign end users to worlds and ensure that the correct number of users are in each world.\n * @param {object} `options` (Optional) Options object to override global options.\n *\n */\n create: function (params, options) {\n var createOptions = $.extend(true, {}, serviceOptions, options, { url: urlConfig.getAPIPath(apiEndpoint) });\n var worldApiParams = ['scope', 'files', 'roles', 'optionalRoles', 'minUsers', 'group', 'name'];\n var validParams = _pick(serviceOptions, ['account', 'project', 'group']);\n // whitelist the fields that we actually can send to the api\n params = _pick(params, worldApiParams);\n\n // account and project go in the body, not in the url\n params = $.extend({}, validParams, params);\n\n var oldSuccess = createOptions.success;\n createOptions.success = function (response) {\n serviceOptions.filter = response.id; //all future chained calls to operate on this id\n return oldSuccess.apply(this, arguments);\n };\n\n return http.post(params, createOptions);\n },\n\n /**\n * Updates a World, for example to replace the roles in the world.\n *\n * Typically, you complete world configuration at the project level, rather than at the world level. For example, each world in your project probably has the same roles for end users. And your project is probably either configured so that all end users share the same world (and run), or smaller sets of end users share worlds — but not both. However, this method is available if you need to update the configuration of a particular world.\n *\n * **Example**\n *\n * var wa = new F.service.World({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * group: 'team1' });\n * wa.create()\n * .then(function(world) {\n * wa.update({ roles: ['VP Marketing', 'VP Sales', 'VP Engineering'] });\n * });\n *\n * **Parameters**\n * @param {object} `params` Parameters to update the world.\n * @param {string} `params.name` A string identifier for the linked end users, for example, \"name\": \"Our Team\".\n * @param {object} `params.roles` (Optional) The list of roles (strings) for this world. Some worlds have specific roles that **must** be filled by end users. Listing the roles allows you to autoassign users to worlds and ensure that all roles are filled in each world.\n * @param {object} `params.optionalRoles` (Optional) The list of optional roles (strings) for this world. Some worlds have specific roles that **may** be filled by end users. Listing the optional roles as part of the world object allows you to autoassign users to worlds and ensure that all roles are filled in each world.\n * @param {integer} `params.minUsers` (Optional) The minimum number of users for the world. Including this number allows you to autoassign end users to worlds and ensure that the correct number of users are in each world.\n * @param {object} `options` (Optional) Options object to override global options.\n *\n */\n update: function (params, options) {\n var whitelist = ['roles', 'optionalRoles', 'minUsers'];\n options = options || {};\n setIdFilterOrThrowError(options);\n\n var updateOptions = $.extend(true, {},\n serviceOptions,\n options,\n { url: urlConfig.getAPIPath(apiEndpoint) + serviceOptions.filter }\n );\n\n params = _pick(params || {}, whitelist);\n\n return http.patch(params, updateOptions);\n },\n\n /**\n * Deletes an existing world.\n *\n * This function optionally takes one argument. If the argument is a string, it is the id of the world to delete. If the argument is an object, it is the override for global options.\n *\n * **Example**\n *\n * var wa = new F.service.World({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * group: 'team1' });\n * wa.create()\n * .then(function(world) {\n * wa.delete();\n * });\n *\n * **Parameters**\n * @param {String|Object} `options` (Optional) The id of the world to delete, or options object to override global options.\n *\n */\n delete: function (options) {\n options = (options && (typeof options === 'string')) ? { filter: options } : {};\n setIdFilterOrThrowError(options);\n\n var deleteOptions = $.extend(true, {},\n serviceOptions,\n options,\n { url: urlConfig.getAPIPath(apiEndpoint) + serviceOptions.filter }\n );\n\n return http.delete(null, deleteOptions);\n },\n\n /**\n * Updates the configuration for the current instance of the World API Adapter (including all subsequent function calls, until the configuration is updated again).\n *\n * **Example**\n *\n * var wa = new F.service.World({...}).updateConfig({ filter: '123' }).addUser({ userId: '123' });\n *\n * **Parameters**\n * @param {object} `config` The configuration object to use in updating existing configuration.\n */\n updateConfig: function (config) {\n $.extend(serviceOptions, config);\n\n return this;\n },\n\n /**\n * Lists all worlds for a given account, project, and group. All three are required, and if not specified as parameters, are read from the service.\n *\n * **Example**\n *\n * var wa = new F.service.World({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * group: 'team1' });\n * wa.create()\n * .then(function(world) {\n * // lists all worlds in group \"team1\"\n * wa.list();\n *\n * // lists all worlds in group \"other-group-name\"\n * wa.list({ group: 'other-group-name' });\n * });\n *\n * **Parameters**\n * @param {object} `options` (Optional) Options object to override global options.\n *\n */\n list: function (options) {\n options = options || {};\n\n var getOptions = $.extend(true, {},\n serviceOptions,\n options,\n { url: urlConfig.getAPIPath(apiEndpoint) }\n );\n\n var filters = _pick(getOptions, ['account', 'project', 'group']);\n\n return http.get(filters, getOptions);\n },\n\n /**\n * Gets all worlds that an end user belongs to for a given account (team), project, and group.\n *\n * **Example**\n *\n * var wa = new F.service.World({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * group: 'team1' });\n * wa.create()\n * .then(function(world) {\n * wa.getWorldsForUser('b1c19dda-2d2e-4777-ad5d-3929f17e86d3')\n * });\n *\n * ** Parameters **\n * @param {string} `userId` The `userId` of the user whose worlds are being retrieved.\n * @param {object} `options` (Optional) Options object to override global options.\n */\n getWorldsForUser: function (userId, options) {\n options = options || {};\n\n var getOptions = $.extend(true, {},\n serviceOptions,\n options,\n { url: urlConfig.getAPIPath(apiEndpoint) }\n );\n\n var filters = $.extend(\n _pick(getOptions, ['account', 'project', 'group']),\n { userId: userId }\n );\n\n return http.get(filters, getOptions);\n },\n\n /**\n * Load information for a specific world. All further calls to the world service will use the id provided.\n *\n * **Parameters**\n * @param {String} `worldId` The id of the world to load.\n * @param {Object} `options` (Optional) Options object to override global options.\n */\n load: function (worldId, options) {\n if (worldId) {\n serviceOptions.filter = worldId;\n }\n if (!serviceOptions.filter) {\n throw new Error('Please provide a worldid to load');\n }\n var httpOptions = $.extend(true, {}, serviceOptions, options, { url: urlConfig.getAPIPath(apiEndpoint) + serviceOptions.filter + '/' });\n return http.get('', httpOptions);\n },\n\n /**\n * Adds an end user or list of end users to a given world. The end user must be a member of the `group` that is associated with this world.\n *\n * **Example**\n *\n * var wa = new F.service.World({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * group: 'team1' });\n * wa.create()\n * .then(function(world) {\n * // add one user\n * wa.addUsers('b1c19dda-2d2e-4777-ad5d-3929f17e86d3');\n * wa.addUsers(['b1c19dda-2d2e-4777-ad5d-3929f17e86d3']);\n * wa.addUsers({ userId: 'b1c19dda-2d2e-4777-ad5d-3929f17e86d3', role: 'VP Sales' });\n *\n * // add several users\n * wa.addUsers([\n * { userId: 'a6fe0c1e-f4b8-4f01-9f5f-01ccf4c2ed44',\n * role: 'VP Marketing' },\n * { userId: '8f2604cf-96cd-449f-82fa-e331530734ee',\n * role: 'VP Engineering' }\n * ]);\n *\n * // add one user to a specific world\n * wa.addUsers('b1c19dda-2d2e-4777-ad5d-3929f17e86d3', world.id);\n * wa.addUsers('b1c19dda-2d2e-4777-ad5d-3929f17e86d3', { filter: world.id });\n * });\n *\n * ** Parameters **\n * @param {string|object|array} `users` User id, array of user ids, object, or array of objects of the users to add to this world.\n * @param {string} `users.role` The `role` the user should have in the world. It is up to the caller to ensure, if needed, that the `role` passed in is one of the `roles` or `optionalRoles` of this world.\n * @param {string} `worldId` The world to which the users should be added. If not specified, the filter parameter of the `options` object is used.\n * @param {object} `options` (Optional) Options object to override global options.\n */\n addUsers: function (users, worldId, options) {\n\n if (!users) {\n throw new Error('Please provide a list of users to add to the world');\n }\n\n // normalize the list of users to an array of user objects\n users = $.map([].concat(users), function (u) {\n var isObject = $.isPlainObject(u);\n\n if (typeof u !== 'string' && !isObject) {\n throw new Error('Some of the users in the list are not in the valid format: ' + u);\n }\n\n return isObject ? u : { userId: u };\n });\n\n // check if options were passed as the second parameter\n if ($.isPlainObject(worldId) && !options) {\n options = worldId;\n worldId = null;\n }\n\n options = options || {};\n\n // we must have options by now\n if (typeof worldId === 'string') {\n options.filter = worldId;\n }\n\n setIdFilterOrThrowError(options);\n\n var updateOptions = $.extend(true, {},\n serviceOptions,\n options,\n { url: urlConfig.getAPIPath(apiEndpoint) + serviceOptions.filter + '/users' }\n );\n\n return http.post(users, updateOptions);\n },\n\n /**\n * Updates the role of an end user in a given world. (You can only update one end user at a time.)\n *\n * **Example**\n *\n * var wa = new F.service.World({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * group: 'team1' });\n *\n * wa.create().then(function(world) {\n * wa.addUsers('b1c19dda-2d2e-4777-ad5d-3929f17e86d3');\n * wa.updateUser({ userId: 'b1c19dda-2d2e-4777-ad5d-3929f17e86d3', role: 'leader' });\n * });\n *\n * **Parameters**\n * @param {object} `user` User object with `userId` and the new `role`.\n * @param {object} `options` (Optional) Options object to override global options.\n *\n */\n updateUser: function (user, options) {\n options = options || {};\n\n if (!user || !user.userId) {\n throw new Error('You need to pass a userId to update from the world');\n }\n\n setIdFilterOrThrowError(options);\n\n var patchOptions = $.extend(true, {},\n serviceOptions,\n options,\n { url: urlConfig.getAPIPath(apiEndpoint) + serviceOptions.filter + '/users/' + user.userId }\n );\n\n return http.patch(_pick(user, 'role'), patchOptions);\n },\n\n /**\n * Removes an end user from a given world.\n *\n * **Example**\n *\n * var wa = new F.service.World({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * group: 'team1' });\n * wa.create()\n * .then(function(world) {\n * wa.addUsers(['a6fe0c1e-f4b8-4f01-9f5f-01ccf4c2ed44', '8f2604cf-96cd-449f-82fa-e331530734ee']);\n * wa.removeUser('a6fe0c1e-f4b8-4f01-9f5f-01ccf4c2ed44');\n * wa.removeUser({ userId: '8f2604cf-96cd-449f-82fa-e331530734ee' });\n * });\n *\n * ** Parameters **\n * @param {object|string} `user` The `userId` of the user to remove from the world, or an object containing the `userId` field.\n * @param {object} `options` (Optional) Options object to override global options.\n */\n removeUser: function (user, options) {\n options = options || {};\n\n if (typeof user === 'string') {\n user = { userId: user };\n }\n\n if (!user.userId) {\n throw new Error('You need to pass a userId to remove from the world');\n }\n\n setIdFilterOrThrowError(options);\n\n var getOptions = $.extend(true, {},\n serviceOptions,\n options,\n { url: urlConfig.getAPIPath(apiEndpoint) + serviceOptions.filter + '/users/' + user.userId }\n );\n\n return http.delete(null, getOptions);\n },\n\n /**\n * Gets the run id of current run for the given world. If the world does not have a run, creates a new one and returns the run id.\n *\n * Remember that a [run](../../glossary/#run) is a collection of interactions with a project and its model. In the case of multiplayer projects, the run is shared by all end users in the world.\n *\n * **Example**\n *\n * var wa = new F.service.World({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * group: 'team1' });\n * wa.create()\n * .then(function(world) {\n * wa.getCurrentRunId({ model: 'model.py' });\n * });\n *\n * ** Parameters **\n * @param {object} `options` (Optional) Options object to override global options.\n * @param {object} `options.model` The model file to use to create a run if needed.\n */\n getCurrentRunId: function (options) {\n options = options || {};\n\n setIdFilterOrThrowError(options);\n\n var getOptions = $.extend(true, {},\n serviceOptions,\n options,\n { url: urlConfig.getAPIPath(apiEndpoint) + serviceOptions.filter + '/run' }\n );\n\n validateModelOrThrowError(getOptions);\n return http.post(_pick(getOptions, 'model'), getOptions);\n },\n\n /**\n * Gets the current (most recent) world for the given end user in the given group. Brings this most recent world into memory if needed.\n *\n * **Example**\n *\n * var wa = new F.service.World({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * group: 'team1' });\n * wa.getCurrentWorldForUser('8f2604cf-96cd-449f-82fa-e331530734ee')\n * .then(function(world) {\n * // use data from world\n * });\n *\n * ** Parameters **\n * @param {string} `userId` The `userId` of the user whose current (most recent) world is being retrieved.\n * @param {string} `groupName` (Optional) The name of the group. If not provided, defaults to the group used to create the service.\n */\n getCurrentWorldForUser: function (userId, groupName) {\n var dtd = $.Deferred();\n var me = this;\n this.getWorldsForUser(userId, { group: groupName })\n .then(function (worlds) {\n // assume the most recent world as the 'active' world\n worlds.sort(function (a, b) { return new Date(b.lastModified) - new Date(a.lastModified); });\n var currentWorld = worlds[0];\n\n if (currentWorld) {\n serviceOptions.filter = currentWorld.id;\n }\n\n dtd.resolve(currentWorld, me);\n })\n .fail(dtd.reject);\n\n return dtd.promise();\n },\n\n /**\n * Deletes the current run from the world.\n *\n * (Note that the world id remains part of the run record, indicating that the run was formerly an active run for the world.)\n *\n * **Example**\n *\n * var wa = new F.service.World({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * group: 'team1' });\n *\n * wa.deleteRun('sample-world-id');\n *\n * **Parameters**\n * @param {string} `worldId` The `worldId` of the world from which the current run is being deleted.\n * @param {object} `options` (Optional) Options object to override global options.\n */\n deleteRun: function (worldId, options) {\n options = options || {};\n\n if (worldId) {\n options.filter = worldId;\n }\n\n setIdFilterOrThrowError(options);\n\n var deleteOptions = $.extend(true, {},\n serviceOptions,\n options,\n { url: urlConfig.getAPIPath(apiEndpoint) + serviceOptions.filter + '/run' }\n );\n\n return http.delete(null, deleteOptions);\n },\n\n /**\n * Creates a new run for the world.\n *\n * **Example**\n *\n * var wa = new F.service.World({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * group: 'team1' });\n *\n * wa.getCurrentWorldForUser('8f2604cf-96cd-449f-82fa-e331530734ee')\n * .then(function (world) {\n * wa.newRunForWorld(world.id);\n * });\n *\n * **Parameters**\n * @param {string} `worldId` worldId in which we create the new run.\n * @param {object} `options` (Optional) Options object to override global options.\n * @param {object} `options.model` The model file to use to create a run if needed.\n */\n newRunForWorld: function (worldId, options) {\n var currentRunOptions = $.extend(true, {},\n options,\n { filter: worldId || serviceOptions.filter }\n );\n var _this = this;\n\n validateModelOrThrowError(currentRunOptions);\n\n return this.deleteRun(worldId, options)\n .then(function () {\n return _this.getCurrentRunId(currentRunOptions);\n });\n },\n\n /**\n * Assigns end users to worlds, creating new worlds as appropriate, automatically. Assigns all end users in the group, and creates new worlds as needed based on the project-level world configuration (roles, optional roles, and minimum end users per world).\n *\n * **Example**\n *\n * var wa = new F.service.World({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * group: 'team1' });\n *\n * wa.autoAssign();\n *\n * **Parameters**\n * @param {object} `options` (Optional) Options object to override global options.\n *\n */\n autoAssign: function (options) {\n options = options || {};\n\n var opt = $.extend(true, {},\n serviceOptions,\n options,\n { url: urlConfig.getAPIPath(assignmentEndpoint) }\n );\n\n var params = {\n account: opt.account,\n project: opt.project,\n group: opt.group\n };\n\n if (opt.maxUsers) {\n params.maxUsers = opt.maxUsers;\n }\n\n return http.post(params, opt);\n },\n\n /**\n * Gets the project's world configuration.\n *\n * Typically, every interaction with your project uses the same configuration of each world. For example, each world in your project probably has the same roles for end users. And your project is probably either configured so that all end users share the same world (and run), or smaller sets of end users share worlds — but not both.\n *\n * (The [Multiplayer Project REST API](../../../rest_apis/multiplayer/multiplayer_project/) allows you to set these project-level world configurations. The World Adapter simply retrieves them, for example so they can be used in auto-assignment of end users to worlds.)\n *\n * **Example**\n *\n * var wa = new F.service.World({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * group: 'team1' });\n *\n * wa.getProjectSettings()\n * .then(function(settings) {\n * console.log(settings.roles);\n * console.log(settings.optionalRoles);\n * });\n *\n * **Parameters**\n * @param {object} `options` (Optional) Options object to override global options.\n */\n getProjectSettings: function (options) {\n options = options || {};\n\n var opt = $.extend(true, {},\n serviceOptions,\n options,\n { url: urlConfig.getAPIPath(projectEndpoint) }\n );\n\n opt.url += [opt.account, opt.project].join('/');\n\n return http.get(null, opt);\n }\n\n };\n\n $.extend(this, publicAPI);\n};\n","'use strict';\n/**\n* ## User API Adapter\n*\n* The User API Adapter allows you to retrieve details about end users in your team (account). It is based on the querying capabilities of the underlying RESTful [User API](../../../rest_apis/user_management/user/).\n*\n* To use the User API Adapter, instantiate it and then call its methods.\n*\n* var ua = new F.service.User({\n* account: 'acme-simulations',\n* token: 'user-or-project-access-token'\n* });\n* ua.getById('42836d4b-5b61-4fe4-80eb-3136e956ee5c');\n* ua.get({ userName: 'jsmith' });\n* ua.get({ id: ['42836d4b-5b61-4fe4-80eb-3136e956ee5c',\n* '4ea75631-4c8d-4872-9d80-b4600146478e'] });\n*\n* The constructor takes an optional `options` parameter in which you can specify the `account` and `token` if they are not already available in the current context.\n*/\n\nvar ConfigService = require('./configuration-service');\nvar TransportFactory = require('../transport/http-transport-factory');\nvar SessionManager = require('../store/session-manager');\nvar qutil = require('../util/query-util');\n\nmodule.exports = function (config) {\n var defaults = {\n\n /**\n * The account id. In the Epicenter UI, this is the **Team ID** (for team projects) or **User ID** (for personal projects). Defaults to empty string.\n * @type {String}\n */\n account: undefined,\n\n /**\n * The access token to use when searching for end users. (See [more background on access tokens](../../../project_access/)).\n * @type {String}\n */\n token: undefined,\n\n /**\n * Options to pass on to the underlying transport layer. All jquery.ajax options at http://api.jquery.com/jQuery.ajax/ are available. Defaults to empty object.\n * @type {Object}\n */\n transport: {}\n };\n\n this.sessionManager = new SessionManager();\n var serviceOptions = this.sessionManager.getMergedOptions(defaults, config);\n var urlConfig = new ConfigService(serviceOptions).get('server');\n var transportOptions = $.extend(true, {}, serviceOptions.transport, {\n url: urlConfig.getAPIPath('user')\n });\n\n if (serviceOptions.token) {\n transportOptions.headers = {\n 'Authorization': 'Bearer ' + serviceOptions.token\n };\n }\n\n var http = new TransportFactory(transportOptions);\n\n var publicAPI = {\n\n /**\n * Retrieve details about particular end users in your team, based on user name or user id.\n *\n * **Example**\n *\n * var ua = new F.service.User({\n * account: 'acme-simulations',\n * token: 'user-or-project-access-token'\n * });\n * ua.get({ userName: 'jsmith' });\n * ua.get({ id: ['42836d4b-5b61-4fe4-80eb-3136e956ee5c',\n * '4ea75631-4c8d-4872-9d80-b4600146478e'] });\n *\n * **Parameters**\n * @param {object} `filter` Object with field `userName` and value of the username. Alternatively, object with field `id` and value of an array of user ids.\n * @param {object} `options` (Optional) Overrides for configuration options.\n */\n\n get: function (filter, options) {\n options = options || {};\n filter = filter || {};\n\n var getOptions = $.extend(true, {},\n serviceOptions,\n options\n );\n\n var toQFilter = function (filter) {\n var res = {};\n\n // API only supports filtering by username for now\n if (filter.userName) {\n res.q = filter.userName;\n }\n\n return res;\n };\n\n var toIdFilters = function (id) {\n if (!id) {\n return '';\n }\n\n id = $.isArray(id) ? id : [id];\n return 'id=' + id.join('&id=');\n };\n\n var getFilters = [\n 'account=' + getOptions.account,\n toIdFilters(filter.id),\n qutil.toQueryFormat(toQFilter(filter))\n ].join('&');\n\n // special case for queries with large number of ids\n // make it as a post with GET semantics\n var threshold = 30;\n if (filter.id && $.isArray(filter.id) && filter.id.length >= threshold) {\n getOptions.url = urlConfig.getAPIPath('user') + '?_method=GET';\n return http.post({ id: filter.id }, getOptions);\n } else {\n return http.get(getFilters, getOptions);\n }\n },\n\n /**\n * Retrieve details about a single end user in your team, based on user id.\n *\n * **Example**\n *\n * var ua = new F.service.User({\n * account: 'acme-simulations',\n * token: 'user-or-project-access-token'\n * });\n * ua.getById('42836d4b-5b61-4fe4-80eb-3136e956ee5c');\n *\n * **Parameters**\n * @param {string} `userId` The user id for the end user in your team.\n * @param {object} `options` (Optional) Overrides for configuration options.\n */\n\n getById: function (userId, options) {\n return publicAPI.get({ id: userId }, options);\n }\n };\n\n $.extend(this, publicAPI);\n};\n\n\n\n\n","/**\n *\n * ## Member API Adapter\n *\n * The Member API Adapter provides methods to look up information about end users for your project and how they are divided across groups. It is based on query capabilities of the underlying RESTful [Member API](../../../rest_apis/user_management/member/).\n *\n * This is only needed for Authenticated projects, that is, team projects with [end users and groups](../../../groups_and_end_users/). For example, if some of your end users are facilitators, or if your end users should be treated differently based on which group they are in, use the Member API to find that information.\n *\n * var ma = new F.service.Member({ token: 'user-or-project-access-token' });\n * ma.getGroupsForUser({ userId: 'b6b313a3-ab84-479c-baea-206f6bff337' });\n * ma.getGroupDetails({ groupId: '00b53308-9833-47f2-b21e-1278c07d53b8' });\n */\n\n'use strict';\n\nvar ConfigService = require('./configuration-service');\nvar TransportFactory = require('../transport/http-transport-factory');\nvar SessionManager = require('../store/session-manager');\nvar _pick = require('../util/object-util')._pick;\nvar apiEndpoint = 'member/local';\n\nmodule.exports = function (config) {\n var defaults = {\n /**\n * Epicenter user id. Defaults to a blank string.\n * @type {string}\n */\n userId: undefined,\n\n /**\n * Epicenter group id. Defaults to a blank string. Note that this is the group *id*, not the group *name*.\n * @type {string}\n */\n groupId: undefined,\n\n /**\n * Options to pass on to the underlying transport layer. All jquery.ajax options at http://api.jquery.com/jQuery.ajax/ are available. Defaults to empty object.\n * @type {object}\n */\n transport: {}\n };\n this.sessionManager = new SessionManager();\n var serviceOptions = this.sessionManager.getMergedOptions(defaults, config);\n var urlConfig = new ConfigService(serviceOptions).get('server');\n\n var transportOptions = $.extend(true, {}, serviceOptions.transport, {\n url: urlConfig.getAPIPath(apiEndpoint)\n });\n\n if (serviceOptions.token) {\n transportOptions.headers = {\n 'Authorization': 'Bearer ' + serviceOptions.token\n };\n }\n var http = new TransportFactory(transportOptions, serviceOptions);\n\n var getFinalParams = function (params) {\n if (typeof params === 'object') {\n return $.extend(true, serviceOptions, params);\n }\n return serviceOptions;\n };\n\n var patchUserActiveField = function (params, active, options) {\n var httpOptions = $.extend(true, serviceOptions, options, {\n url: urlConfig.getAPIPath(apiEndpoint) + params.groupId + '/' + params.userId\n });\n\n return http.patch({ active: active }, httpOptions);\n };\n\n var publicAPI = {\n\n /**\n * Retrieve details about all of the group memberships for one end user. The membership details are returned in an array, with one element (group record) for each group to which the end user belongs.\n *\n * In the membership array, each group record includes the group id, project id, account (team) id, and an array of members. However, only the user whose userId is included in the call is listed in the members array (regardless of whether there are other members in this group).\n *\n * **Example**\n *\n * var ma = new F.service.Member({ token: 'user-or-project-access-token' });\n * ma.getGroupsForUser('42836d4b-5b61-4fe4-80eb-3136e956ee5c')\n * .then(function(memberships){\n * for (var i=0; i\n * // \n * // \n * // \n * // \n * //\n * $('#upload-file').on('submit', function (e) {\n * e.preventDefault();\n * var filename = $('#filename').val();\n * var data = new FormData();\n * var inputControl = $('#file')[0];\n * data.append('file', inputControl.files[0], filename);\n *\n * aa.create(filename, data, { scope: 'user' });\n * });\n *\n */\n\n'use strict';\n\nvar ConfigService = require('./configuration-service');\nvar TransportFactory = require('../transport/http-transport-factory');\nvar _pick = require('../util/object-util')._pick;\nvar SessionManager = require('../store/session-manager');\n\nvar apiEndpoint = 'asset';\n\nmodule.exports = function (config) {\n var defaults = {\n /**\n * For projects that require authentication, pass in the user access token (defaults to empty string). If the user is already logged in to Epicenter, the user access token is already set in a cookie and automatically loaded from there. (See [more background on access tokens](../../../project_access/)).\n * @see [Authentication API Service](../auth-api-service/) for getting tokens.\n * @type {String}\n */\n token: undefined,\n /**\n * The account id. In the Epicenter UI, this is the **Team ID** (for team projects). If left undefined, taken from the URL.\n * @type {String}\n */\n account: undefined,\n /**\n * The project id. If left undefined, taken from the URL.\n * @type {String}\n */\n project: undefined,\n /**\n * The group name. Defaults to session's `groupName`.\n * @type {String}\n */\n group: undefined,\n /**\n * The user id. Defaults to session's `userId`.\n * @type {String}\n */\n userId: undefined,\n /**\n * The scope for the asset. Valid values are: `user`, `group`, and `project`. See above for the required permissions to write to each scope. Defaults to `user`, meaning the current end user or a facilitator in the end user's group can edit the asset.\n * @type {String}\n */\n scope: 'user',\n /**\n * Determines if a request to list the assets in a scope includes the complete URL for each asset (`true`), or only the file names of the assets (`false`). Defaults to `true`.\n * @type {boolean}\n */\n fullUrl: true,\n /**\n * The transport object contains the options passed to the XHR request.\n * @type {object}\n */\n transport: {\n processData: false\n }\n };\n this.sessionManager = new SessionManager();\n var serviceOptions = this.sessionManager.getMergedOptions(defaults, config);\n var urlConfig = new ConfigService(serviceOptions).get('server');\n\n if (!serviceOptions.account) {\n serviceOptions.account = urlConfig.accountPath;\n }\n\n if (!serviceOptions.project) {\n serviceOptions.project = urlConfig.projectPath;\n }\n\n var transportOptions = $.extend(true, {}, serviceOptions.transport, {\n url: urlConfig.getAPIPath(apiEndpoint)\n });\n\n if (serviceOptions.token) {\n transportOptions.headers = {\n 'Authorization': 'Bearer ' + serviceOptions.token\n };\n }\n\n var http = new TransportFactory(transportOptions);\n\n var assetApiParams = ['encoding', 'data', 'contentType'];\n var scopeConfig = {\n user: ['scope', 'account', 'project', 'group', 'userId'],\n group: ['scope', 'account', 'project', 'group'],\n project: ['scope', 'account', 'project'],\n };\n\n var validateFilename = function (filename) {\n if (!filename) {\n throw new Error('filename is needed.');\n }\n };\n\n var validateUrlParams = function (options) {\n var partKeys = scopeConfig[options.scope];\n if (!partKeys) {\n throw new Error('scope parameter is needed.');\n }\n\n $.each(partKeys, function () {\n if (!options[this]) {\n throw new Error(this + ' parameter is needed.');\n }\n });\n };\n\n var buildUrl = function (filename, options) {\n validateUrlParams(options);\n var partKeys = scopeConfig[options.scope];\n var parts = $.map(partKeys, function (key) {\n return options[key];\n });\n if (filename) {\n // This prevents adding a trailing / in the URL as the Asset API\n // does not work correctly with it\n filename = '/' + filename;\n }\n return urlConfig.getAPIPath(apiEndpoint) + parts.join('/') + filename;\n };\n\n // Private function, all requests follow a more or less same approach to\n // use the Asset API and the difference is the HTTP verb\n //\n // @param {string} `method` (Required) HTTP verb\n // @param {string} `filename` (Required) Name of the file to delete/replace/create\n // @param {object} `params` (Optional) Body parameters to send to the Asset API\n // @param {object} `options` (Optional) Options object to override global options.\n var upload = function (method, filename, params, options) {\n validateFilename(filename);\n // make sure the parameter is clean\n method = method.toLowerCase();\n var contentType = params instanceof FormData === true ? false : 'application/json';\n if (contentType === 'application/json') {\n // whitelist the fields that we actually can send to the api\n params = _pick(params, assetApiParams);\n } else { // else we're sending form data which goes directly in request body\n // For multipart/form-data uploads the filename is not set in the URL,\n // it's getting picked by the FormData field filename.\n filename = method === 'post' || method === 'put' ? '' : filename;\n }\n var urlOptions = $.extend({}, serviceOptions, options);\n var url = buildUrl(filename, urlOptions);\n var createOptions = $.extend(true, {}, urlOptions, { url: url, contentType: contentType });\n\n return http[method](params, createOptions);\n };\n\n var publicAPI = {\n /**\n * Creates a file in the Asset API. The server returns an error (status code `409`, conflict) if the file already exists, so\n * check first with a `list()` or a `get()`.\n *\n * **Example**\n *\n * var aa = new F.service.Asset({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * group: 'team1',\n * userId: ''\n * });\n *\n * // create a new asset using encoded text\n * aa.create('test.txt', {\n * encoding: 'BASE_64',\n * data: 'VGhpcyBpcyBhIHRlc3QgZmlsZS4=',\n * contentType: 'text/plain'\n * }, { scope: 'user' });\n *\n * // alternatively, create a new asset using a file uploaded through a form\n * // this sample code goes with an html form that looks like this:\n * //\n * //
\n * // \n * // \n * // \n * //
\n * //\n * $('#upload-file').on('submit', function (e) {\n * e.preventDefault();\n * var filename = $('#filename').val();\n * var data = new FormData();\n * var inputControl = $('#file')[0];\n * data.append('file', inputControl.files[0], filename);\n *\n * aa.create(filename, data, { scope: 'user' });\n * });\n *\n *\n * **Parameters**\n * @param {string} `filename` (Required) Name of the file to create.\n * @param {object} `params` (Optional) Body parameters to send to the Asset API. Required if the `options.transport.contentType` is `application/json`, otherwise ignored.\n * @param {string} `params.encoding` Either `HEX` or `BASE_64`. Required if `options.transport.contentType` is `application/json`.\n * @param {string} `params.data` The encoded data for the file. Required if `options.transport.contentType` is `application/json`.\n * @param {string} `params.contentType` The mime type of the file. Optional.\n * @param {object} `options` (Optional) Options object to override global options.\n *\n */\n create: function (filename, params, options) {\n return upload('post', filename, params, options);\n },\n\n /**\n * Gets a file from the Asset API, fetching the asset content. (To get a list\n * of the assets in a scope, use `list()`.)\n *\n * **Parameters**\n * @param {string} `filename` (Required) Name of the file to retrieve.\n * @param {object} `options` (Optional) Options object to override global options.\n *\n */\n get: function (filename, options) {\n var getServiceOptions = _pick(serviceOptions, ['scope', 'account', 'project', 'group', 'userId']);\n var urlOptions = $.extend({}, getServiceOptions, options);\n var url = buildUrl(filename, urlOptions);\n var getOptions = $.extend(true, {}, urlOptions, { url: url });\n\n return http.get({}, getOptions);\n },\n\n /**\n * Gets the list of the assets in a scope.\n *\n * **Example**\n *\n * aa.list({ fullUrl: true }).then(function(fileList){\n * console.log('array of files = ', fileList);\n * });\n *\n * **Parameters**\n * @param {object} `options` (Optional) Options object to override global options.\n * @param {string} `options.scope` (Optional) The scope (`user`, `group`, `project`).\n * @param {boolean} `options.fullUrl` (Optional) Determines if the list of assets in a scope includes the complete URL for each asset (`true`), or only the file names of the assets (`false`).\n *\n */\n list: function (options) {\n var dtd = $.Deferred();\n var me = this;\n var urlOptions = $.extend({}, serviceOptions, options);\n var url = buildUrl('', urlOptions);\n var getOptions = $.extend(true, {}, urlOptions, { url: url });\n var fullUrl = getOptions.fullUrl;\n\n if (!fullUrl) {\n return http.get({}, getOptions);\n }\n\n http.get({}, getOptions)\n .then(function (files) {\n var fullPathFiles = $.map(files, function (file) {\n return buildUrl(file, urlOptions);\n });\n dtd.resolve(fullPathFiles, me);\n })\n .fail(dtd.reject);\n\n return dtd.promise();\n },\n\n /**\n * Replaces an existing file in the Asset API.\n *\n * **Example**\n *\n * // replace an asset using encoded text\n * aa.replace('test.txt', {\n * encoding: 'BASE_64',\n * data: 'VGhpcyBpcyBhIHNlY29uZCB0ZXN0IGZpbGUu',\n * contentType: 'text/plain'\n * }, { scope: 'user' });\n *\n * // alternatively, replace an asset using a file uploaded through a form\n * // this sample code goes with an html form that looks like this:\n * //\n * //
\n * // \n * // \n * // \n * //
\n * //\n * $('#replace-file').on('submit', function (e) {\n * e.preventDefault();\n * var filename = $('#replace-filename').val();\n * var data = new FormData();\n * var inputControl = $('#file')[0];\n * data.append('file', inputControl.files[0], filename);\n *\n * aa.replace(filename, data, { scope: 'user' });\n * });\n *\n * **Parameters**\n * @param {string} `filename` (Required) Name of the file being replaced.\n * @param {object} `params` (Optional) Body parameters to send to the Asset API. Required if the `options.transport.contentType` is `application/json`, otherwise ignored.\n * @param {string} `params.encoding` Either `HEX` or `BASE_64`. Required if `options.transport.contentType` is `application/json`.\n * @param {string} `params.data` The encoded data for the file. Required if `options.transport.contentType` is `application/json`.\n * @param {string} `params.contentType` The mime type of the file. Optional.\n * @param {object} `options` (Optional) Options object to override global options.\n *\n */\n replace: function (filename, params, options) {\n return upload('put', filename, params, options);\n },\n\n /**\n * Deletes a file from the Asset API.\n *\n * **Example**\n *\n * aa.delete(sampleFileName);\n *\n * **Parameters**\n * @param {string} `filename` (Required) Name of the file to delete.\n * @param {object} `options` (Optional) Options object to override global options.\n *\n */\n delete: function (filename, options) {\n return upload('delete', filename, {}, options);\n },\n\n assetUrl: function (filename, options) {\n var urlOptions = $.extend({}, serviceOptions, options);\n return buildUrl(filename, urlOptions);\n }\n };\n $.extend(this, publicAPI);\n};\n","/**\n * @class Cookie Storage Service\n *\n * @example\n * var people = require('cookie-store')({ root: 'people' });\n people\n .save({lastName: 'smith' })\n\n */\n\n\n'use strict';\n\n// Thin document.cookie wrapper to allow unit testing\nvar Cookie = function () {\n this.get = function () {\n return document.cookie;\n };\n\n this.set = function (newCookie) {\n document.cookie = newCookie;\n };\n};\n\nmodule.exports = function (config) {\n var host = window.location.hostname;\n var defaults = {\n /**\n * Name of collection\n * @type { string}\n */\n root: '/',\n\n domain: '.' + host,\n cookie: new Cookie()\n };\n this.serviceOptions = $.extend({}, defaults, config);\n\n var publicAPI = {\n // * TBD\n // * Query collection; uses MongoDB syntax\n // * @see \n // *\n // * @param { string} qs Query Filter\n // * @param { string} limiters @see \n // *\n // * @example\n // * cs.query(\n // * { name: 'John', className: 'CSC101' },\n // * {limit: 10}\n // * )\n\n // query: function (qs, limiters) {\n\n // },\n\n /**\n * Save cookie value\n * @param { string|Object} key If given a key save values under it, if given an object directly, save to top-level api\n * @param {Object} value (Optional)\n * @param {Object} options Overrides for service options\n *\n * @return {*} The saved value\n *\n * @example\n * cs.set('person', { firstName: 'john', lastName: 'smith' });\n * cs.set({ name:'smith', age:'32' });\n */\n set: function (key, value, options) {\n var setOptions = $.extend(true, {}, this.serviceOptions, options);\n\n var domain = setOptions.domain;\n var path = setOptions.root;\n var cookie = setOptions.cookie;\n\n cookie.set(encodeURIComponent(key) + '=' +\n encodeURIComponent(value) +\n (domain ? '; domain=' + domain : '') +\n (path ? '; path=' + path : '')\n );\n\n return value;\n },\n\n /**\n * Load cookie value\n * @param { string|Object} key If given a key save values under it, if given an object directly, save to top-level api\n * @return {*} The value stored\n *\n * @example\n * cs.get('person');\n */\n get: function (key) {\n var cookie = this.serviceOptions.cookie;\n var cookieReg = new RegExp('(?:^|;)\\\\s*' + encodeURIComponent(key).replace(/[\\-\\.\\+\\*]/g, '\\\\$&') + '\\\\s*\\\\=\\\\s*([^;]*).*$');\n var res = cookieReg.exec(cookie.get());\n var val = res ? decodeURIComponent(res[1]) : null;\n return val;\n },\n\n /**\n * Removes key from collection\n * @param { string} key key to remove\n * @return { string} key The key removed\n *\n * @example\n * cs.remove('person');\n */\n remove: function (key, options) {\n var remOptions = $.extend(true, {}, this.serviceOptions, options);\n\n var domain = remOptions.domain;\n var path = remOptions.root;\n var cookie = remOptions.cookie;\n\n cookie.set(encodeURIComponent(key) +\n '=; expires=Thu, 01 Jan 1970 00:00:00 GMT' +\n (domain ? '; domain=' + domain : '') +\n (path ? '; path=' + path : '')\n );\n return key;\n },\n\n /**\n * Removes collection being referenced\n * @return { array} keys All the keys removed\n */\n destroy: function () {\n var cookie = this.serviceOptions.cookie;\n var aKeys = cookie.get().replace(/((?:^|\\s*;)[^\\=]+)(?=;|$)|^\\s*|\\s*(?:\\=[^;]*)?(?:\\1|$)/g, '').split(/\\s*(?:\\=[^;]*)?;\\s*/);\n for (var nIdx = 0; nIdx < aKeys.length; nIdx++) {\n var cookieKey = decodeURIComponent(aKeys[nIdx]);\n this.remove(cookieKey);\n }\n return aKeys;\n }\n };\n\n $.extend(this, publicAPI);\n};\n","/**\n Decides type of store to provide\n*/\n\n'use strict';\n// var isNode = false; FIXME: Browserify/minifyify has issues with the next link\n// var store = (isNode) ? require('./session-store') : require('./cookie-store');\nvar store = require('./cookie-store');\n\nmodule.exports = store;\n","'use strict';\nvar RunService = require('../service/run-api-service');\n\nvar defaults = {\n validFilter: { saved: true }\n};\n\nfunction ScenarioManager(options) {\n this.options = $.extend(true, {}, defaults, options);\n this.runService = this.options.run || new RunService(this.options);\n}\n\nScenarioManager.prototype = {\n getRuns: function (filter) {\n this.filter = $.extend(true, {}, this.options.validFilter, filter);\n return this.runService.query(this.filter);\n },\n\n loadVariables: function (vars) {\n return this.runService.query(this.filter, { include: vars });\n },\n\n save: function (run, meta) {\n return this._getService(run).save($.extend(true, {}, { saved: true }, meta));\n },\n\n archive: function (run) {\n return this._getService(run).save({ saved: false });\n },\n\n _getService: function (run) {\n if (typeof run === 'string') {\n return new RunService($.extend(true, {}, this.options, { filter: run }));\n }\n\n if (typeof run === 'object' && run instanceof RunService) {\n return run;\n }\n\n throw new Error('Save method requires a run service or a runId');\n },\n\n getRun: function (runId) {\n return new RunService($.extend(true, {}, this.options, { filter: runId }));\n }\n};\n\nmodule.exports = ScenarioManager;\n\n","/**\n* ## Run Manager\n*\n* The Run Manager gives you access to runs for your project. This allows you to read and update variables, call operations, etc. Additionally, the Run Manager gives you control over run creation depending on run states. Specifically, you can select [run creation strategies (rules)](../../strategy/) for which runs end users of your project work with when they log in to your project.\n*\n* There are many ways to create new runs, including the Epicenter.js [Run Service](../run-api-service/), the RESFTful [Run API](../../../rest_apis/aggregate_run_api) and the [Model Run API](../../../rest_apis/other_apis/model_apis/run/). However, for some projects it makes more sense to pick up where the user left off, using an existing run. And in some projects, whether to create a new run or use an existing one is conditional, for example based on characteristics of the existing run or your own knowledge about the model. The Run Manager provides this level of control: your call to `getRun()`, rather than always returning a new run, returns a run based on the strategy you've specified. (Note that many of the Epicenter sample projects use a Run Service directly, because generally the sample projects are played in one end user session and don't care about run states or run strategies.)\n*\n*\n* ### Using the Run Manager to create and access runs\n*\n* To use the Run Manager, instantiate it by passing in:\n*\n* * `run`: (required) Run object. Must contain:\n* * `account`: Epicenter account id (**Team ID** for team projects, **User ID** for personal projects).\n* * `project`: Epicenter project id.\n* * `model`: The name of your primary model file. (See more on [Writing your Model](../../../writing_your_model/).)\n* * `scope`: (optional) Scope object for the run, for example `scope.group` with value of the name of the group.\n* * `server`: (optional) An object with one field, `host`. The value of `host` is the string `api.forio.com`, the URI of the Forio server. This is automatically set, but you can pass it explicitly if desired. It is most commonly used for clarity when you are [hosting an Epicenter project on your own server](../../../how_to/self_hosting/).\n* * `files`: (optional) If and only if you are using a Vensim model and you have additional data to pass in to your model, you can pass a `files` object with the names of the files, for example: `\"files\": {\"data\": \"myExtraData.xls\"}`. (Note that you'll also need to add this same files object to your Vensim [configuration file](../../../model_code/vensim/).) See the [underlying Model Run API](../../../rest_apis/other_apis/model_apis/run/#post-creating-a-new-run-for-this-project) for additional information.\n*\n* * `strategy`: (optional) Run creation strategy for when to create a new run and when to reuse an end user's existing run. See [Run Manager Strategies](../../strategy/) for details. Defaults to `new-if-initialized`.\n*\n* * `sessionKey`: (optional) Name of browser cookie in which to store run information, including run id. Many conditional strategies, including the provided strategies, rely on this browser cookie to store the run id and help make the decision of whether to create a new run or use an existing one. The name of this cookie defaults to `epicenter-scenario` and can be set with the `sessionKey` parameter.\n*\n*\n* After instantiating a Run Manager, make a call to `getRun()` whenever you need to access a run for this end user. The `RunManager.run` contains the instantiated [Run Service](../run-api-service/). The Run Service allows you to access variables, call operations, etc.\n*\n* **Example**\n*\n* var rm = new F.manager.RunManager({\n* run: {\n* account: 'acme-simulations',\n* project: 'supply-chain-game',\n* model: 'supply-chain-model.jl',\n* server: { host: 'api.forio.com' }\n* },\n* strategy: 'always-new',\n* sessionKey: 'epicenter-session'\n* });\n* rm.getRun()\n* .then(function(run) {\n* // the return value of getRun() is a run object\n* var thisRunId = run.id;\n* // the RunManager.run also contains the instantiated Run Service,\n* // so any Run Service method is valid here\n* rm.run.do('runModel');\n* })\n*\n*/\n\n'use strict';\nvar strategiesMap = require('./run-strategies/strategies-map');\nvar specialOperations = require('./special-operations');\nvar RunService = require('../service/run-api-service');\n\n\nfunction patchRunService(service, manager) {\n if (service.patched) {\n return service;\n }\n\n var orig = service.do;\n service.do = function (operation, params, options) {\n var reservedOps = Object.keys(specialOperations);\n if (reservedOps.indexOf(operation) === -1) {\n return orig.apply(service, arguments);\n } else {\n return specialOperations[operation].call(service, params, options, manager);\n }\n };\n\n service.patched = true;\n\n return service;\n}\n\n\n\nvar defaults = {\n /**\n * Run creation strategy for when to create a new run and when to reuse an end user's existing run. See [Run Manager Strategies](../../strategy/) for details. Defaults to `new-if-initialized`.\n * @type {String}\n */\n\n strategy: 'new-if-initialized'\n};\n\nfunction RunManager(options) {\n this.options = $.extend(true, {}, defaults, options);\n\n if (this.options.run instanceof RunService) {\n this.run = this.options.run;\n } else {\n this.run = new RunService(this.options.run);\n }\n\n patchRunService(this.run, this);\n\n var StrategyCtor = typeof this.options.strategy === 'function' ? this.options.strategy : strategiesMap[this.options.strategy];\n\n if (!StrategyCtor) {\n throw new Error('Specified run creation strategy was invalid:', this.options.strategy);\n }\n\n this.strategy = new StrategyCtor(this.run, this.options);\n}\n\nRunManager.prototype = {\n /**\n * Returns the run object for a 'good' run.\n *\n * A good run is defined by the strategy. For example, if the strategy is `always-new`, the call\n * to `getRun()` always returns a newly created run; if the strategy is `new-if-persisted`,\n * `getRun()` creates a new run if the previous run is in a persisted state, otherwise\n * it returns the previous run. See [Run Manager Strategies](../../strategy/) for more on strategies.\n *\n * **Example**\n *\n * rm.getRun().then(function (run) {\n * // use the run object\n * var thisRunId = run.id;\n *\n * // use the Run Service object\n * rm.run.do('runModel');\n * });\n *\n * @return {$promise} Promise to complete the call.\n */\n getRun: function () {\n return this.strategy\n .getRun();\n },\n\n /**\n * Returns the run object for a new run, regardless of strategy: force creation of a new run.\n *\n * **Example**\n *\n * rm.reset().then(function (run) {\n * // use the (new) run object\n * var thisRunId = run.id;\n *\n * // use the Run Service object\n * rm.run.do('runModel');\n * });\n *\n * **Parameters**\n * @param {Object} `runServiceOptions` The options object to configure the Run Service. See [Run API Service](../run-api-service/) for more.\n */\n reset: function (runServiceOptions) {\n return this.strategy.reset(runServiceOptions);\n }\n};\n\nmodule.exports = RunManager;\n","/**\n* ## Authorization Manager\n*\n* The Authorization Manager provides an easy way to manage user authentication (logging in and out) and authorization (keeping track of tokens, sessions, and groups) for projects.\n*\n* The Authorization Manager is most useful for [team projects](../../../glossary/#team) with an access level of [Authenticated](../../../glossary/#access). These projects are accessed by [end users](../../../glossary/#users) who are members of one or more [groups](../../../glossary/#groups).\n*\n* #### Using the Authorization Manager\n*\n* To use the Authorization Manager, instantiate it. Then, make calls to any of the methods you need:\n*\n* var authMgr = new F.manager.AuthManager({\n* account: 'acme-simulations',\n* userName: 'enduser1',\n* password: 'passw0rd'\n* });\n* authMgr.login().then(function () {\n* authMgr.getCurrentUserSessionInfo();\n* });\n*\n*\n* The `options` object passed to the `F.manager.AuthManager()` call can include:\n*\n* * `account`: The account id for this `userName`. In the Epicenter UI, this is the **Team ID** (for team projects) or the **User ID** (for personal projects).\n* * `userName`: Email or username to use for logging in.\n* * `password`: Password for specified `userName`.\n* * `project`: The **Project ID** for the project to log this user into. Optional.\n* * `groupId`: Id of the group to which `userName` belongs. Required for end users if the `project` is specified.\n*\n* If you prefer starting from a template, the Epicenter JS Libs [Login Component](../../#components) uses the Authorization Manager as well. This sample HTML page (and associated CSS and JS files) provides a login form for team members and end users of your project. It also includes a group selector for end users that are members of multiple groups.\n*/\n\n'use strict';\nvar AuthAdapter = require('../service/auth-api-service');\nvar MemberAdapter = require('../service/member-api-adapter');\nvar SessionManager = require('../store/session-manager');\nvar Buffer = require('buffer').Buffer;\nvar _pick = require('../util/object-util')._pick;\n\nvar defaults = {\n requiresGroup: true\n};\n\nfunction AuthManager(options) {\n options = $.extend(true, {}, defaults, options);\n this.sessionManager = new SessionManager(options);\n this.options = this.sessionManager.getMergedOptions();\n\n this.isLocal = this.options.isLocal;\n this.authAdapter = new AuthAdapter(this.options);\n}\n\nvar _findUserInGroup = function (members, id) {\n for (var j = 0; j 1) {\n if (groupId) {\n var filteredGroups = $.grep(memberInfo, function (resGroup) {\n return resGroup.groupId === groupId;\n });\n group = filteredGroups.length === 1 ? filteredGroups[0] : null;\n }\n }\n\n if (group) {\n var groupData = {\n 'groupId': group.groupId,\n 'groupName': group.name,\n 'isFac': _findUserInGroup(group.members, userInfo.user_id).role === 'facilitator'\n };\n var sessionInfoWithGroup = $.extend({}, sessionInfo, groupData);\n sessionInfo.groups[project] = groupData;\n _this.sessionManager.saveSession(sessionInfoWithGroup, adapterOptions);\n outSuccess.apply(this, [data]);\n $d.resolve(data);\n } else {\n handleGroupError('This user is associated with more than one group. Please specify a group id to log into and try again', 403, data);\n }\n }).fail($d.reject);\n };\n\n adapterOptions.success = handleSuccess;\n adapterOptions.error = function (response) {\n if (adapterOptions.account) {\n // Try to login as a system user\n adapterOptions.account = null;\n adapterOptions.error = function () {\n outError.apply(this, arguments);\n $d.reject(response);\n };\n\n _this.authAdapter.login(adapterOptions);\n return;\n }\n\n outError.apply(this, arguments);\n $d.reject(response);\n };\n\n this.authAdapter.login(adapterOptions);\n return $d.promise();\n },\n\n /**\n * Logs user out by clearing all session information.\n *\n * **Example**\n *\n * authMgr.logout();\n *\n * **Parameters**\n *\n * @param {Object} `options` (Optional) Overrides for configuration options.\n */\n logout: function (options) {\n var _this = this;\n var adapterOptions = this.sessionManager.getMergedOptions(options);\n\n var removeCookieFn = function (response) {\n _this.sessionManager.removeSession();\n };\n\n return this.authAdapter.logout(adapterOptions).done(removeCookieFn);\n },\n\n /**\n * Returns the existing user access token if the user is already logged in. Otherwise, logs the user in, creating a new user access token, and returns the new token. (See [more background on access tokens](../../../project_access/)).\n *\n * **Example**\n *\n * authMgr.getToken()\n * .then(function (token) {\n * console.log('My token is ', token);\n * });\n *\n * **Parameters**\n * @param {Object} `options` (Optional) Overrides for configuration options.\n */\n getToken: function (options) {\n var httpOptions = this.sessionManager.getMergedOptions(options);\n\n var session = this.sessionManager.getSession();\n var $d = $.Deferred();\n //jshint camelcase: false\n //jscs:disable\n if (session.auth_token) {\n $d.resolve(session.auth_token);\n } else {\n this.login(httpOptions).then($d.resolve);\n }\n return $d.promise();\n },\n\n /**\n * Returns an array of group records, one for each group of which the current user is a member. Each group record includes the group `name`, `account`, `project`, and `groupId`.\n *\n * If some end users in your project are members of multiple groups, this is a useful method to call on your project's login page. When the user attempts to log in, you can use this to display the groups of which the user is member, and have the user select the correct group to log in to for this session.\n *\n * **Example**\n *\n * // get groups for current user\n * var sessionObj = authMgr.getCurrentUserSessionInfo();\n * authMgr.getUserGroups({ userId: sessionObj.userId, token: sessionObj.auth_token })\n * .then(function (groups) {\n * for (var i=0; i < groups.length; i++)\n * { console.log(groups[i].name); }\n * });\n *\n * // get groups for particular user\n * authMgr.getUserGroups({userId: 'b1c19dda-2d2e-4777-ad5d-3929f17e86d3', token: savedProjAccessToken });\n *\n * **Parameters**\n * @param {Object} `params` Object with a userId and token properties.\n * @param {String} `params.userId` The userId. If looking up groups for the currently logged in user, this is in the session information. Otherwise, pass a string.\n * @param {String} `params.token` The authorization credentials (access token) to use for checking the groups for this user. If looking up groups for the currently logged in user, this is in the session information. A team member's token or a project access token can access all the groups for all end users in the team or project.\n * @param {Object} `options` (Optional) Overrides for configuration options.\n */\n getUserGroups: function (params, options) {\n var adapterOptions = this.sessionManager.getMergedOptions({ success: $.noop }, options);\n var $d = $.Deferred();\n var outSuccess = adapterOptions.success;\n\n adapterOptions.success = function (memberInfo) {\n // The member API is at the account scope, we filter by project\n if (adapterOptions.project) {\n memberInfo = $.grep(memberInfo, function (group) {\n return group.project === adapterOptions.project;\n });\n }\n\n outSuccess.apply(this, [memberInfo]);\n $d.resolve(memberInfo);\n };\n\n var memberAdapter = new MemberAdapter({ token: params.token });\n memberAdapter.getGroupsForUser(params, adapterOptions).fail($d.reject);\n return $d.promise();\n },\n\n /**\n * Returns session information for the current user, including the `userId`, `account`, `project`, `groupId`, `groupName`, `isFac` (whether the end user is a facilitator of this group), and `auth_token` (user access token).\n *\n * *Important*: This method is synchronous. The session information is returned immediately in an object; no callbacks or promises are needed.\n *\n * Session information is stored in a cookie in the browser.\n *\n * **Example**\n *\n * var sessionObj = authMgr.getCurrentUserSessionInfo();\n *\n * **Parameters**\n * @param {Object} `options` (Optional) Overrides for configuration options.\n */\n getCurrentUserSessionInfo: function (options) {\n return this.sessionManager.getSession(options);\n },\n\n // (replace with /* */ comment block, to make visible in docs, once EPICENTER-1939 is complete)\n //\n // Add one or more groups to the current session. \n //\n // This method assumes that the project and group exist and the user specified in the session is part of this project and group.\n //\n // Returns the new session object.\n //\n // **Example**\n //\n // authMgr.addGroups({ project: 'hello-world', groupName: 'groupName', groupId: 'groupId' });\n // authMgr.addGroups([{ project: 'hello-world', groupName: 'groupName', groupId: 'groupId' }, { project: ... }]);\n //\n // **Parameters**\n // @param {object|array} `groups` (Required) The group object must contain the `project` (**Project ID**) and `groupName` properties.\n // @param {string} `group.isFac` (optional) Defaults to `false`. Set to `true` if the user in the session should be a facilitator in this group.\n // @param {string} `group.groupId` (optional) Defaults to undefined. Needed mostly for the Members API.\n //\n addGroups: function (groups) {\n var session = this.getCurrentUserSessionInfo();\n var isArray = Array.isArray(groups);\n groups = isArray ? groups : [groups];\n\n $.each(groups, function (index, group) {\n var extendedGroup = $.extend({}, { isFac: false }, group);\n var project = extendedGroup.project;\n var validProps = ['groupName', 'groupId', 'isFac'];\n if (!project || !extendedGroup.groupName) {\n throw new Error('No project or groupName specified.');\n }\n // filter object\n extendedGroup = _pick(extendedGroup, validProps);\n session.groups[project] = extendedGroup;\n });\n this.sessionManager.saveSession(session);\n return session;\n }\n});\n\nmodule.exports = AuthManager;\n","/**\n* ## World Manager\n*\n* As discussed under the [World API Adapter](../world-api-adapter/), a [run](../../../glossary/#run) is a collection of end user interactions with a project and its model. For building multiplayer simulations you typically want multiple end users to share the same set of interactions, and work within a common state. Epicenter allows you to create \"worlds\" to handle such cases.\n*\n* The World Manager provides an easy way to track and access the current world and run for particular end users. It is typically used in pages that end users will interact with. (The related [World API Adapter](../world-api-adapter/) handles creating multiplayer worlds, and adding and removing end users and runs from a world. Because of this, typically the World Adapter is used for facilitator pages in your project.)\n*\n* ### Using the World Manager\n*\n* To use the World Manager, instantiate it. Then, make calls to any of the methods you need.\n*\n* When you instantiate a World Manager, the world's account id, project id, and group are automatically taken from the session (thanks to the [Authentication Service](../auth-api-service)).\n*\n* Note that the World Manager does *not* create worlds automatically. (This is different than the [Run Manager](../run-manager).) However, you can pass in specific options to any runs created by the manager, using a `run` object.\n*\n* The parameters for creating a World Manager are:\n*\n* * `account`: The **Team ID** in the Epicenter user interface for this project.\n* * `project`: The **Project ID** for this project.\n* * `group`: The **Group Name** for this world.\n* * `run`: Options to use when creating new runs with the manager, e.g. `run: { files: ['data.xls'] }`.\n* * `run.model`: The name of the primary model file for this project. Required if you have not already passed it in as part of the `options` parameter for an enclosing call.\n*\n* For example:\n*\n* var wMgr = new F.manager.WorldManager({\n* account: 'acme-simulations',\n* project: 'supply-chain-game',\n* run: { model: 'supply-chain.py' },\n* group: 'team1'\n* });\n*\n* wMgr.getCurrentRun();\n*/\n\n'use strict';\n\nvar WorldApi = require('../service/world-api-adapter');\nvar RunManager = require('./run-manager');\nvar AuthManager = require('./auth-manager');\nvar worldApi;\n\n// var defaults = {\n// account: '',\n// project: '',\n// group: '',\n// transport: {\n// }\n// };\n\n\nfunction buildStrategy(worldId, dtd) {\n\n return function Ctor(runService, options) {\n this.runService = runService;\n this.options = options;\n\n $.extend(this, {\n reset: function () {\n throw new Error('not implementd. Need api changes');\n },\n\n getRun: function () {\n var _this = this;\n //get or create!\n // Model is required in the options\n var model = this.options.run.model || this.options.model;\n return worldApi.getCurrentRunId({ model: model, filter: worldId })\n .then(function (runId) {\n return _this.runService.load(runId);\n })\n .then(function (run) {\n dtd.resolve.call(this, run, _this.runService);\n })\n .fail(dtd.reject);\n }\n }\n );\n };\n}\n\n\nmodule.exports = function (options) {\n this.options = options || { run: {}, world: {} };\n\n $.extend(true, this.options, this.options.run);\n $.extend(true, this.options, this.options.world);\n\n worldApi = new WorldApi(this.options);\n this._auth = new AuthManager();\n var _this = this;\n\n var api = {\n\n /**\n * Returns the current world (object) and an instance of the [World API Adapter](../world-api-adapter/).\n *\n * **Example**\n *\n * wMgr.getCurrentWorld()\n * .then(function(world, worldAdapter) {\n * console.log(world.id);\n * worldAdapter.getCurrentRunId();\n * });\n *\n * **Parameters**\n * @param {string} `userId` (Optional) The id of the user whose world is being accessed. Defaults to the user in the current session.\n * @param {string} `groupName` (Optional) The name of the group whose world is being accessed. Defaults to the group for the user in the current session.\n */\n getCurrentWorld: function (userId, groupName) {\n var session = this._auth.getCurrentUserSessionInfo();\n if (!userId) {\n userId = session.userId;\n }\n if (!groupName) {\n groupName = session.groupName;\n }\n return worldApi.getCurrentWorldForUser(userId, groupName);\n },\n\n /**\n * Returns the current run (object) and an instance of the [Run API Service](../run-api-service/).\n *\n * **Example**\n *\n * wMgr.getCurrentRun({model: 'myModel.py'})\n * .then(function(run, runService) {\n * console.log(run.id);\n * runService.do('startGame');\n * });\n *\n * **Parameters**\n * @param {string} `model` (Optional) The name of the model file. Required if not already passed in as `run.model` when the World Manager is created.\n */\n getCurrentRun: function (model) {\n var dtd = $.Deferred();\n var session = this._auth.getCurrentUserSessionInfo();\n var curUserId = session.userId;\n var curGroupName = session.groupName;\n\n function getAndRestoreLatestRun(world) {\n if (!world) {\n return dtd.reject({ error: 'The user is not part of any world!' });\n }\n\n var currentWorldId = world.id;\n var runOpts = $.extend(true, _this.options, { model: model });\n var strategy = buildStrategy(currentWorldId, dtd);\n var opt = $.extend(true, {}, {\n strategy: strategy,\n run: runOpts\n });\n var rm = new RunManager(opt);\n\n return rm.getRun()\n .then(function (run) {\n dtd.resolve(run, rm.runService, rm);\n });\n }\n\n this.getCurrentWorld(curUserId, curGroupName)\n .then(getAndRestoreLatestRun);\n\n return dtd.promise();\n }\n };\n\n $.extend(this, api);\n};\n","'use strict';\n\n/**\n * ## Epicenter Channel Manager\n *\n * The Epicenter platform provides a push channel, which allows you to publish and subscribe to messages within a [project](../../../glossary/#projects), [group](../../../glossary/#groups), or [multiplayer world](../../../glossary/#world). There are two main use cases for the channel: event notifications and chat messages.\n *\n * The Epicenter Channel Manager is a wrapper around the (more generic) [Channel Manager](../channel-manager/), to instantiate it with Epicenter-specific defaults. If you are interested in including a notification or chat feature in your project, using an Epicenter Channel Manager is probably the easiest way to get started.\n *\n * You'll need to include the `epicenter-multiplayer-dependencies.js` library in addition to the `epicenter.js` library in your project to use the Epicenter Channel Manager. See [Including Epicenter.js](../../#include).\n *\n * To use the Epicenter Channel Manager: instantiate it, get the channel of the scope you want ([user](../../../glossary/#users), [world](../../../glossary/#world), or [group](../../../glossary/#groups)), then use the channel's `subscribe()` and `publish()` methods to subscribe to topics or publish data to topics.\n *\n * var cm = new F.manager.ChannelManager();\n * var gc = cm.getGroupChannel();\n * gc.subscribe('broadcasts', callback);\n *\n * For additional background on Epicenter's push channel, see the introductory notes on the [Push Channel API](../../../rest_apis/multiplayer/channel/) page.\n *\n * The parameters for instantiating an Epicenter Channel Manager include:\n *\n * * `options` Object with details about the Epicenter project for this Epicenter Channel Manager instance.\n * * `options.account` The Epicenter account id (**Team ID** for team projects, **User ID** for personal projects).\n * * `options.project` Epicenter project id.\n * * `options.userName` Epicenter userName used for authentication.\n * * `options.userId` Epicenter user id used for authentication. Optional; `options.userName` is preferred.\n * * `options.token` Epicenter token used for authentication. (You can retrieve this using `authManager.getToken()` from the [Authorization Manager](../auth-manager/).)\n * * `options.allowAllChannels` If not included or if set to `false`, all channel paths are validated; if your project requires [Push Channel Authorization](../../../updating_your_settings/), you should use this option. If you want to allow other channel paths, set to `true`; this is not common.\n */\n\nvar ChannelManager = require('./channel-manager');\nvar classFrom = require('../util/inherit');\nvar urlService = require('../service/url-config-service');\nvar SessionManager = require('../store/session-manager');\n\nvar AuthManager = require('./auth-manager');\n\nvar validTypes = {\n project: true,\n group: true,\n world: true,\n user: true,\n data: true,\n general: true,\n chat: true\n};\nvar session = new AuthManager();\nvar getFromSettingsOrSessionOrError = function (value, sessionKeyName, settings) {\n if (!value) {\n var userInfo = session.getCurrentUserSessionInfo();\n if (settings && settings[sessionKeyName]) {\n value = settings[sessionKeyName];\n } else if (userInfo[sessionKeyName]) {\n value = userInfo[sessionKeyName];\n } else {\n throw new Error(sessionKeyName + ' not found. Please log-in again, or specify ' + sessionKeyName + ' explicitly');\n }\n }\n return value;\n};\nvar __super = ChannelManager.prototype;\nvar EpicenterChannelManager = classFrom(ChannelManager, {\n constructor: function (options) {\n this.sessionManager = new SessionManager();\n var defaultCometOptions = this.sessionManager.getMergedOptions(options);\n\n var urlOpts = urlService(defaultCometOptions.server);\n if (!defaultCometOptions.url) {\n //Default epicenter cometd endpoint\n defaultCometOptions.url = urlOpts.protocol + '://' + urlOpts.host + '/channel/subscribe';\n }\n\n if (defaultCometOptions.handshake === undefined) {\n var userName = defaultCometOptions.userName;\n var userId = defaultCometOptions.userId;\n var token = defaultCometOptions.token;\n if ((userName || userId) && token) {\n var userProp = userName ? 'userName' : 'userId';\n var ext = {\n authorization: 'Bearer ' + token\n };\n ext[userProp] = userName ? userName : userId;\n\n defaultCometOptions.handshake = {\n ext: ext\n };\n }\n }\n\n this.options = defaultCometOptions;\n return __super.constructor.call(this, defaultCometOptions);\n },\n\n /**\n * Creates and returns a channel, that is, an instance of a [Channel Service](../channel-service/).\n *\n * This method enforces Epicenter-specific channel naming: all channels requested must be in the form `/{type}/{account id}/{project id}/{...}`, where `type` is one of `run`, `data`, `user`, `world`, or `chat`.\n *\n * **Example**\n *\n * var cm = new F.manager.EpicenterChannelManager();\n * var channel = cm.getChannel('/group/acme/supply-chain-game/');\n *\n * channel.subscribe('topic', callback);\n * channel.publish('topic', { myData: 100 });\n *\n * **Parameters**\n * @param {Object|String} `options` (Optional) If string, assumed to be the base channel url. If object, assumed to be configuration options for the constructor.\n */\n getChannel: function (options) {\n if (options && typeof options !== 'object') {\n options = {\n base: options\n };\n }\n var channelOpts = $.extend({}, this.options, options);\n var base = channelOpts.base;\n if (!base) {\n throw new Error('No base topic was provided');\n }\n\n if (!channelOpts.allowAllChannels) {\n var baseParts = base.split('/');\n var channelType = baseParts[1];\n if (baseParts.length < 4) {\n throw new Error('Invalid channel base name, it must be in the form /{type}/{account id}/{project id}/{...}');\n }\n if (!validTypes[channelType]) {\n throw new Error('Invalid channel type');\n }\n }\n return __super.getChannel.apply(this, arguments);\n },\n\n /**\n * Create and return a publish/subscribe channel (from the underlying [Channel Manager](../channel-manager/)) for the given [group](../../../glossary/#groups). The group must exist in the account (team) and project provided.\n *\n * There are no notifications from Epicenter on this channel; all messages are user-originated.\n *\n * **Example**\n *\n * var cm = new F.manager.ChannelManager();\n * var gc = cm.getGroupChannel();\n * gc.subscribe('broadcasts', callback);\n *\n * **Return Value**\n *\n * * *Channel* Returns the channel (an instance of the [Channel Service](../channel-service/)).\n *\n * **Parameters**\n *\n * @param {String} `groupName` (Optional) Group to broadcast to. If not provided, picks up group from current session if end user is logged in.\n */\n getGroupChannel: function (groupName) {\n groupName = getFromSettingsOrSessionOrError(groupName, 'groupName', this.options);\n var account = getFromSettingsOrSessionOrError('', 'account', this.options);\n var project = getFromSettingsOrSessionOrError('', 'project', this.options);\n\n var baseTopic = ['/group', account, project, groupName].join('/');\n return __super.getChannel.call(this, { base: baseTopic });\n },\n\n /**\n * Create and return a publish/subscribe channel (from the underlying [Channel Manager](../channel-manager/)) for the given [world](../../../glossary/#world).\n *\n * This is typically used together with the [World Manager](../world-manager).\n *\n * **Example**\n *\n * var cm = new F.manager.ChannelManager();\n * var worldManager = new F.manager.WorldManager({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * group: 'team1',\n * run: { model: 'model.eqn' }\n * });\n * worldManager.getCurrentWorld().then(function (worldObject, worldAdapter) {\n * var worldChannel = cm.getWorldChannel(worldObject);\n * worldChannel.subscribe('', function (data) {\n * console.log(data);\n * });\n * });\n *\n * **Return Value**\n *\n * * *Channel* Returns the channel (an instance of the [Channel Service](../channel-service/)).\n *\n * **Parameters**\n *\n * @param {String|Object} `world` The world object or id.\n * @param {String} `groupName` (Optional) Group the world exists in. If not provided, picks up group from current session if end user is logged in.\n */\n getWorldChannel: function (world, groupName) {\n var worldid = ($.isPlainObject(world) && world.id) ? world.id : world;\n if (!worldid) {\n throw new Error('Please specify a world id');\n }\n groupName = getFromSettingsOrSessionOrError(groupName, 'groupName', this.options);\n var account = getFromSettingsOrSessionOrError('', 'account', this.options);\n var project = getFromSettingsOrSessionOrError('', 'project', this.options);\n\n var baseTopic = ['/world', account, project, groupName, worldid].join('/');\n return __super.getChannel.call(this, { base: baseTopic });\n },\n\n /**\n * Create and return a publish/subscribe channel (from the underlying [Channel Manager](../channel-manager/)) for the current [end user](../../../glossary/#users) in that user's current [world](../../../glossary/#world).\n *\n * This is typically used together with the [World Manager](../world-manager). Note that this channel only gets notifications for worlds currently in memory. (See more background on [persistence](../../../run_persistence).)\n *\n * **Example**\n *\n * var cm = new F.manager.ChannelManager();\n * var worldManager = new F.manager.WorldManager({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * group: 'team1',\n * run: { model: 'model.eqn' }\n * });\n * worldManager.getCurrentWorld().then(function (worldObject, worldAdapter) {\n * var userChannel = cm.getUserChannel(worldObject);\n * userChannel.subscribe('', function (data) {\n * console.log(data);\n * });\n * });\n *\n *\n * **Return Value**\n *\n * * *Channel* Returns the channel (an instance of the [Channel Service](../channel-service/)).\n *\n * **Parameters**\n *\n * @param {String|Object} `world` World object or id.\n * @param {String|Object} `user` (Optional) User object or id. If not provided, picks up user id from current session if end user is logged in.\n * @param {String} `groupName` (Optional) Group the world exists in. If not provided, picks up group from current session if end user is logged in.\n */\n getUserChannel: function (world, user, groupName) {\n var worldid = ($.isPlainObject(world) && world.id) ? world.id : world;\n if (!worldid) {\n throw new Error('Please specify a world id');\n }\n var userid = ($.isPlainObject(user) && user.id) ? user.id : user;\n userid = getFromSettingsOrSessionOrError(userid, 'userId', this.options);\n groupName = getFromSettingsOrSessionOrError(groupName, 'groupName', this.options);\n\n var account = getFromSettingsOrSessionOrError('', 'account', this.options);\n var project = getFromSettingsOrSessionOrError('', 'project', this.options);\n\n var baseTopic = ['/user', account, project, groupName, worldid, userid].join('/');\n return __super.getChannel.call(this, { base: baseTopic });\n },\n\n /**\n * Create and return a publish/subscribe channel (from the underlying [Channel Manager](../channel-manager/)) that automatically tracks the presence of an [end user](../../../glossary/#users), that is, whether the end user is currently online in this group and world. Notifications are automatically sent when the end user comes online, and when the end user goes offline (not present for more than 2 minutes). Useful in multiplayer games for letting each end user know whether other users in their shared world are also online.\n *\n * **Example**\n *\n * var cm = new F.manager.ChannelManager();\n * var worldManager = new F.manager.WorldManager({\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * model: 'model.eqn'\n * });\n * worldManager.getCurrentWorld().then(function (worldObject, worldService) {\n * var presenceChannel = cm.getPresenceChannel(worldObject);\n * presenceChannel.on('presence', function (evt, notification) {\n * console.log(notification.online, notification.userId);\n * });\n * });\n *\n *\n * **Return Value**\n *\n * * *Channel* Returns the channel (an instance of the [Channel Service](../channel-service/)).\n *\n * **Parameters**\n *\n * @param {String|Object} `world` World object or id.\n * @param {String|Object} `userid` (Optional) User object or id. If not provided, picks up user id from current session if end user is logged in.\n * @param {String} `groupName` (Optional) Group the world exists in. If not provided, picks up group from current session if end user is logged in.\n */\n getPresenceChannel: function (world, userid, groupName) {\n var worldid = ($.isPlainObject(world) && world.id) ? world.id : world;\n if (!worldid) {\n throw new Error('Please specify a world id');\n }\n userid = getFromSettingsOrSessionOrError(userid, 'userId', this.options);\n groupName = getFromSettingsOrSessionOrError(groupName, 'groupName', this.options);\n\n var account = getFromSettingsOrSessionOrError('', 'account', this.options);\n var project = getFromSettingsOrSessionOrError('', 'project', this.options);\n\n var baseTopic = ['/user', account, project, groupName, worldid].join('/');\n var channel = __super.getChannel.call(this, { base: baseTopic });\n\n var lastPingTime = { };\n\n var PING_INTERVAL = 6000;\n channel.subscribe('internal-ping-channel', function (notification) {\n var incomingUserId = notification.data.user;\n if (!lastPingTime[incomingUserId] && incomingUserId !== userid) {\n channel.trigger.call(channel, 'presence', { userId: incomingUserId, online: true });\n }\n lastPingTime[incomingUserId] = (new Date()).valueOf();\n });\n\n setInterval(function () {\n channel.publish('internal-ping-channel', { user: userid });\n\n $.each(lastPingTime, function (key, value) {\n var now = (new Date()).valueOf();\n if (value && value + (PING_INTERVAL * 2) < now) {\n lastPingTime[key] = null;\n channel.trigger.call(channel, 'presence', { userId: key, online: false });\n }\n });\n }, PING_INTERVAL);\n\n return channel;\n },\n\n /**\n * Create and return a publish/subscribe channel (from the underlying [Channel Manager](../channel-manager/)) for the given collection. (The collection name is specified in the `root` argument when the [Data Service](../data-api-service/) is instantiated.) Must be one of the collections in this account (team) and project.\n *\n * There are automatic notifications from Epicenter on this channel when data is created, updated, or deleted in this collection. See more on [automatic messages to the data channel](../../../rest_apis/multiplayer/channel/#data-messages).\n *\n * **Example**\n *\n * var cm = new F.manager.ChannelManager();\n * var dc = cm.getDataChannel('survey-responses');\n * dc.subscribe('', function(data, meta) {\n * console.log(data);\n *\n * // meta.date is time of change,\n * // meta.subType is the kind of change: new, update, or delete\n * // meta.path is the full path to the changed data\n * console.log(meta);\n * });\n *\n * **Return Value**\n *\n * * *Channel* Returns the channel (an instance of the [Channel Service](../channel-service/)).\n *\n * **Parameters**\n *\n * @param {String} `collection` Name of collection whose automatic notifications you want to receive.\n */\n getDataChannel: function (collection) {\n if (!collection) {\n throw new Error('Please specify a collection to listen on.');\n }\n var account = getFromSettingsOrSessionOrError('', 'account', this.options);\n var project = getFromSettingsOrSessionOrError('', 'project', this.options);\n var baseTopic = ['/data', account, project, collection].join('/');\n var channel = __super.getChannel.call(this, { base: baseTopic });\n\n //TODO: Fix after Epicenter bug is resolved\n var oldsubs = channel.subscribe;\n channel.subscribe = function (topic, callback, context, options) {\n var callbackWithCleanData = function (payload) {\n var meta = {\n path: payload.channel,\n subType: payload.data.subType,\n date: payload.data.date\n };\n var actualData = payload.data.data;\n if (actualData.data) { //Delete notifications are one data-level behind of course\n actualData = actualData.data;\n }\n\n callback.call(context, actualData, meta);\n };\n return oldsubs.call(channel, topic, callbackWithCleanData, context, options);\n };\n\n return channel;\n }\n});\n\nmodule.exports = EpicenterChannelManager;\n","'use strict';\n\n/**\n * ## Channel Service\n *\n * The Epicenter platform provides a push channel, which allows you to publish and subscribe to messages within a [project](../../../glossary/#projects), [group](../../../glossary/#groups), or [multiplayer world](../../../glossary/#world). There are two main use cases for the channel: event notifications and chat messages.\n *\n * The Channel Service is a building block for this functionality. It creates a publish-subscribe object, allowing you to publish messages, subscribe to messages, or unsubscribe from messages for a given 'topic' on a `$.cometd` transport instance.\n *\n * Typically, you use the [Epicenter Channel Manager](../epicenter-channel-manager/) to create or retrieve channels, then use the Channel Service `subscribe()` and `publish()` methods to listen to or update data. (For additional background on Epicenter's push channel, see the introductory notes on the [Push Channel API](../../../rest_apis/multiplayer/channel/) page.)\n *\n * You'll need to include the `epicenter-multiplayer-dependencies.js` library in addition to the `epicenter.js` library in your project to use the Channel Service. See [Including Epicenter.js](../../#include).\n *\n * To use the Channel Service, instantiate it, then make calls to any of the methods you need.\n *\n * var cs = new F.service.Channel();\n * cs.publish('/acme-simulations/supply-chain-game/fall-seminar/run/variables', { price: 50 });\n *\n * The parameters for instantiating a Channel Service include:\n *\n * * `options` The options object to configure the Channel Service.\n * * `options.base` The base topic. This is added as a prefix to all further topics you publish or subscribe to while working with this Channel Service.\n * * `options.topicResolver` A function that processes all 'topics' passed into the `publish` and `subscribe` methods. This is useful if you want to implement your own serialize functions for converting custom objects to topic names. Returns a String. By default, it just echoes the topic.\n * * `options.transport` The instance of `$.cometd` to hook onto. See http://docs.cometd.org/reference/javascript.html for additional background on cometd.\n */\nvar Channel = function (options) {\n var defaults = {\n\n /**\n * The base topic. This is added as a prefix to all further topics you publish or subscribe to while working with this Channel Service.\n * @type {string}\n */\n base: '',\n\n /**\n * A function that processes all 'topics' passed into the `publish` and `subscribe` methods. This is useful if you want to implement your own serialize functions for converting custom objects to topic names. By default, it just echoes the topic.\n *\n * **Parameters**\n *\n * * `topic` Topic to parse.\n *\n * **Return Value**\n *\n * * *String*: This function should return a string topic.\n *\n * @type {function}\n */\n topicResolver: function (topic) {\n return topic;\n },\n\n /**\n * The instance of `$.cometd` to hook onto.\n * @type {object}\n */\n transport: null\n };\n this.channelOptions = $.extend(true, {}, defaults, options);\n};\n\nvar makeName = function (channelName, topic) {\n //Replace trailing/double slashes\n var newName = (channelName ? (channelName + '/' + topic) : topic).replace(/\\/\\//g, '/').replace(/\\/$/,'');\n return newName;\n};\n\n\nChannel.prototype = $.extend(Channel.prototype, {\n\n // future functionality:\n // // Set the context for the callback\n // cs.subscribe('run', function () { this.innerHTML = 'Triggered'}, document.body);\n //\n // // Control the order of operations by setting the `priority`\n // cs.subscribe('run', cb, this, {priority: 9});\n //\n // // Only execute the callback, `cb`, if the value of the `price` variable is 50\n // cs.subscribe('run/variables/price', cb, this, {priority: 30, value: 50});\n //\n // // Only execute the callback, `cb`, if the value of the `price` variable is greater than 50\n // subscribe('run/variables/price', cb, this, {priority: 30, value: '>50'});\n //\n // // Only execute the callback, `cb`, if the value of the `price` variable is even\n // subscribe('run/variables/price', cb, this, {priority: 30, value: function (val) {return val % 2 === 0}});\n\n\n /**\n * Subscribe to changes on a topic.\n *\n * The topic should include the full path of the account id (**Team ID** for team projects), project id, and group name. (In most cases, it is simpler to use the [Epicenter Channel Manager](../epicenter-channel-manager/) instead, in which case this is configured for you.)\n *\n * **Examples**\n *\n * var cb = function(val) { console.log(val.data); };\n *\n * // Subscribe to changes on a top-level 'run' topic\n * cs.subscribe('/acme-simulations/supply-chain-game/fall-seminar/run', cb);\n *\n * // Subscribe to changes on children of the 'run' topic. Note this will also be triggered for changes to run.x.y.z.\n * cs.subscribe('/acme-simulations/supply-chain-game/fall-seminar/run/*', cb);\n *\n * // Subscribe to changes on both the top-level 'run' topic and its children\n * cs.subscribe(['/acme-simulations/supply-chain-game/fall-seminar/run',\n * '/acme-simulations/supply-chain-game/fall-seminar/run/*'], cb);\n *\n * // Subscribe to changes on a particular variable\n * subscribe('/acme-simulations/supply-chain-game/fall-seminar/run/variables/price', cb);\n *\n *\n * **Return Value**\n *\n * * *String* Returns a token you can later use to unsubscribe.\n *\n * **Parameters**\n * @param {String|Array} `topic` List of topics to listen for changes on.\n * @param {Function} `callback` Callback function to execute. Callback is called with signature `(evt, payload, metadata)`.\n * @param {Object} `context` Context in which the `callback` is executed.\n * @param {Object} `options` (Optional) Overrides for configuration options.\n * @param {Number} `options.priority` Used to control order of operations. Defaults to 0. Can be any +ve or -ve number.\n * @param {String|Number|Function} `options.value` The `callback` is only triggered if this condition matches. See examples for details.\n *\n */\n subscribe: function (topic, callback, context, options) {\n\n var topics = [].concat(topic);\n var me = this;\n var subscriptionIds = [];\n var opts = me.channelOptions;\n\n opts.transport.batch(function () {\n $.each(topics, function (index, topic) {\n topic = makeName(opts.base, opts.topicResolver(topic));\n subscriptionIds.push(opts.transport.subscribe(topic, callback));\n });\n });\n return (subscriptionIds[1] ? subscriptionIds : subscriptionIds[0]);\n },\n\n /**\n * Publish data to a topic.\n *\n * **Examples**\n *\n * // Send data to all subscribers of the 'run' topic\n * cs.publish('/acme-simulations/supply-chain-game/fall-seminar/run', { completed: false });\n *\n * // Send data to all subscribers of the 'run/variables' topic\n * cs.publish('/acme-simulations/supply-chain-game/fall-seminar/run/variables', { price: 50 });\n *\n * **Parameters**\n *\n * @param {String} `topic` Topic to publish to.\n * @param {*} `data` Data to publish to topic.\n *\n */\n publish: function (topic, data) {\n var topics = [].concat(topic);\n var me = this;\n var returnObjs = [];\n var opts = me.channelOptions;\n\n\n opts.transport.batch(function () {\n $.each(topics, function (index, topic) {\n topic = makeName(opts.base, opts.topicResolver(topic));\n if (topic.charAt(topic.length - 1) === '*') {\n topic = topic.replace(/\\*+$/, '');\n console.warn('You can cannot publish to channels with wildcards. Publishing to ', topic, 'instead');\n }\n returnObjs.push(opts.transport.publish(topic, data));\n });\n });\n return (returnObjs[1] ? returnObjs : returnObjs[0]);\n },\n\n /**\n * Unsubscribe from changes to a topic.\n *\n * **Example**\n *\n * cs.unsubscribe('sampleToken');\n *\n * **Parameters**\n * @param {String} `token` The token for topic is returned when you initially subscribe. Pass it here to unsubscribe from that topic.\n */\n unsubscribe: function (token) {\n this.channelOptions.transport.unsubscribe(token);\n return token;\n },\n\n /**\n * Start listening for events on this instance. Signature is same as for jQuery Events: http://api.jquery.com/on/.\n *\n * Supported events are: `connect`, `disconnect`, `subscribe`, `unsubscribe`, `publish`, `error`.\n *\n * **Parameters**\n *\n * @param {string} `event` The event type. See more detail at jQuery Events: http://api.jquery.com/on/.\n */\n on: function (event) {\n $(this).on.apply($(this), arguments);\n },\n\n /**\n * Stop listening for events on this instance. Signature is same as for jQuery Events: http://api.jquery.com/off/.\n *\n * **Parameters**\n *\n * @param {string} `event` The event type. See more detail at jQuery Events: http://api.jquery.com/off/.\n */\n off: function (event) {\n $(this).off.apply($(this), arguments);\n },\n\n /**\n * Trigger events and execute handlers. Signature is same as for jQuery Events: http://api.jquery.com/trigger/.\n *\n * **Parameters**\n *\n * @param {string} `event` The event type. See more detail at jQuery Events: http://api.jquery.com/trigger/.\n */\n trigger: function (event) {\n $(this).trigger.apply($(this), arguments);\n }\n\n});\n\nmodule.exports = Channel;\n","'use strict';\n\nvar classFrom = require('../../util/inherit');\nvar ConditionalStrategy = require('./conditional-creation-strategy');\n\nvar __super = ConditionalStrategy.prototype;\n\nvar Strategy = classFrom(ConditionalStrategy, {\n constructor: function (runService, options) {\n __super.constructor.call(this, runService, this.createIf, options);\n },\n\n createIf: function (run, headers) {\n // always create a new run!\n return true;\n }\n});\n\nmodule.exports = Strategy;\n","'use strict';\n\nvar makeSeq = require('../../util/make-sequence');\nvar Base = require('./identity-strategy');\nvar SessionStore = require('../../store/store-factory');\nvar classFrom = require('../../util/inherit');\nvar UrlService = require('../../service/url-config-service');\nvar AuthManager = require('../auth-manager');\n\nvar sessionStore = new SessionStore({});\nvar urlService = new UrlService();\nvar keyNames = require('../key-names');\n\nvar defaults = {\n sessionKey: keyNames.STRATEGY_SESSION_KEY,\n path: ''\n};\n\nfunction setRunInSession(sessionKey, run, path) {\n if (!path) {\n if (!urlService.isLocalhost()) {\n path = '/' + [urlService.appPath, urlService.accountPath, urlService.projectPath].join('/');\n // make sure we don't get consecuteive '/' so we have a valid path for the session\n path = path.replace(/\\/{2,}/g,'/');\n } else {\n path = '';\n }\n }\n // set the seesionKey for the run\n sessionStore.set(sessionKey, JSON.stringify({ runId: run.id }), { root: path });\n}\n\n/**\n* Conditional Creation Strategy\n* This strategy will try to get the run stored in the cookie and\n* evaluate if needs to create a new run by calling the 'condition' function\n*/\n\n/* jshint eqnull: true */\nvar Strategy = classFrom(Base, {\n constructor: function Strategy(runService, condition, options) {\n\n if (condition == null) {\n throw new Error('Conditional strategy needs a condition to createte a run');\n }\n\n this._auth = new AuthManager();\n this.run = makeSeq(runService);\n this.condition = typeof condition !== 'function' ? function () { return condition; } : condition;\n this.options = $.extend(true, {}, defaults, options);\n this.runOptions = this.options.run;\n },\n\n runOptionsWithScope: function () {\n var userSession = this._auth.getCurrentUserSessionInfo();\n return $.extend({\n scope: { group: userSession.groupName }\n }, this.runOptions);\n },\n\n reset: function (runServiceOptions) {\n var _this = this;\n var opt = this.runOptionsWithScope();\n\n return this.run\n .create(opt, runServiceOptions)\n .then(function (run) {\n setRunInSession(_this.options.sessionKey, run, _this.options.path);\n run.freshlyCreated = true;\n return run;\n })\n .start();\n },\n\n getRun: function () {\n var runSession = JSON.parse(sessionStore.get(this.options.sessionKey));\n\n if (runSession && runSession.runId) {\n return this._loadAndCheck(runSession);\n } else {\n return this.reset();\n }\n },\n\n _loadAndCheck: function (runSession) {\n var shouldCreate = false;\n var _this = this;\n\n return this.run\n .load(runSession.runId, null, {\n success: function (run, msg, headers) {\n shouldCreate = _this.condition.call(_this, run, headers);\n }\n })\n .then(function (run) {\n if (shouldCreate) {\n var opt = _this.runOptionsWithScope();\n // we need to do this, on the original runService (ie not sequencialized)\n // so we don't get in the middle of the queue\n return _this.run.original.create(opt)\n .then(function (run) {\n setRunInSession(_this.options.sessionKey, run);\n run.freshlyCreated = true;\n return run;\n });\n }\n\n return run;\n })\n .start();\n }\n});\n\nmodule.exports = Strategy;\n","'use strict';\n\nvar classFrom = require('../../util/inherit');\nvar Base = {};\n\n// Interface that all strategies need to implement\nmodule.exports = classFrom(Base, {\n constructor: function (runService, options) {\n this.runService = runService;\n },\n\n reset: function () {\n // return a newly created run\n return $.Deferred().resolve().promise();\n },\n\n getRun: function () {\n // return a usable run\n return $.Deferred().resolve(this.runService).promise();\n }\n});\n","'use strict';\n\nvar classFrom = require('../../util/inherit');\nvar ConditionalStrategy = require('./conditional-creation-strategy');\n\nvar __super = ConditionalStrategy.prototype;\n\n/*\n* create a new run only if nothing is stored in the cookie\n* this is useful for baseRuns.\n*/\nvar Strategy = classFrom(ConditionalStrategy, {\n constructor: function (runService, options) {\n __super.constructor.call(this, runService, this.createIf, options);\n },\n\n createIf: function (run, headers) {\n // if we are here, it means that the run exists... so we don't need a new one\n return false;\n }\n});\n\nmodule.exports = Strategy;\n","'use strict';\nvar classFrom = require('../../util/inherit');\nvar ConditionalStrategy = require('./conditional-creation-strategy');\n\nvar __super = ConditionalStrategy.prototype;\n\nvar Strategy = classFrom(ConditionalStrategy, {\n constructor: function (runService, options) {\n __super.constructor.call(this, runService, this.createIf, options);\n },\n\n createIf: function (run, headers) {\n return headers.getResponseHeader('pragma') === 'persistent';\n }\n});\n\nmodule.exports = Strategy;\n","'use strict';\nvar classFrom = require('../../util/inherit');\nvar ConditionalStrategy = require('./conditional-creation-strategy');\n\nvar __super = ConditionalStrategy.prototype;\n\nvar Strategy = classFrom(ConditionalStrategy, {\n constructor: function (runService, options) {\n __super.constructor.call(this, runService, this.createIf, options);\n },\n\n createIf: function (run, headers) {\n return headers.getResponseHeader('pragma') === 'persistent' || run.initialized;\n }\n});\n\nmodule.exports = Strategy;\n","'use strict';\n\nmodule.exports = {\n _pick: function (obj, props) {\n var res = {};\n for (var p in obj) {\n if (props.indexOf(p) !== -1) {\n res[p] = obj[p];\n }\n }\n\n return res;\n }\n};\n","/**\n *\n * ## Introspection API Service\n *\n * Used in conjunction with the [Run API Service](../run-api-service/) to access Native DMS 3 Introspection calls\n *\n * var rm = new F.manager.RunManager({\n * run: {\n * account: 'acme-simulations',\n * project: 'supply-chain-game',\n * model: 'supply-chain-model.jl'\n * }\n * });\n * rm.getRun()\n * .then(function() {\n * var is = rm.run.introspection();\n * });\n *\n */\n\n'use strict';\n\nvar ConfigService = require('./configuration-service');\nvar TransportFactory = require('../transport/http-transport-factory');\n\nmodule.exports = function (config) {\n var defaults = {\n server: {\n versionPath: 'v3/'\n }\n };\n var serviceOptions = $.extend({}, defaults, config);\n\n var urlConfig = new ConfigService(serviceOptions).get('server');\n if (serviceOptions.account) {\n urlConfig.accountPath = serviceOptions.account;\n }\n if (serviceOptions.project) {\n urlConfig.projectPath = serviceOptions.project;\n }\n\n urlConfig.filter = ';';\n\n var httpOptions = {\n url: urlConfig.getAPIPath('model') + 'publish'\n };\n if (serviceOptions.token) {\n httpOptions.headers = {\n 'Authorization': 'Bearer ' + serviceOptions.token\n };\n }\n var http = new TransportFactory(httpOptions);\n\n var publicAPI = {\n /**\n * Get the available Functions and Variables\n *\n * **Example**\n *\n * vs.get()\n * .then(function(data) {\n * // data contains an object with available functions (used with operations API) and available variables (used with variables API)\n * console.log(data.functions);\n * console.log(data.variables);\n * });\n *\n * **Parameters**\n * @param {String} `runId` (Optional) Overrides the run id used when the service was created\n * @param {Object} `options` (Optional) Overrides for configuration options.\n */\n get: function (runId, options) {\n var httpOptions = $.extend(true, {}, serviceOptions, options);\n var params = {\n runId: runId || httpOptions.filter,\n commandWrapper: { command: { introspect: {} } },\n reanimate: false\n };\n return http.post(params, httpOptions);\n }\n };\n $.extend(this, publicAPI);\n};\n","'use strict';\n\nvar keyNames = require('../managers/key-names');\nvar StorageFactory = require('./store-factory');\nvar optionUtils = require('../util/option-utils');\n\nvar EPI_SESSION_KEY = keyNames.EPI_SESSION_KEY;\nvar defaults = {\n /**\n * Where to store user access tokens for temporary access. Defaults to storing in a cookie in the browser.\n * @type {string}\n */\n store: { synchronous: true }\n};\n\nvar SessionManager = function (managerOptions) {\n managerOptions = managerOptions || {};\n function getBaseOptions(overrides) {\n overrides = overrides || {};\n var libOptions = optionUtils.getOptions();\n var finalOptions = $.extend(true, {}, defaults, libOptions, managerOptions, overrides);\n return finalOptions;\n }\n\n function getStore(overrides) {\n var baseOptions = getBaseOptions(overrides);\n var storeOpts = baseOptions.store || {};\n if (storeOpts.root === undefined && baseOptions.account && baseOptions.project && !baseOptions.isLocal) {\n storeOpts.root = '/app/' + baseOptions.account + '/' + baseOptions.project;\n }\n return new StorageFactory(storeOpts);\n }\n\n var publicAPI = {\n saveSession: function (userInfo, options) {\n var serialized = JSON.stringify(userInfo);\n getStore(options).set(EPI_SESSION_KEY, serialized);\n },\n getSession: function (options) {\n // var session = getStore(options).get(EPI_SESSION_KEY) || '{}';\n // return JSON.parse(session);\n var store = getStore(options);\n var finalOpts = store.serviceOptions;\n var serialized = store.get(EPI_SESSION_KEY) || '{}';\n var session = JSON.parse(serialized);\n // If the url contains the project and account\n // validate the account and project in the session\n // and override project, groupName, groupId and isFac\n // Otherwise (i.e. localhost) use the saved session values\n var account = finalOpts.account;\n var project = finalOpts.project;\n if (account && session.account !== account) {\n // This means that the token was not used to login to the same account\n return {};\n }\n if (session.groups && account && project) {\n var group = session.groups[project] || { groupId: '', groupName: '', isFac: false };\n $.extend(session, { project: project }, group);\n }\n return session;\n },\n removeSession: function (options) {\n return getStore(options).remove(EPI_SESSION_KEY);\n },\n getStore: function (options) {\n return getStore(options);\n },\n\n getMergedOptions: function () {\n var args = Array.prototype.slice.call(arguments);\n var overrides = $.extend.apply($, [true, {}].concat(args));\n var baseOptions = getBaseOptions(overrides);\n var session = this.getSession(overrides);\n\n var sessionDefaults = {\n /**\n * For projects that require authentication, pass in the user access token (defaults to empty string). If the user is already logged in to Epicenter, the user access token is already set in a cookie and automatically loaded from there. (See [more background on access tokens](../../../project_access/)).\n * @see [Authentication API Service](../auth-api-service/) for getting tokens.\n * @type {String}\n */\n //jshint camelcase: false\n //jscs:disable\n token: session.auth_token,\n /**\n * The group name. If left undefined, taken from the cookie session.\n * @type {String}\n */\n group: session.groupName,\n /**\n * The group id. If left undefined, taken from the cookie session.\n * @type {String}\n */\n groupId: session.groupId,\n userId: session.userId\n };\n return $.extend(true, sessionDefaults, baseOptions);\n }\n };\n $.extend(this, publicAPI);\n};\n\nmodule.exports = SessionManager;","'use strict';\n\n\nmodule.exports = {\n reset: function (params, options, manager) {\n return manager.reset(options);\n }\n};\n","module.exports = {\n 'new-if-initialized': require('./new-if-initialized-strategy'),\n 'new-if-persisted': require('./new-if-persisted-strategy'),\n 'new-if-missing': require('./new-if-missing-strategy'),\n 'always-new': require('./always-new-strategy'),\n 'multiplayer': require('./multiplayer-strategy'),\n 'persistent-single-player': require('./persistent-single-player-strategy'),\n 'none': require('./identity-strategy')\n};\n","/*!\n * The buffer module from node.js, for the browser.\n *\n * @author Feross Aboukhadijeh \n * @license MIT\n */\n/* eslint-disable no-proto */\n\n'use strict'\n\nvar base64 = require('base64-js')\nvar ieee754 = require('ieee754')\nvar isArray = require('isarray')\n\nexports.Buffer = Buffer\nexports.SlowBuffer = SlowBuffer\nexports.INSPECT_MAX_BYTES = 50\n\n/**\n * If `Buffer.TYPED_ARRAY_SUPPORT`:\n * === true Use Uint8Array implementation (fastest)\n * === false Use Object implementation (most compatible, even IE6)\n *\n * Browsers that support typed arrays are IE 10+, Firefox 4+, Chrome 7+, Safari 5.1+,\n * Opera 11.6+, iOS 4.2+.\n *\n * Due to various browser bugs, sometimes the Object implementation will be used even\n * when the browser supports typed arrays.\n *\n * Note:\n *\n * - Firefox 4-29 lacks support for adding new properties to `Uint8Array` instances,\n * See: https://bugzilla.mozilla.org/show_bug.cgi?id=695438.\n *\n * - Chrome 9-10 is missing the `TypedArray.prototype.subarray` function.\n *\n * - IE10 has a broken `TypedArray.prototype.subarray` function which returns arrays of\n * incorrect length in some situations.\n\n * We detect these buggy browsers and set `Buffer.TYPED_ARRAY_SUPPORT` to `false` so they\n * get the Object implementation, which is slower but behaves correctly.\n */\nBuffer.TYPED_ARRAY_SUPPORT = global.TYPED_ARRAY_SUPPORT !== undefined\n ? global.TYPED_ARRAY_SUPPORT\n : typedArraySupport()\n\n/*\n * Export kMaxLength after typed array support is determined.\n */\nexports.kMaxLength = kMaxLength()\n\nfunction typedArraySupport () {\n try {\n var arr = new Uint8Array(1)\n arr.__proto__ = {__proto__: Uint8Array.prototype, foo: function () { return 42 }}\n return arr.foo() === 42 && // typed array instances can be augmented\n typeof arr.subarray === 'function' && // chrome 9-10 lack `subarray`\n arr.subarray(1, 1).byteLength === 0 // ie10 has broken `subarray`\n } catch (e) {\n return false\n }\n}\n\nfunction kMaxLength () {\n return Buffer.TYPED_ARRAY_SUPPORT\n ? 0x7fffffff\n : 0x3fffffff\n}\n\nfunction createBuffer (that, length) {\n if (kMaxLength() < length) {\n throw new RangeError('Invalid typed array length')\n }\n if (Buffer.TYPED_ARRAY_SUPPORT) {\n // Return an augmented `Uint8Array` instance, for best performance\n that = new Uint8Array(length)\n that.__proto__ = Buffer.prototype\n } else {\n // Fallback: Return an object instance of the Buffer class\n if (that === null) {\n that = new Buffer(length)\n }\n that.length = length\n }\n\n return that\n}\n\n/**\n * The Buffer constructor returns instances of `Uint8Array` that have their\n * prototype changed to `Buffer.prototype`. Furthermore, `Buffer` is a subclass of\n * `Uint8Array`, so the returned instances will have all the node `Buffer` methods\n * and the `Uint8Array` methods. Square bracket notation works as expected -- it\n * returns a single octet.\n *\n * The `Uint8Array` prototype remains unmodified.\n */\n\nfunction Buffer (arg, encodingOrOffset, length) {\n if (!Buffer.TYPED_ARRAY_SUPPORT && !(this instanceof Buffer)) {\n return new Buffer(arg, encodingOrOffset, length)\n }\n\n // Common case.\n if (typeof arg === 'number') {\n if (typeof encodingOrOffset === 'string') {\n throw new Error(\n 'If encoding is specified then the first argument must be a string'\n )\n }\n return allocUnsafe(this, arg)\n }\n return from(this, arg, encodingOrOffset, length)\n}\n\nBuffer.poolSize = 8192 // not used by this implementation\n\n// TODO: Legacy, not needed anymore. Remove in next major version.\nBuffer._augment = function (arr) {\n arr.__proto__ = Buffer.prototype\n return arr\n}\n\nfunction from (that, value, encodingOrOffset, length) {\n if (typeof value === 'number') {\n throw new TypeError('\"value\" argument must not be a number')\n }\n\n if (typeof ArrayBuffer !== 'undefined' && value instanceof ArrayBuffer) {\n return fromArrayBuffer(that, value, encodingOrOffset, length)\n }\n\n if (typeof value === 'string') {\n return fromString(that, value, encodingOrOffset)\n }\n\n return fromObject(that, value)\n}\n\n/**\n * Functionally equivalent to Buffer(arg, encoding) but throws a TypeError\n * if value is a number.\n * Buffer.from(str[, encoding])\n * Buffer.from(array)\n * Buffer.from(buffer)\n * Buffer.from(arrayBuffer[, byteOffset[, length]])\n **/\nBuffer.from = function (value, encodingOrOffset, length) {\n return from(null, value, encodingOrOffset, length)\n}\n\nif (Buffer.TYPED_ARRAY_SUPPORT) {\n Buffer.prototype.__proto__ = Uint8Array.prototype\n Buffer.__proto__ = Uint8Array\n if (typeof Symbol !== 'undefined' && Symbol.species &&\n Buffer[Symbol.species] === Buffer) {\n // Fix subarray() in ES2016. See: https://github.com/feross/buffer/pull/97\n Object.defineProperty(Buffer, Symbol.species, {\n value: null,\n configurable: true\n })\n }\n}\n\nfunction assertSize (size) {\n if (typeof size !== 'number') {\n throw new TypeError('\"size\" argument must be a number')\n }\n}\n\nfunction alloc (that, size, fill, encoding) {\n assertSize(size)\n if (size <= 0) {\n return createBuffer(that, size)\n }\n if (fill !== undefined) {\n // Only pay attention to encoding if it's a string. This\n // prevents accidentally sending in a number that would\n // be interpretted as a start offset.\n return typeof encoding === 'string'\n ? createBuffer(that, size).fill(fill, encoding)\n : createBuffer(that, size).fill(fill)\n }\n return createBuffer(that, size)\n}\n\n/**\n * Creates a new filled Buffer instance.\n * alloc(size[, fill[, encoding]])\n **/\nBuffer.alloc = function (size, fill, encoding) {\n return alloc(null, size, fill, encoding)\n}\n\nfunction allocUnsafe (that, size) {\n assertSize(size)\n that = createBuffer(that, size < 0 ? 0 : checked(size) | 0)\n if (!Buffer.TYPED_ARRAY_SUPPORT) {\n for (var i = 0; i < size; ++i) {\n that[i] = 0\n }\n }\n return that\n}\n\n/**\n * Equivalent to Buffer(num), by default creates a non-zero-filled Buffer instance.\n * */\nBuffer.allocUnsafe = function (size) {\n return allocUnsafe(null, size)\n}\n/**\n * Equivalent to SlowBuffer(num), by default creates a non-zero-filled Buffer instance.\n */\nBuffer.allocUnsafeSlow = function (size) {\n return allocUnsafe(null, size)\n}\n\nfunction fromString (that, string, encoding) {\n if (typeof encoding !== 'string' || encoding === '') {\n encoding = 'utf8'\n }\n\n if (!Buffer.isEncoding(encoding)) {\n throw new TypeError('\"encoding\" must be a valid string encoding')\n }\n\n var length = byteLength(string, encoding) | 0\n that = createBuffer(that, length)\n\n that.write(string, encoding)\n return that\n}\n\nfunction fromArrayLike (that, array) {\n var length = checked(array.length) | 0\n that = createBuffer(that, length)\n for (var i = 0; i < length; i += 1) {\n that[i] = array[i] & 255\n }\n return that\n}\n\nfunction fromArrayBuffer (that, array, byteOffset, length) {\n array.byteLength // this throws if `array` is not a valid ArrayBuffer\n\n if (byteOffset < 0 || array.byteLength < byteOffset) {\n throw new RangeError('\\'offset\\' is out of bounds')\n }\n\n if (array.byteLength < byteOffset + (length || 0)) {\n throw new RangeError('\\'length\\' is out of bounds')\n }\n\n if (length === undefined) {\n array = new Uint8Array(array, byteOffset)\n } else {\n array = new Uint8Array(array, byteOffset, length)\n }\n\n if (Buffer.TYPED_ARRAY_SUPPORT) {\n // Return an augmented `Uint8Array` instance, for best performance\n that = array\n that.__proto__ = Buffer.prototype\n } else {\n // Fallback: Return an object instance of the Buffer class\n that = fromArrayLike(that, array)\n }\n return that\n}\n\nfunction fromObject (that, obj) {\n if (Buffer.isBuffer(obj)) {\n var len = checked(obj.length) | 0\n that = createBuffer(that, len)\n\n if (that.length === 0) {\n return that\n }\n\n obj.copy(that, 0, 0, len)\n return that\n }\n\n if (obj) {\n if ((typeof ArrayBuffer !== 'undefined' &&\n obj.buffer instanceof ArrayBuffer) || 'length' in obj) {\n if (typeof obj.length !== 'number' || isnan(obj.length)) {\n return createBuffer(that, 0)\n }\n return fromArrayLike(that, obj)\n }\n\n if (obj.type === 'Buffer' && isArray(obj.data)) {\n return fromArrayLike(that, obj.data)\n }\n }\n\n throw new TypeError('First argument must be a string, Buffer, ArrayBuffer, Array, or array-like object.')\n}\n\nfunction checked (length) {\n // Note: cannot use `length < kMaxLength` here because that fails when\n // length is NaN (which is otherwise coerced to zero.)\n if (length >= kMaxLength()) {\n throw new RangeError('Attempt to allocate Buffer larger than maximum ' +\n 'size: 0x' + kMaxLength().toString(16) + ' bytes')\n }\n return length | 0\n}\n\nfunction SlowBuffer (length) {\n if (+length != length) { // eslint-disable-line eqeqeq\n length = 0\n }\n return Buffer.alloc(+length)\n}\n\nBuffer.isBuffer = function isBuffer (b) {\n return !!(b != null && b._isBuffer)\n}\n\nBuffer.compare = function compare (a, b) {\n if (!Buffer.isBuffer(a) || !Buffer.isBuffer(b)) {\n throw new TypeError('Arguments must be Buffers')\n }\n\n if (a === b) return 0\n\n var x = a.length\n var y = b.length\n\n for (var i = 0, len = Math.min(x, y); i < len; ++i) {\n if (a[i] !== b[i]) {\n x = a[i]\n y = b[i]\n break\n }\n }\n\n if (x < y) return -1\n if (y < x) return 1\n return 0\n}\n\nBuffer.isEncoding = function isEncoding (encoding) {\n switch (String(encoding).toLowerCase()) {\n case 'hex':\n case 'utf8':\n case 'utf-8':\n case 'ascii':\n case 'binary':\n case 'base64':\n case 'raw':\n case 'ucs2':\n case 'ucs-2':\n case 'utf16le':\n case 'utf-16le':\n return true\n default:\n return false\n }\n}\n\nBuffer.concat = function concat (list, length) {\n if (!isArray(list)) {\n throw new TypeError('\"list\" argument must be an Array of Buffers')\n }\n\n if (list.length === 0) {\n return Buffer.alloc(0)\n }\n\n var i\n if (length === undefined) {\n length = 0\n for (i = 0; i < list.length; ++i) {\n length += list[i].length\n }\n }\n\n var buffer = Buffer.allocUnsafe(length)\n var pos = 0\n for (i = 0; i < list.length; ++i) {\n var buf = list[i]\n if (!Buffer.isBuffer(buf)) {\n throw new TypeError('\"list\" argument must be an Array of Buffers')\n }\n buf.copy(buffer, pos)\n pos += buf.length\n }\n return buffer\n}\n\nfunction byteLength (string, encoding) {\n if (Buffer.isBuffer(string)) {\n return string.length\n }\n if (typeof ArrayBuffer !== 'undefined' && typeof ArrayBuffer.isView === 'function' &&\n (ArrayBuffer.isView(string) || string instanceof ArrayBuffer)) {\n return string.byteLength\n }\n if (typeof string !== 'string') {\n string = '' + string\n }\n\n var len = string.length\n if (len === 0) return 0\n\n // Use a for loop to avoid recursion\n var loweredCase = false\n for (;;) {\n switch (encoding) {\n case 'ascii':\n case 'binary':\n case 'raw':\n case 'raws':\n return len\n case 'utf8':\n case 'utf-8':\n case undefined:\n return utf8ToBytes(string).length\n case 'ucs2':\n case 'ucs-2':\n case 'utf16le':\n case 'utf-16le':\n return len * 2\n case 'hex':\n return len >>> 1\n case 'base64':\n return base64ToBytes(string).length\n default:\n if (loweredCase) return utf8ToBytes(string).length // assume utf8\n encoding = ('' + encoding).toLowerCase()\n loweredCase = true\n }\n }\n}\nBuffer.byteLength = byteLength\n\nfunction slowToString (encoding, start, end) {\n var loweredCase = false\n\n // No need to verify that \"this.length <= MAX_UINT32\" since it's a read-only\n // property of a typed array.\n\n // This behaves neither like String nor Uint8Array in that we set start/end\n // to their upper/lower bounds if the value passed is out of range.\n // undefined is handled specially as per ECMA-262 6th Edition,\n // Section 13.3.3.7 Runtime Semantics: KeyedBindingInitialization.\n if (start === undefined || start < 0) {\n start = 0\n }\n // Return early if start > this.length. Done here to prevent potential uint32\n // coercion fail below.\n if (start > this.length) {\n return ''\n }\n\n if (end === undefined || end > this.length) {\n end = this.length\n }\n\n if (end <= 0) {\n return ''\n }\n\n // Force coersion to uint32. This will also coerce falsey/NaN values to 0.\n end >>>= 0\n start >>>= 0\n\n if (end <= start) {\n return ''\n }\n\n if (!encoding) encoding = 'utf8'\n\n while (true) {\n switch (encoding) {\n case 'hex':\n return hexSlice(this, start, end)\n\n case 'utf8':\n case 'utf-8':\n return utf8Slice(this, start, end)\n\n case 'ascii':\n return asciiSlice(this, start, end)\n\n case 'binary':\n return binarySlice(this, start, end)\n\n case 'base64':\n return base64Slice(this, start, end)\n\n case 'ucs2':\n case 'ucs-2':\n case 'utf16le':\n case 'utf-16le':\n return utf16leSlice(this, start, end)\n\n default:\n if (loweredCase) throw new TypeError('Unknown encoding: ' + encoding)\n encoding = (encoding + '').toLowerCase()\n loweredCase = true\n }\n }\n}\n\n// The property is used by `Buffer.isBuffer` and `is-buffer` (in Safari 5-7) to detect\n// Buffer instances.\nBuffer.prototype._isBuffer = true\n\nfunction swap (b, n, m) {\n var i = b[n]\n b[n] = b[m]\n b[m] = i\n}\n\nBuffer.prototype.swap16 = function swap16 () {\n var len = this.length\n if (len % 2 !== 0) {\n throw new RangeError('Buffer size must be a multiple of 16-bits')\n }\n for (var i = 0; i < len; i += 2) {\n swap(this, i, i + 1)\n }\n return this\n}\n\nBuffer.prototype.swap32 = function swap32 () {\n var len = this.length\n if (len % 4 !== 0) {\n throw new RangeError('Buffer size must be a multiple of 32-bits')\n }\n for (var i = 0; i < len; i += 4) {\n swap(this, i, i + 3)\n swap(this, i + 1, i + 2)\n }\n return this\n}\n\nBuffer.prototype.toString = function toString () {\n var length = this.length | 0\n if (length === 0) return ''\n if (arguments.length === 0) return utf8Slice(this, 0, length)\n return slowToString.apply(this, arguments)\n}\n\nBuffer.prototype.equals = function equals (b) {\n if (!Buffer.isBuffer(b)) throw new TypeError('Argument must be a Buffer')\n if (this === b) return true\n return Buffer.compare(this, b) === 0\n}\n\nBuffer.prototype.inspect = function inspect () {\n var str = ''\n var max = exports.INSPECT_MAX_BYTES\n if (this.length > 0) {\n str = this.toString('hex', 0, max).match(/.{2}/g).join(' ')\n if (this.length > max) str += ' ... '\n }\n return ''\n}\n\nBuffer.prototype.compare = function compare (target, start, end, thisStart, thisEnd) {\n if (!Buffer.isBuffer(target)) {\n throw new TypeError('Argument must be a Buffer')\n }\n\n if (start === undefined) {\n start = 0\n }\n if (end === undefined) {\n end = target ? target.length : 0\n }\n if (thisStart === undefined) {\n thisStart = 0\n }\n if (thisEnd === undefined) {\n thisEnd = this.length\n }\n\n if (start < 0 || end > target.length || thisStart < 0 || thisEnd > this.length) {\n throw new RangeError('out of range index')\n }\n\n if (thisStart >= thisEnd && start >= end) {\n return 0\n }\n if (thisStart >= thisEnd) {\n return -1\n }\n if (start >= end) {\n return 1\n }\n\n start >>>= 0\n end >>>= 0\n thisStart >>>= 0\n thisEnd >>>= 0\n\n if (this === target) return 0\n\n var x = thisEnd - thisStart\n var y = end - start\n var len = Math.min(x, y)\n\n var thisCopy = this.slice(thisStart, thisEnd)\n var targetCopy = target.slice(start, end)\n\n for (var i = 0; i < len; ++i) {\n if (thisCopy[i] !== targetCopy[i]) {\n x = thisCopy[i]\n y = targetCopy[i]\n break\n }\n }\n\n if (x < y) return -1\n if (y < x) return 1\n return 0\n}\n\nfunction arrayIndexOf (arr, val, byteOffset, encoding) {\n var indexSize = 1\n var arrLength = arr.length\n var valLength = val.length\n\n if (encoding !== undefined) {\n encoding = String(encoding).toLowerCase()\n if (encoding === 'ucs2' || encoding === 'ucs-2' ||\n encoding === 'utf16le' || encoding === 'utf-16le') {\n if (arr.length < 2 || val.length < 2) {\n return -1\n }\n indexSize = 2\n arrLength /= 2\n valLength /= 2\n byteOffset /= 2\n }\n }\n\n function read (buf, i) {\n if (indexSize === 1) {\n return buf[i]\n } else {\n return buf.readUInt16BE(i * indexSize)\n }\n }\n\n var foundIndex = -1\n for (var i = byteOffset; i < arrLength; ++i) {\n if (read(arr, i) === read(val, foundIndex === -1 ? 0 : i - foundIndex)) {\n if (foundIndex === -1) foundIndex = i\n if (i - foundIndex + 1 === valLength) return foundIndex * indexSize\n } else {\n if (foundIndex !== -1) i -= i - foundIndex\n foundIndex = -1\n }\n }\n\n return -1\n}\n\nBuffer.prototype.indexOf = function indexOf (val, byteOffset, encoding) {\n if (typeof byteOffset === 'string') {\n encoding = byteOffset\n byteOffset = 0\n } else if (byteOffset > 0x7fffffff) {\n byteOffset = 0x7fffffff\n } else if (byteOffset < -0x80000000) {\n byteOffset = -0x80000000\n }\n byteOffset >>= 0\n\n if (this.length === 0) return -1\n if (byteOffset >= this.length) return -1\n\n // Negative offsets start from the end of the buffer\n if (byteOffset < 0) byteOffset = Math.max(this.length + byteOffset, 0)\n\n if (typeof val === 'string') {\n val = Buffer.from(val, encoding)\n }\n\n if (Buffer.isBuffer(val)) {\n // special case: looking for empty string/buffer always fails\n if (val.length === 0) {\n return -1\n }\n return arrayIndexOf(this, val, byteOffset, encoding)\n }\n if (typeof val === 'number') {\n if (Buffer.TYPED_ARRAY_SUPPORT && Uint8Array.prototype.indexOf === 'function') {\n return Uint8Array.prototype.indexOf.call(this, val, byteOffset)\n }\n return arrayIndexOf(this, [ val ], byteOffset, encoding)\n }\n\n throw new TypeError('val must be string, number or Buffer')\n}\n\nBuffer.prototype.includes = function includes (val, byteOffset, encoding) {\n return this.indexOf(val, byteOffset, encoding) !== -1\n}\n\nfunction hexWrite (buf, string, offset, length) {\n offset = Number(offset) || 0\n var remaining = buf.length - offset\n if (!length) {\n length = remaining\n } else {\n length = Number(length)\n if (length > remaining) {\n length = remaining\n }\n }\n\n // must be an even number of digits\n var strLen = string.length\n if (strLen % 2 !== 0) throw new Error('Invalid hex string')\n\n if (length > strLen / 2) {\n length = strLen / 2\n }\n for (var i = 0; i < length; ++i) {\n var parsed = parseInt(string.substr(i * 2, 2), 16)\n if (isNaN(parsed)) return i\n buf[offset + i] = parsed\n }\n return i\n}\n\nfunction utf8Write (buf, string, offset, length) {\n return blitBuffer(utf8ToBytes(string, buf.length - offset), buf, offset, length)\n}\n\nfunction asciiWrite (buf, string, offset, length) {\n return blitBuffer(asciiToBytes(string), buf, offset, length)\n}\n\nfunction binaryWrite (buf, string, offset, length) {\n return asciiWrite(buf, string, offset, length)\n}\n\nfunction base64Write (buf, string, offset, length) {\n return blitBuffer(base64ToBytes(string), buf, offset, length)\n}\n\nfunction ucs2Write (buf, string, offset, length) {\n return blitBuffer(utf16leToBytes(string, buf.length - offset), buf, offset, length)\n}\n\nBuffer.prototype.write = function write (string, offset, length, encoding) {\n // Buffer#write(string)\n if (offset === undefined) {\n encoding = 'utf8'\n length = this.length\n offset = 0\n // Buffer#write(string, encoding)\n } else if (length === undefined && typeof offset === 'string') {\n encoding = offset\n length = this.length\n offset = 0\n // Buffer#write(string, offset[, length][, encoding])\n } else if (isFinite(offset)) {\n offset = offset | 0\n if (isFinite(length)) {\n length = length | 0\n if (encoding === undefined) encoding = 'utf8'\n } else {\n encoding = length\n length = undefined\n }\n // legacy write(string, encoding, offset, length) - remove in v0.13\n } else {\n throw new Error(\n 'Buffer.write(string, encoding, offset[, length]) is no longer supported'\n )\n }\n\n var remaining = this.length - offset\n if (length === undefined || length > remaining) length = remaining\n\n if ((string.length > 0 && (length < 0 || offset < 0)) || offset > this.length) {\n throw new RangeError('Attempt to write outside buffer bounds')\n }\n\n if (!encoding) encoding = 'utf8'\n\n var loweredCase = false\n for (;;) {\n switch (encoding) {\n case 'hex':\n return hexWrite(this, string, offset, length)\n\n case 'utf8':\n case 'utf-8':\n return utf8Write(this, string, offset, length)\n\n case 'ascii':\n return asciiWrite(this, string, offset, length)\n\n case 'binary':\n return binaryWrite(this, string, offset, length)\n\n case 'base64':\n // Warning: maxLength not taken into account in base64Write\n return base64Write(this, string, offset, length)\n\n case 'ucs2':\n case 'ucs-2':\n case 'utf16le':\n case 'utf-16le':\n return ucs2Write(this, string, offset, length)\n\n default:\n if (loweredCase) throw new TypeError('Unknown encoding: ' + encoding)\n encoding = ('' + encoding).toLowerCase()\n loweredCase = true\n }\n }\n}\n\nBuffer.prototype.toJSON = function toJSON () {\n return {\n type: 'Buffer',\n data: Array.prototype.slice.call(this._arr || this, 0)\n }\n}\n\nfunction base64Slice (buf, start, end) {\n if (start === 0 && end === buf.length) {\n return base64.fromByteArray(buf)\n } else {\n return base64.fromByteArray(buf.slice(start, end))\n }\n}\n\nfunction utf8Slice (buf, start, end) {\n end = Math.min(buf.length, end)\n var res = []\n\n var i = start\n while (i < end) {\n var firstByte = buf[i]\n var codePoint = null\n var bytesPerSequence = (firstByte > 0xEF) ? 4\n : (firstByte > 0xDF) ? 3\n : (firstByte > 0xBF) ? 2\n : 1\n\n if (i + bytesPerSequence <= end) {\n var secondByte, thirdByte, fourthByte, tempCodePoint\n\n switch (bytesPerSequence) {\n case 1:\n if (firstByte < 0x80) {\n codePoint = firstByte\n }\n break\n case 2:\n secondByte = buf[i + 1]\n if ((secondByte & 0xC0) === 0x80) {\n tempCodePoint = (firstByte & 0x1F) << 0x6 | (secondByte & 0x3F)\n if (tempCodePoint > 0x7F) {\n codePoint = tempCodePoint\n }\n }\n break\n case 3:\n secondByte = buf[i + 1]\n thirdByte = buf[i + 2]\n if ((secondByte & 0xC0) === 0x80 && (thirdByte & 0xC0) === 0x80) {\n tempCodePoint = (firstByte & 0xF) << 0xC | (secondByte & 0x3F) << 0x6 | (thirdByte & 0x3F)\n if (tempCodePoint > 0x7FF && (tempCodePoint < 0xD800 || tempCodePoint > 0xDFFF)) {\n codePoint = tempCodePoint\n }\n }\n break\n case 4:\n secondByte = buf[i + 1]\n thirdByte = buf[i + 2]\n fourthByte = buf[i + 3]\n if ((secondByte & 0xC0) === 0x80 && (thirdByte & 0xC0) === 0x80 && (fourthByte & 0xC0) === 0x80) {\n tempCodePoint = (firstByte & 0xF) << 0x12 | (secondByte & 0x3F) << 0xC | (thirdByte & 0x3F) << 0x6 | (fourthByte & 0x3F)\n if (tempCodePoint > 0xFFFF && tempCodePoint < 0x110000) {\n codePoint = tempCodePoint\n }\n }\n }\n }\n\n if (codePoint === null) {\n // we did not generate a valid codePoint so insert a\n // replacement char (U+FFFD) and advance only 1 byte\n codePoint = 0xFFFD\n bytesPerSequence = 1\n } else if (codePoint > 0xFFFF) {\n // encode to utf16 (surrogate pair dance)\n codePoint -= 0x10000\n res.push(codePoint >>> 10 & 0x3FF | 0xD800)\n codePoint = 0xDC00 | codePoint & 0x3FF\n }\n\n res.push(codePoint)\n i += bytesPerSequence\n }\n\n return decodeCodePointsArray(res)\n}\n\n// Based on http://stackoverflow.com/a/22747272/680742, the browser with\n// the lowest limit is Chrome, with 0x10000 args.\n// We go 1 magnitude less, for safety\nvar MAX_ARGUMENTS_LENGTH = 0x1000\n\nfunction decodeCodePointsArray (codePoints) {\n var len = codePoints.length\n if (len <= MAX_ARGUMENTS_LENGTH) {\n return String.fromCharCode.apply(String, codePoints) // avoid extra slice()\n }\n\n // Decode in chunks to avoid \"call stack size exceeded\".\n var res = ''\n var i = 0\n while (i < len) {\n res += String.fromCharCode.apply(\n String,\n codePoints.slice(i, i += MAX_ARGUMENTS_LENGTH)\n )\n }\n return res\n}\n\nfunction asciiSlice (buf, start, end) {\n var ret = ''\n end = Math.min(buf.length, end)\n\n for (var i = start; i < end; ++i) {\n ret += String.fromCharCode(buf[i] & 0x7F)\n }\n return ret\n}\n\nfunction binarySlice (buf, start, end) {\n var ret = ''\n end = Math.min(buf.length, end)\n\n for (var i = start; i < end; ++i) {\n ret += String.fromCharCode(buf[i])\n }\n return ret\n}\n\nfunction hexSlice (buf, start, end) {\n var len = buf.length\n\n if (!start || start < 0) start = 0\n if (!end || end < 0 || end > len) end = len\n\n var out = ''\n for (var i = start; i < end; ++i) {\n out += toHex(buf[i])\n }\n return out\n}\n\nfunction utf16leSlice (buf, start, end) {\n var bytes = buf.slice(start, end)\n var res = ''\n for (var i = 0; i < bytes.length; i += 2) {\n res += String.fromCharCode(bytes[i] + bytes[i + 1] * 256)\n }\n return res\n}\n\nBuffer.prototype.slice = function slice (start, end) {\n var len = this.length\n start = ~~start\n end = end === undefined ? len : ~~end\n\n if (start < 0) {\n start += len\n if (start < 0) start = 0\n } else if (start > len) {\n start = len\n }\n\n if (end < 0) {\n end += len\n if (end < 0) end = 0\n } else if (end > len) {\n end = len\n }\n\n if (end < start) end = start\n\n var newBuf\n if (Buffer.TYPED_ARRAY_SUPPORT) {\n newBuf = this.subarray(start, end)\n newBuf.__proto__ = Buffer.prototype\n } else {\n var sliceLen = end - start\n newBuf = new Buffer(sliceLen, undefined)\n for (var i = 0; i < sliceLen; ++i) {\n newBuf[i] = this[i + start]\n }\n }\n\n return newBuf\n}\n\n/*\n * Need to make sure that buffer isn't trying to write out of bounds.\n */\nfunction checkOffset (offset, ext, length) {\n if ((offset % 1) !== 0 || offset < 0) throw new RangeError('offset is not uint')\n if (offset + ext > length) throw new RangeError('Trying to access beyond buffer length')\n}\n\nBuffer.prototype.readUIntLE = function readUIntLE (offset, byteLength, noAssert) {\n offset = offset | 0\n byteLength = byteLength | 0\n if (!noAssert) checkOffset(offset, byteLength, this.length)\n\n var val = this[offset]\n var mul = 1\n var i = 0\n while (++i < byteLength && (mul *= 0x100)) {\n val += this[offset + i] * mul\n }\n\n return val\n}\n\nBuffer.prototype.readUIntBE = function readUIntBE (offset, byteLength, noAssert) {\n offset = offset | 0\n byteLength = byteLength | 0\n if (!noAssert) {\n checkOffset(offset, byteLength, this.length)\n }\n\n var val = this[offset + --byteLength]\n var mul = 1\n while (byteLength > 0 && (mul *= 0x100)) {\n val += this[offset + --byteLength] * mul\n }\n\n return val\n}\n\nBuffer.prototype.readUInt8 = function readUInt8 (offset, noAssert) {\n if (!noAssert) checkOffset(offset, 1, this.length)\n return this[offset]\n}\n\nBuffer.prototype.readUInt16LE = function readUInt16LE (offset, noAssert) {\n if (!noAssert) checkOffset(offset, 2, this.length)\n return this[offset] | (this[offset + 1] << 8)\n}\n\nBuffer.prototype.readUInt16BE = function readUInt16BE (offset, noAssert) {\n if (!noAssert) checkOffset(offset, 2, this.length)\n return (this[offset] << 8) | this[offset + 1]\n}\n\nBuffer.prototype.readUInt32LE = function readUInt32LE (offset, noAssert) {\n if (!noAssert) checkOffset(offset, 4, this.length)\n\n return ((this[offset]) |\n (this[offset + 1] << 8) |\n (this[offset + 2] << 16)) +\n (this[offset + 3] * 0x1000000)\n}\n\nBuffer.prototype.readUInt32BE = function readUInt32BE (offset, noAssert) {\n if (!noAssert) checkOffset(offset, 4, this.length)\n\n return (this[offset] * 0x1000000) +\n ((this[offset + 1] << 16) |\n (this[offset + 2] << 8) |\n this[offset + 3])\n}\n\nBuffer.prototype.readIntLE = function readIntLE (offset, byteLength, noAssert) {\n offset = offset | 0\n byteLength = byteLength | 0\n if (!noAssert) checkOffset(offset, byteLength, this.length)\n\n var val = this[offset]\n var mul = 1\n var i = 0\n while (++i < byteLength && (mul *= 0x100)) {\n val += this[offset + i] * mul\n }\n mul *= 0x80\n\n if (val >= mul) val -= Math.pow(2, 8 * byteLength)\n\n return val\n}\n\nBuffer.prototype.readIntBE = function readIntBE (offset, byteLength, noAssert) {\n offset = offset | 0\n byteLength = byteLength | 0\n if (!noAssert) checkOffset(offset, byteLength, this.length)\n\n var i = byteLength\n var mul = 1\n var val = this[offset + --i]\n while (i > 0 && (mul *= 0x100)) {\n val += this[offset + --i] * mul\n }\n mul *= 0x80\n\n if (val >= mul) val -= Math.pow(2, 8 * byteLength)\n\n return val\n}\n\nBuffer.prototype.readInt8 = function readInt8 (offset, noAssert) {\n if (!noAssert) checkOffset(offset, 1, this.length)\n if (!(this[offset] & 0x80)) return (this[offset])\n return ((0xff - this[offset] + 1) * -1)\n}\n\nBuffer.prototype.readInt16LE = function readInt16LE (offset, noAssert) {\n if (!noAssert) checkOffset(offset, 2, this.length)\n var val = this[offset] | (this[offset + 1] << 8)\n return (val & 0x8000) ? val | 0xFFFF0000 : val\n}\n\nBuffer.prototype.readInt16BE = function readInt16BE (offset, noAssert) {\n if (!noAssert) checkOffset(offset, 2, this.length)\n var val = this[offset + 1] | (this[offset] << 8)\n return (val & 0x8000) ? val | 0xFFFF0000 : val\n}\n\nBuffer.prototype.readInt32LE = function readInt32LE (offset, noAssert) {\n if (!noAssert) checkOffset(offset, 4, this.length)\n\n return (this[offset]) |\n (this[offset + 1] << 8) |\n (this[offset + 2] << 16) |\n (this[offset + 3] << 24)\n}\n\nBuffer.prototype.readInt32BE = function readInt32BE (offset, noAssert) {\n if (!noAssert) checkOffset(offset, 4, this.length)\n\n return (this[offset] << 24) |\n (this[offset + 1] << 16) |\n (this[offset + 2] << 8) |\n (this[offset + 3])\n}\n\nBuffer.prototype.readFloatLE = function readFloatLE (offset, noAssert) {\n if (!noAssert) checkOffset(offset, 4, this.length)\n return ieee754.read(this, offset, true, 23, 4)\n}\n\nBuffer.prototype.readFloatBE = function readFloatBE (offset, noAssert) {\n if (!noAssert) checkOffset(offset, 4, this.length)\n return ieee754.read(this, offset, false, 23, 4)\n}\n\nBuffer.prototype.readDoubleLE = function readDoubleLE (offset, noAssert) {\n if (!noAssert) checkOffset(offset, 8, this.length)\n return ieee754.read(this, offset, true, 52, 8)\n}\n\nBuffer.prototype.readDoubleBE = function readDoubleBE (offset, noAssert) {\n if (!noAssert) checkOffset(offset, 8, this.length)\n return ieee754.read(this, offset, false, 52, 8)\n}\n\nfunction checkInt (buf, value, offset, ext, max, min) {\n if (!Buffer.isBuffer(buf)) throw new TypeError('\"buffer\" argument must be a Buffer instance')\n if (value > max || value < min) throw new RangeError('\"value\" argument is out of bounds')\n if (offset + ext > buf.length) throw new RangeError('Index out of range')\n}\n\nBuffer.prototype.writeUIntLE = function writeUIntLE (value, offset, byteLength, noAssert) {\n value = +value\n offset = offset | 0\n byteLength = byteLength | 0\n if (!noAssert) {\n var maxBytes = Math.pow(2, 8 * byteLength) - 1\n checkInt(this, value, offset, byteLength, maxBytes, 0)\n }\n\n var mul = 1\n var i = 0\n this[offset] = value & 0xFF\n while (++i < byteLength && (mul *= 0x100)) {\n this[offset + i] = (value / mul) & 0xFF\n }\n\n return offset + byteLength\n}\n\nBuffer.prototype.writeUIntBE = function writeUIntBE (value, offset, byteLength, noAssert) {\n value = +value\n offset = offset | 0\n byteLength = byteLength | 0\n if (!noAssert) {\n var maxBytes = Math.pow(2, 8 * byteLength) - 1\n checkInt(this, value, offset, byteLength, maxBytes, 0)\n }\n\n var i = byteLength - 1\n var mul = 1\n this[offset + i] = value & 0xFF\n while (--i >= 0 && (mul *= 0x100)) {\n this[offset + i] = (value / mul) & 0xFF\n }\n\n return offset + byteLength\n}\n\nBuffer.prototype.writeUInt8 = function writeUInt8 (value, offset, noAssert) {\n value = +value\n offset = offset | 0\n if (!noAssert) checkInt(this, value, offset, 1, 0xff, 0)\n if (!Buffer.TYPED_ARRAY_SUPPORT) value = Math.floor(value)\n this[offset] = (value & 0xff)\n return offset + 1\n}\n\nfunction objectWriteUInt16 (buf, value, offset, littleEndian) {\n if (value < 0) value = 0xffff + value + 1\n for (var i = 0, j = Math.min(buf.length - offset, 2); i < j; ++i) {\n buf[offset + i] = (value & (0xff << (8 * (littleEndian ? i : 1 - i)))) >>>\n (littleEndian ? i : 1 - i) * 8\n }\n}\n\nBuffer.prototype.writeUInt16LE = function writeUInt16LE (value, offset, noAssert) {\n value = +value\n offset = offset | 0\n if (!noAssert) checkInt(this, value, offset, 2, 0xffff, 0)\n if (Buffer.TYPED_ARRAY_SUPPORT) {\n this[offset] = (value & 0xff)\n this[offset + 1] = (value >>> 8)\n } else {\n objectWriteUInt16(this, value, offset, true)\n }\n return offset + 2\n}\n\nBuffer.prototype.writeUInt16BE = function writeUInt16BE (value, offset, noAssert) {\n value = +value\n offset = offset | 0\n if (!noAssert) checkInt(this, value, offset, 2, 0xffff, 0)\n if (Buffer.TYPED_ARRAY_SUPPORT) {\n this[offset] = (value >>> 8)\n this[offset + 1] = (value & 0xff)\n } else {\n objectWriteUInt16(this, value, offset, false)\n }\n return offset + 2\n}\n\nfunction objectWriteUInt32 (buf, value, offset, littleEndian) {\n if (value < 0) value = 0xffffffff + value + 1\n for (var i = 0, j = Math.min(buf.length - offset, 4); i < j; ++i) {\n buf[offset + i] = (value >>> (littleEndian ? i : 3 - i) * 8) & 0xff\n }\n}\n\nBuffer.prototype.writeUInt32LE = function writeUInt32LE (value, offset, noAssert) {\n value = +value\n offset = offset | 0\n if (!noAssert) checkInt(this, value, offset, 4, 0xffffffff, 0)\n if (Buffer.TYPED_ARRAY_SUPPORT) {\n this[offset + 3] = (value >>> 24)\n this[offset + 2] = (value >>> 16)\n this[offset + 1] = (value >>> 8)\n this[offset] = (value & 0xff)\n } else {\n objectWriteUInt32(this, value, offset, true)\n }\n return offset + 4\n}\n\nBuffer.prototype.writeUInt32BE = function writeUInt32BE (value, offset, noAssert) {\n value = +value\n offset = offset | 0\n if (!noAssert) checkInt(this, value, offset, 4, 0xffffffff, 0)\n if (Buffer.TYPED_ARRAY_SUPPORT) {\n this[offset] = (value >>> 24)\n this[offset + 1] = (value >>> 16)\n this[offset + 2] = (value >>> 8)\n this[offset + 3] = (value & 0xff)\n } else {\n objectWriteUInt32(this, value, offset, false)\n }\n return offset + 4\n}\n\nBuffer.prototype.writeIntLE = function writeIntLE (value, offset, byteLength, noAssert) {\n value = +value\n offset = offset | 0\n if (!noAssert) {\n var limit = Math.pow(2, 8 * byteLength - 1)\n\n checkInt(this, value, offset, byteLength, limit - 1, -limit)\n }\n\n var i = 0\n var mul = 1\n var sub = 0\n this[offset] = value & 0xFF\n while (++i < byteLength && (mul *= 0x100)) {\n if (value < 0 && sub === 0 && this[offset + i - 1] !== 0) {\n sub = 1\n }\n this[offset + i] = ((value / mul) >> 0) - sub & 0xFF\n }\n\n return offset + byteLength\n}\n\nBuffer.prototype.writeIntBE = function writeIntBE (value, offset, byteLength, noAssert) {\n value = +value\n offset = offset | 0\n if (!noAssert) {\n var limit = Math.pow(2, 8 * byteLength - 1)\n\n checkInt(this, value, offset, byteLength, limit - 1, -limit)\n }\n\n var i = byteLength - 1\n var mul = 1\n var sub = 0\n this[offset + i] = value & 0xFF\n while (--i >= 0 && (mul *= 0x100)) {\n if (value < 0 && sub === 0 && this[offset + i + 1] !== 0) {\n sub = 1\n }\n this[offset + i] = ((value / mul) >> 0) - sub & 0xFF\n }\n\n return offset + byteLength\n}\n\nBuffer.prototype.writeInt8 = function writeInt8 (value, offset, noAssert) {\n value = +value\n offset = offset | 0\n if (!noAssert) checkInt(this, value, offset, 1, 0x7f, -0x80)\n if (!Buffer.TYPED_ARRAY_SUPPORT) value = Math.floor(value)\n if (value < 0) value = 0xff + value + 1\n this[offset] = (value & 0xff)\n return offset + 1\n}\n\nBuffer.prototype.writeInt16LE = function writeInt16LE (value, offset, noAssert) {\n value = +value\n offset = offset | 0\n if (!noAssert) checkInt(this, value, offset, 2, 0x7fff, -0x8000)\n if (Buffer.TYPED_ARRAY_SUPPORT) {\n this[offset] = (value & 0xff)\n this[offset + 1] = (value >>> 8)\n } else {\n objectWriteUInt16(this, value, offset, true)\n }\n return offset + 2\n}\n\nBuffer.prototype.writeInt16BE = function writeInt16BE (value, offset, noAssert) {\n value = +value\n offset = offset | 0\n if (!noAssert) checkInt(this, value, offset, 2, 0x7fff, -0x8000)\n if (Buffer.TYPED_ARRAY_SUPPORT) {\n this[offset] = (value >>> 8)\n this[offset + 1] = (value & 0xff)\n } else {\n objectWriteUInt16(this, value, offset, false)\n }\n return offset + 2\n}\n\nBuffer.prototype.writeInt32LE = function writeInt32LE (value, offset, noAssert) {\n value = +value\n offset = offset | 0\n if (!noAssert) checkInt(this, value, offset, 4, 0x7fffffff, -0x80000000)\n if (Buffer.TYPED_ARRAY_SUPPORT) {\n this[offset] = (value & 0xff)\n this[offset + 1] = (value >>> 8)\n this[offset + 2] = (value >>> 16)\n this[offset + 3] = (value >>> 24)\n } else {\n objectWriteUInt32(this, value, offset, true)\n }\n return offset + 4\n}\n\nBuffer.prototype.writeInt32BE = function writeInt32BE (value, offset, noAssert) {\n value = +value\n offset = offset | 0\n if (!noAssert) checkInt(this, value, offset, 4, 0x7fffffff, -0x80000000)\n if (value < 0) value = 0xffffffff + value + 1\n if (Buffer.TYPED_ARRAY_SUPPORT) {\n this[offset] = (value >>> 24)\n this[offset + 1] = (value >>> 16)\n this[offset + 2] = (value >>> 8)\n this[offset + 3] = (value & 0xff)\n } else {\n objectWriteUInt32(this, value, offset, false)\n }\n return offset + 4\n}\n\nfunction checkIEEE754 (buf, value, offset, ext, max, min) {\n if (offset + ext > buf.length) throw new RangeError('Index out of range')\n if (offset < 0) throw new RangeError('Index out of range')\n}\n\nfunction writeFloat (buf, value, offset, littleEndian, noAssert) {\n if (!noAssert) {\n checkIEEE754(buf, value, offset, 4, 3.4028234663852886e+38, -3.4028234663852886e+38)\n }\n ieee754.write(buf, value, offset, littleEndian, 23, 4)\n return offset + 4\n}\n\nBuffer.prototype.writeFloatLE = function writeFloatLE (value, offset, noAssert) {\n return writeFloat(this, value, offset, true, noAssert)\n}\n\nBuffer.prototype.writeFloatBE = function writeFloatBE (value, offset, noAssert) {\n return writeFloat(this, value, offset, false, noAssert)\n}\n\nfunction writeDouble (buf, value, offset, littleEndian, noAssert) {\n if (!noAssert) {\n checkIEEE754(buf, value, offset, 8, 1.7976931348623157E+308, -1.7976931348623157E+308)\n }\n ieee754.write(buf, value, offset, littleEndian, 52, 8)\n return offset + 8\n}\n\nBuffer.prototype.writeDoubleLE = function writeDoubleLE (value, offset, noAssert) {\n return writeDouble(this, value, offset, true, noAssert)\n}\n\nBuffer.prototype.writeDoubleBE = function writeDoubleBE (value, offset, noAssert) {\n return writeDouble(this, value, offset, false, noAssert)\n}\n\n// copy(targetBuffer, targetStart=0, sourceStart=0, sourceEnd=buffer.length)\nBuffer.prototype.copy = function copy (target, targetStart, start, end) {\n if (!start) start = 0\n if (!end && end !== 0) end = this.length\n if (targetStart >= target.length) targetStart = target.length\n if (!targetStart) targetStart = 0\n if (end > 0 && end < start) end = start\n\n // Copy 0 bytes; we're done\n if (end === start) return 0\n if (target.length === 0 || this.length === 0) return 0\n\n // Fatal error conditions\n if (targetStart < 0) {\n throw new RangeError('targetStart out of bounds')\n }\n if (start < 0 || start >= this.length) throw new RangeError('sourceStart out of bounds')\n if (end < 0) throw new RangeError('sourceEnd out of bounds')\n\n // Are we oob?\n if (end > this.length) end = this.length\n if (target.length - targetStart < end - start) {\n end = target.length - targetStart + start\n }\n\n var len = end - start\n var i\n\n if (this === target && start < targetStart && targetStart < end) {\n // descending copy from end\n for (i = len - 1; i >= 0; --i) {\n target[i + targetStart] = this[i + start]\n }\n } else if (len < 1000 || !Buffer.TYPED_ARRAY_SUPPORT) {\n // ascending copy from start\n for (i = 0; i < len; ++i) {\n target[i + targetStart] = this[i + start]\n }\n } else {\n Uint8Array.prototype.set.call(\n target,\n this.subarray(start, start + len),\n targetStart\n )\n }\n\n return len\n}\n\n// Usage:\n// buffer.fill(number[, offset[, end]])\n// buffer.fill(buffer[, offset[, end]])\n// buffer.fill(string[, offset[, end]][, encoding])\nBuffer.prototype.fill = function fill (val, start, end, encoding) {\n // Handle string cases:\n if (typeof val === 'string') {\n if (typeof start === 'string') {\n encoding = start\n start = 0\n end = this.length\n } else if (typeof end === 'string') {\n encoding = end\n end = this.length\n }\n if (val.length === 1) {\n var code = val.charCodeAt(0)\n if (code < 256) {\n val = code\n }\n }\n if (encoding !== undefined && typeof encoding !== 'string') {\n throw new TypeError('encoding must be a string')\n }\n if (typeof encoding === 'string' && !Buffer.isEncoding(encoding)) {\n throw new TypeError('Unknown encoding: ' + encoding)\n }\n } else if (typeof val === 'number') {\n val = val & 255\n }\n\n // Invalid ranges are not set to a default, so can range check early.\n if (start < 0 || this.length < start || this.length < end) {\n throw new RangeError('Out of range index')\n }\n\n if (end <= start) {\n return this\n }\n\n start = start >>> 0\n end = end === undefined ? this.length : end >>> 0\n\n if (!val) val = 0\n\n var i\n if (typeof val === 'number') {\n for (i = start; i < end; ++i) {\n this[i] = val\n }\n } else {\n var bytes = Buffer.isBuffer(val)\n ? val\n : utf8ToBytes(new Buffer(val, encoding).toString())\n var len = bytes.length\n for (i = 0; i < end - start; ++i) {\n this[i + start] = bytes[i % len]\n }\n }\n\n return this\n}\n\n// HELPER FUNCTIONS\n// ================\n\nvar INVALID_BASE64_RE = /[^+\\/0-9A-Za-z-_]/g\n\nfunction base64clean (str) {\n // Node strips out invalid characters like \\n and \\t from the string, base64-js does not\n str = stringtrim(str).replace(INVALID_BASE64_RE, '')\n // Node converts strings with length < 2 to ''\n if (str.length < 2) return ''\n // Node allows for non-padded base64 strings (missing trailing ===), base64-js does not\n while (str.length % 4 !== 0) {\n str = str + '='\n }\n return str\n}\n\nfunction stringtrim (str) {\n if (str.trim) return str.trim()\n return str.replace(/^\\s+|\\s+$/g, '')\n}\n\nfunction toHex (n) {\n if (n < 16) return '0' + n.toString(16)\n return n.toString(16)\n}\n\nfunction utf8ToBytes (string, units) {\n units = units || Infinity\n var codePoint\n var length = string.length\n var leadSurrogate = null\n var bytes = []\n\n for (var i = 0; i < length; ++i) {\n codePoint = string.charCodeAt(i)\n\n // is surrogate component\n if (codePoint > 0xD7FF && codePoint < 0xE000) {\n // last char was a lead\n if (!leadSurrogate) {\n // no lead yet\n if (codePoint > 0xDBFF) {\n // unexpected trail\n if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD)\n continue\n } else if (i + 1 === length) {\n // unpaired lead\n if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD)\n continue\n }\n\n // valid lead\n leadSurrogate = codePoint\n\n continue\n }\n\n // 2 leads in a row\n if (codePoint < 0xDC00) {\n if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD)\n leadSurrogate = codePoint\n continue\n }\n\n // valid surrogate pair\n codePoint = (leadSurrogate - 0xD800 << 10 | codePoint - 0xDC00) + 0x10000\n } else if (leadSurrogate) {\n // valid bmp char, but last char was a lead\n if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD)\n }\n\n leadSurrogate = null\n\n // encode utf8\n if (codePoint < 0x80) {\n if ((units -= 1) < 0) break\n bytes.push(codePoint)\n } else if (codePoint < 0x800) {\n if ((units -= 2) < 0) break\n bytes.push(\n codePoint >> 0x6 | 0xC0,\n codePoint & 0x3F | 0x80\n )\n } else if (codePoint < 0x10000) {\n if ((units -= 3) < 0) break\n bytes.push(\n codePoint >> 0xC | 0xE0,\n codePoint >> 0x6 & 0x3F | 0x80,\n codePoint & 0x3F | 0x80\n )\n } else if (codePoint < 0x110000) {\n if ((units -= 4) < 0) break\n bytes.push(\n codePoint >> 0x12 | 0xF0,\n codePoint >> 0xC & 0x3F | 0x80,\n codePoint >> 0x6 & 0x3F | 0x80,\n codePoint & 0x3F | 0x80\n )\n } else {\n throw new Error('Invalid code point')\n }\n }\n\n return bytes\n}\n\nfunction asciiToBytes (str) {\n var byteArray = []\n for (var i = 0; i < str.length; ++i) {\n // Node's code seems to be doing this and not & 0x7F..\n byteArray.push(str.charCodeAt(i) & 0xFF)\n }\n return byteArray\n}\n\nfunction utf16leToBytes (str, units) {\n var c, hi, lo\n var byteArray = []\n for (var i = 0; i < str.length; ++i) {\n if ((units -= 2) < 0) break\n\n c = str.charCodeAt(i)\n hi = c >> 8\n lo = c % 256\n byteArray.push(lo)\n byteArray.push(hi)\n }\n\n return byteArray\n}\n\nfunction base64ToBytes (str) {\n return base64.toByteArray(base64clean(str))\n}\n\nfunction blitBuffer (src, dst, offset, length) {\n for (var i = 0; i < length; ++i) {\n if ((i + offset >= dst.length) || (i >= src.length)) break\n dst[i + offset] = src[i]\n }\n return i\n}\n\nfunction isnan (val) {\n return val !== val // eslint-disable-line no-self-compare\n}\n","'use strict';\n\nvar Channel = require('../service/channel-service');\nvar SessionManager = require('../store/session-manager');\n\n/**\n * ## Channel Manager\n *\n * There are two main use cases for the channel: event notifications and chat messages.\n *\n * The Channel Manager is a wrapper around the default [cometd JavaScript library](http://docs.cometd.org/2/reference/javascript.html), `$.cometd`. It provides a few nice features that `$.cometd` doesn't, including:\n *\n * * Automatic re-subscription to channels if you lose your connection\n * * Online / Offline notifications\n * * 'Events' for cometd notifications (instead of having to listen on specific meta channels)\n *\n * While you can work directly with the Channel Manager through Node.js (for example, `require('manager/channel-manager')`) -- or even work directly with `$.cometd` and Epicenter's underlying [Push Channel API](../../../rest_apis/multiplayer/channel/) -- most often it will be easiest to work with the [Epicenter Channel Manager](../epicenter-channel-manager/). The Epicenter Channel Manager is a wrapper that instantiates a Channel Manager with Epicenter-specific defaults.\n *\n * You'll need to include the `epicenter-multiplayer-dependencies.js` library in addition to the `epicenter.js` library in your project to use the Channel Manager. (See [Including Epicenter.js](../../#include).)\n *\n * To use the Channel Manager in client-side JavaScript, instantiate the [Epicenter Channel Manager](../epicenter-channel-manager/), get the channel, then use the channel's `subscribe()` and `publish()` methods to subscribe to topics or publish data to topics.\n *\n * var cm = new F.manager.ChannelManager();\n * var channel = cm.getChannel();\n *\n * channel.subscribe('topic', callback);\n * channel.publish('topic', { myData: 100 });\n *\n * The parameters for instantiating a Channel Manager include:\n *\n * * `options` The options object to configure the Channel Manager. Besides the common options listed here, see http://docs.cometd.org/reference/javascript.html for other supported options.\n * * `options.url` The Cometd endpoint URL.\n * * `options.websocketEnabled` Whether websocket support is active (boolean).\n * * `options.channel` Other defaults to pass on to instances of the underlying Channel Service. See [Channel Service](../channel-service/) for details.\n *\n */\nvar ChannelManager = function (options) {\n if (!$.cometd) {\n throw new Error('Cometd library not found. Please include epicenter-multiplayer-dependencies.js');\n }\n if (!options || !options.url) {\n throw new Error('Please provide an url for the cometd server');\n }\n\n var defaults = {\n /**\n * The Cometd endpoint URL.\n * @type {string}\n */\n url: '',\n\n /**\n * The log level for the channel (logs to console).\n * @type {string}\n */\n logLevel: 'info',\n\n /**\n * Whether websocket support is active. Defaults to `false`; Epicenter doesn't currently support communication through websockets.\n * @type {boolean}\n */\n websocketEnabled: false,\n\n /**\n * If false each instance of Channel will have a separate cometd connection to server, which could be noisy. Set to true to re-use the same connection across instances.\n * @type {boolean}\n */\n shareConnection: false,\n\n /**\n * Other defaults to pass on to instances of the underlying [Channel Service](../channel-service/), which are created through `getChannel()`.\n * @type {object}\n */\n channel: {\n\n },\n\n /**\n * Options to pass to the channel handshake.\n *\n * For example, the [Epicenter Channel Manager](../epicenter-channel-manager/) passes `ext` and authorization information. More information on possible options is in the details of the underlying [Push Channel API](../../../rest_apis/multiplayer/channel/).\n *\n * @type {object}\n */\n handshake: undefined\n };\n this.sessionManager = new SessionManager();\n var defaultCometOptions = this.sessionManager.getMergedOptions(defaults, options);\n this.currentSubscriptions = [];\n this.options = defaultCometOptions;\n\n if (defaultCometOptions.shareConnection && ChannelManager.prototype._cometd) {\n this.cometd = ChannelManager.prototype._cometd;\n return this;\n }\n var cometd = new $.Cometd();\n ChannelManager.prototype._cometd = cometd;\n\n cometd.websocketEnabled = defaultCometOptions.websocketEnabled;\n\n this.isConnected = false;\n var connectionBroken = function (message) {\n $(this).trigger('disconnect', message);\n };\n var connectionSucceeded = function (message) {\n $(this).trigger('connect', message);\n };\n var me = this;\n\n cometd.configure(defaultCometOptions);\n\n cometd.addListener('/meta/connect', function (message) {\n var wasConnected = this.isConnected;\n this.isConnected = (message.successful === true);\n if (!wasConnected && this.isConnected) { //Connecting for the first time\n connectionSucceeded.call(this, message);\n } else if (wasConnected && !this.isConnected) { //Only throw disconnected message fro the first disconnect, not once per try\n connectionBroken.call(this, message);\n }\n }.bind(this));\n\n cometd.addListener('/meta/disconnect', connectionBroken);\n\n cometd.addListener('/meta/handshake', function (message) {\n if (message.successful) {\n //http://docs.cometd.org/reference/javascript_subscribe.html#javascript_subscribe_meta_channels\n // ^ \"dynamic subscriptions are cleared (like any other subscription) and the application needs to figure out which dynamic subscription must be performed again\"\n cometd.batch(function () {\n $(me.currentSubscriptions).each(function (index, subs) {\n cometd.resubscribe(subs);\n });\n });\n }\n });\n\n //Other interesting events for reference\n cometd.addListener('/meta/subscribe', function (message) {\n $(me).trigger('subscribe', message);\n });\n cometd.addListener('/meta/unsubscribe', function (message) {\n $(me).trigger('unsubscribe', message);\n });\n cometd.addListener('/meta/publish', function (message) {\n $(me).trigger('publish', message);\n });\n cometd.addListener('/meta/unsuccessful', function (message) {\n $(me).trigger('error', message);\n });\n\n cometd.handshake(defaultCometOptions.handshake);\n\n this.cometd = cometd;\n};\n\n\nChannelManager.prototype = $.extend(ChannelManager.prototype, {\n\n /**\n * Creates and returns a channel, that is, an instance of a [Channel Service](../channel-service/).\n *\n * **Example**\n *\n * var cm = new F.manager.ChannelManager();\n * var channel = cm.getChannel();\n *\n * channel.subscribe('topic', callback);\n * channel.publish('topic', { myData: 100 });\n *\n * **Parameters**\n * @param {Object|String} `options` (Optional) If string, assumed to be the base channel url. If object, assumed to be configuration options for the constructor.\n */\n getChannel: function (options) {\n //If you just want to pass in a string\n if (options && !$.isPlainObject(options)) {\n options = {\n base: options\n };\n }\n var defaults = {\n transport: this.cometd\n };\n var channel = new Channel($.extend(true, {}, this.options.channel, defaults, options));\n\n\n //Wrap subs and unsubs so we can use it to re-attach handlers after being disconnected\n var subs = channel.subscribe;\n channel.subscribe = function () {\n var subid = subs.apply(channel, arguments);\n this.currentSubscriptions = this.currentSubscriptions.concat(subid);\n return subid;\n }.bind(this);\n\n\n var unsubs = channel.unsubscribe;\n channel.unsubscribe = function () {\n var removed = unsubs.apply(channel, arguments);\n for (var i = 0; i < this.currentSubscriptions.length; i++) {\n if (this.currentSubscriptions[i].id === removed.id) {\n this.currentSubscriptions.splice(i, 1);\n }\n }\n return removed;\n }.bind(this);\n\n return channel;\n },\n\n /**\n * Start listening for events on this instance. Signature is same as for jQuery Events: http://api.jquery.com/on/.\n *\n * Supported events are: `connect`, `disconnect`, `subscribe`, `unsubscribe`, `publish`, `error`.\n *\n * **Parameters**\n *\n * @param {string} `event` The event type. See more detail at jQuery Events: http://api.jquery.com/on/.\n */\n on: function (event) {\n $(this).on.apply($(this), arguments);\n },\n\n /**\n * Stop listening for events on this instance. Signature is same as for jQuery Events: http://api.jquery.com/off/.\n *\n * **Parameters**\n *\n * @param {string} `event` The event type. See more detail at jQuery Events: http://api.jquery.com/off/.\n */\n off: function (event) {\n $(this).off.apply($(this), arguments);\n },\n\n /**\n * Trigger events and execute handlers. Signature is same as for jQuery Events: http://api.jquery.com/trigger/.\n *\n * **Parameters**\n *\n * @param {string} `event` The event type. See more detail at jQuery Events: http://api.jquery.com/trigger/.\n */\n trigger: function (event) {\n $(this).trigger.apply($(this), arguments);\n }\n});\n\nmodule.exports = ChannelManager;\n","'use strict';\n\nmodule.exports = {\n EPI_SESSION_KEY: 'epicenterjs.session',\n STRATEGY_SESSION_KEY: 'epicenter-scenario'\n};","'use strict';\n\nvar ConfigService = require('../service/configuration-service');\n\nvar urlConfig = new ConfigService().get('server');\nvar customDefaults = {};\nvar libDefaults = {\n /**\n * The account id. In the Epicenter UI, this is the **Team ID** (for team projects) or **User ID** (for personal projects). Defaults to empty string. If left undefined, taken from the URL.\n * @type {String}\n */\n account: urlConfig.accountPath,\n /**\n * The account id. In the Epicenter UI, this is the **Team ID** (for team projects) or **User ID** (for personal projects). Defaults to empty string. If left undefined, taken from the URL.\n * @type {String}\n */\n project: urlConfig.projectPath,\n isLocal: urlConfig.isLocalhost(),\n store: {}\n};\n\nvar optionUtils = {\n /**\n * Gets the final options by overriding the global options set with\n * optionUtils#setDefaults() and the lib defaults.\n * @param {object} `options` The final options object.\n */\n getOptions: function (options) {\n return $.extend(true, {}, libDefaults, customDefaults, options);\n },\n /**\n * Sets the global defaults for the optionUtils#getOptions() method.\n * @param {object} `defaults` The defaults object.\n */\n setDefaults: function (defaults) {\n customDefaults = defaults;\n }\n};\nmodule.exports = optionUtils;\n","'use strict';\n\nvar classFrom = require('../../util/inherit');\n\nvar IdentityStrategy = require('./identity-strategy');\nvar WorldApiAdapter = require('../../service/world-api-adapter');\nvar AuthManager = require('../auth-manager');\n\nvar defaults = {\n store: {\n synchronous: true\n }\n};\n\nvar Strategy = classFrom(IdentityStrategy, {\n\n constructor: function (runService, options) {\n this.runService = runService;\n this.options = $.extend(true, {}, defaults, options);\n this._auth = new AuthManager();\n this._loadRun = this._loadRun.bind(this);\n this.worldApi = new WorldApiAdapter(this.options.run);\n },\n\n reset: function () {\n var session = this._auth.getCurrentUserSessionInfo();\n var curUserId = session.userId;\n var curGroupName = session.groupName;\n\n return this.worldApi\n .getCurrentWorldForUser(curUserId, curGroupName)\n .then(function (world) {\n return this.worldApi.newRunForWorld(world.id);\n }.bind(this));\n },\n\n getRun: function () {\n var session = this._auth.getCurrentUserSessionInfo();\n var curUserId = session.userId;\n var curGroupName = session.groupName;\n var worldApi = this.worldApi;\n var model = this.options.model;\n var _this = this;\n var dtd = $.Deferred();\n\n if (!curUserId) {\n return dtd.reject({ statusCode: 400, error: 'We need an authenticated user to join a multiplayer world. (ERR: no userId in session)' }, session).promise();\n }\n\n var loadRunFromWorld = function (world) {\n if (!world) {\n return dtd.reject({ statusCode: 404, error: 'The user is not in any world.' }, { options: this.options, session: session });\n }\n\n return worldApi.getCurrentRunId({ model: model, filter: world.id })\n .then(_this._loadRun)\n .then(dtd.resolve)\n .fail(dtd.reject);\n };\n\n var serverError = function (error) {\n // is this possible?\n dtd.reject(error, session, this.options);\n };\n\n this.worldApi\n .getCurrentWorldForUser(curUserId, curGroupName)\n .then(loadRunFromWorld)\n .fail(serverError);\n\n return dtd.promise();\n },\n\n _loadRun: function (id, options) {\n return this.runService.load(id, null, options);\n }\n});\n\nmodule.exports = Strategy;\n","'use strict';\n\nvar classFrom = require('../../util/inherit');\nvar IdentityStrategy = require('./identity-strategy');\nvar StorageFactory = require('../../store/store-factory');\nvar StateApi = require('../../service/state-api-adapter');\nvar AuthManager = require('../auth-manager');\n\nvar keyNames = require('../key-names');\n\nvar defaults = {\n store: {\n synchronous: true\n }\n};\n\nvar Strategy = classFrom(IdentityStrategy, {\n constructor: function Strategy(runService, options) {\n this.run = runService;\n this.options = $.extend(true, {}, defaults, options);\n this.runOptions = this.options.run;\n this._store = new StorageFactory(this.options.store);\n this.stateApi = new StateApi();\n this._auth = new AuthManager();\n\n this._loadAndCheck = this._loadAndCheck.bind(this);\n this._restoreRun = this._restoreRun.bind(this);\n this._getAllRuns = this._getAllRuns.bind(this);\n this._loadRun = this._loadRun.bind(this);\n },\n\n reset: function (runServiceOptions) {\n var session = this._auth.getCurrentUserSessionInfo();\n var opt = $.extend({\n scope: { group: session.groupName }\n }, this.runOptions);\n\n return this.run\n .create(opt, runServiceOptions)\n .then(function (run) {\n run.freshlyCreated = true;\n return run;\n });\n },\n\n getRun: function () {\n return this._getAllRuns()\n .then(this._loadAndCheck);\n },\n\n _getAllRuns: function () {\n var session = JSON.parse(this._store.get(keyNames.EPI_SESSION_KEY) || '{}');\n return this.run.query({\n 'user.id': session.userId || '0000',\n 'scope.group': session.groupName\n });\n },\n\n _loadAndCheck: function (runs) {\n if (!runs || !runs.length) {\n return this.reset();\n }\n\n var dateComp = function (a, b) { return new Date(b.date) - new Date(a.date); };\n var latestRun = runs.sort(dateComp)[0];\n var _this = this;\n var shouldReplay = false;\n\n return this.run.load(latestRun.id, null, {\n success: function (run, msg, headers) {\n shouldReplay = headers.getResponseHeader('pragma') === 'persistent';\n }\n }).then(function (run) {\n return shouldReplay ? _this._restoreRun(run.id) : run;\n });\n },\n\n _restoreRun: function (runId) {\n var _this = this;\n return this.stateApi.replay({ runId: runId })\n .then(function (resp) {\n return _this._loadRun(resp.run);\n });\n },\n\n _loadRun: function (id, options) {\n return this.run.load(id, null, options);\n }\n\n});\n\nmodule.exports = Strategy;\n","var toString = {}.toString;\n\nmodule.exports = Array.isArray || function (arr) {\n return toString.call(arr) == '[object Array]';\n};\n","exports.read = function (buffer, offset, isLE, mLen, nBytes) {\n var e, m\n var eLen = nBytes * 8 - mLen - 1\n var eMax = (1 << eLen) - 1\n var eBias = eMax >> 1\n var nBits = -7\n var i = isLE ? (nBytes - 1) : 0\n var d = isLE ? -1 : 1\n var s = buffer[offset + i]\n\n i += d\n\n e = s & ((1 << (-nBits)) - 1)\n s >>= (-nBits)\n nBits += eLen\n for (; nBits > 0; e = e * 256 + buffer[offset + i], i += d, nBits -= 8) {}\n\n m = e & ((1 << (-nBits)) - 1)\n e >>= (-nBits)\n nBits += mLen\n for (; nBits > 0; m = m * 256 + buffer[offset + i], i += d, nBits -= 8) {}\n\n if (e === 0) {\n e = 1 - eBias\n } else if (e === eMax) {\n return m ? NaN : ((s ? -1 : 1) * Infinity)\n } else {\n m = m + Math.pow(2, mLen)\n e = e - eBias\n }\n return (s ? -1 : 1) * m * Math.pow(2, e - mLen)\n}\n\nexports.write = function (buffer, value, offset, isLE, mLen, nBytes) {\n var e, m, c\n var eLen = nBytes * 8 - mLen - 1\n var eMax = (1 << eLen) - 1\n var eBias = eMax >> 1\n var rt = (mLen === 23 ? Math.pow(2, -24) - Math.pow(2, -77) : 0)\n var i = isLE ? 0 : (nBytes - 1)\n var d = isLE ? 1 : -1\n var s = value < 0 || (value === 0 && 1 / value < 0) ? 1 : 0\n\n value = Math.abs(value)\n\n if (isNaN(value) || value === Infinity) {\n m = isNaN(value) ? 1 : 0\n e = eMax\n } else {\n e = Math.floor(Math.log(value) / Math.LN2)\n if (value * (c = Math.pow(2, -e)) < 1) {\n e--\n c *= 2\n }\n if (e + eBias >= 1) {\n value += rt / c\n } else {\n value += rt * Math.pow(2, 1 - eBias)\n }\n if (value * c >= 2) {\n e++\n c /= 2\n }\n\n if (e + eBias >= eMax) {\n m = 0\n e = eMax\n } else if (e + eBias >= 1) {\n m = (value * c - 1) * Math.pow(2, mLen)\n e = e + eBias\n } else {\n m = value * Math.pow(2, eBias - 1) * Math.pow(2, mLen)\n e = 0\n }\n }\n\n for (; mLen >= 8; buffer[offset + i] = m & 0xff, i += d, m /= 256, mLen -= 8) {}\n\n e = (e << mLen) | m\n eLen += mLen\n for (; eLen > 0; buffer[offset + i] = e & 0xff, i += d, e /= 256, eLen -= 8) {}\n\n buffer[offset + i - d] |= s * 128\n}\n","'use strict'\n\nexports.toByteArray = toByteArray\nexports.fromByteArray = fromByteArray\n\nvar lookup = []\nvar revLookup = []\nvar Arr = typeof Uint8Array !== 'undefined' ? Uint8Array : Array\n\nfunction init () {\n var code = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'\n for (var i = 0, len = code.length; i < len; ++i) {\n lookup[i] = code[i]\n revLookup[code.charCodeAt(i)] = i\n }\n\n revLookup['-'.charCodeAt(0)] = 62\n revLookup['_'.charCodeAt(0)] = 63\n}\n\ninit()\n\nfunction toByteArray (b64) {\n var i, j, l, tmp, placeHolders, arr\n var len = b64.length\n\n if (len % 4 > 0) {\n throw new Error('Invalid string. Length must be a multiple of 4')\n }\n\n // the number of equal signs (place holders)\n // if there are two placeholders, than the two characters before it\n // represent one byte\n // if there is only one, then the three characters before it represent 2 bytes\n // this is just a cheap hack to not do indexOf twice\n placeHolders = b64[len - 2] === '=' ? 2 : b64[len - 1] === '=' ? 1 : 0\n\n // base64 is 4/3 + up to two characters of the original data\n arr = new Arr(len * 3 / 4 - placeHolders)\n\n // if there are placeholders, only get up to the last complete 4 chars\n l = placeHolders > 0 ? len - 4 : len\n\n var L = 0\n\n for (i = 0, j = 0; i < l; i += 4, j += 3) {\n tmp = (revLookup[b64.charCodeAt(i)] << 18) | (revLookup[b64.charCodeAt(i + 1)] << 12) | (revLookup[b64.charCodeAt(i + 2)] << 6) | revLookup[b64.charCodeAt(i + 3)]\n arr[L++] = (tmp >> 16) & 0xFF\n arr[L++] = (tmp >> 8) & 0xFF\n arr[L++] = tmp & 0xFF\n }\n\n if (placeHolders === 2) {\n tmp = (revLookup[b64.charCodeAt(i)] << 2) | (revLookup[b64.charCodeAt(i + 1)] >> 4)\n arr[L++] = tmp & 0xFF\n } else if (placeHolders === 1) {\n tmp = (revLookup[b64.charCodeAt(i)] << 10) | (revLookup[b64.charCodeAt(i + 1)] << 4) | (revLookup[b64.charCodeAt(i + 2)] >> 2)\n arr[L++] = (tmp >> 8) & 0xFF\n arr[L++] = tmp & 0xFF\n }\n\n return arr\n}\n\nfunction tripletToBase64 (num) {\n return lookup[num >> 18 & 0x3F] + lookup[num >> 12 & 0x3F] + lookup[num >> 6 & 0x3F] + lookup[num & 0x3F]\n}\n\nfunction encodeChunk (uint8, start, end) {\n var tmp\n var output = []\n for (var i = start; i < end; i += 3) {\n tmp = (uint8[i] << 16) + (uint8[i + 1] << 8) + (uint8[i + 2])\n output.push(tripletToBase64(tmp))\n }\n return output.join('')\n}\n\nfunction fromByteArray (uint8) {\n var tmp\n var len = uint8.length\n var extraBytes = len % 3 // if we have 1 byte left, pad 2 bytes\n var output = ''\n var parts = []\n var maxChunkLength = 16383 // must be multiple of 3\n\n // go through the array every three bytes, we'll deal with trailing stuff later\n for (var i = 0, len2 = len - extraBytes; i < len2; i += maxChunkLength) {\n parts.push(encodeChunk(uint8, i, (i + maxChunkLength) > len2 ? len2 : (i + maxChunkLength)))\n }\n\n // pad the end with zeros, but make sure to not forget the extra bytes\n if (extraBytes === 1) {\n tmp = uint8[len - 1]\n output += lookup[tmp >> 2]\n output += lookup[(tmp << 4) & 0x3F]\n output += '=='\n } else if (extraBytes === 2) {\n tmp = (uint8[len - 2] << 8) + (uint8[len - 1])\n output += lookup[tmp >> 10]\n output += lookup[(tmp >> 4) & 0x3F]\n output += lookup[(tmp << 2) & 0x3F]\n output += '='\n }\n\n parts.push(output)\n\n return parts.join('')\n}\n"]} +>>>>>>> dms3-version diff --git a/src/api-version.json b/src/api-version.json index 4fdc6069..8d8d9384 100644 --- a/src/api-version.json +++ b/src/api-version.json @@ -1,3 +1,3 @@ { - "version": "" + "version": "v2" } diff --git a/src/service/admin-file-service.js b/src/service/admin-file-service.js index fc8f026f..44495755 100644 --- a/src/service/admin-file-service.js +++ b/src/service/admin-file-service.js @@ -1,7 +1,9 @@ /** * ## File API Service * - * This is used to upload/download files directly onto Epicenter, analogous to using the File Manager UI in Epicenter directly or SFTPing files in. The Asset API is typically used for all project use-cases, and it's unlikely this File Service will be used directly except by Admin tools (e.g. Flow Inspector). + * The File API Service allows you to upload and download files directly onto Epicenter, analogous to using the File Manager UI in Epicenter directly or SFTPing files in. It is based on the Epicenter File API. + * + * The Asset API Service (https://forio.com/epicenter/docs/public/api_adapters/generated/asset-api-adapter/) is typically used for all project use cases, and it's unlikely this File Service will be used directly except by Admin tools (e.g. Flow Inspector). * * Partially implemented. */ @@ -22,19 +24,19 @@ module.exports = function (config) { token: undefined, /** - * 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. + * The account id. In the Epicenter UI, this is the **Team ID** (for team projects) or **User ID** (for personal projects). Defaults to undefined. * @type {String} */ account: undefined, /** - * The project id. Defaults to empty string. + * The project id. Defaults to undefined. * @type {String} */ project: undefined, /** - * The folder type. One of Model|Static|Node + * The folder type. One of `model` | `static` | `node`. * @type {String} */ folderType: 'static', @@ -68,9 +70,37 @@ module.exports = function (config) { } var http = new TransportFactory(httpOptions); + function uploadBody(fileName, contents) { + var boundary = '---------------------------7da24f2e50046'; + + return { + body: '--' + boundary + '\r\n' + + 'Content-Disposition: form-data; name="file";' + + 'filename="' + fileName + '"\r\n' + + 'Content-type: text/html\r\n\r\n' + + contents + '\r\n' + + '--' + boundary + '--', + boundary: boundary + }; + } + + function uploadFileOptions(filePath, contents, options) { + filePath = filePath.split('/'); + var fileName = filePath.pop(); + filePath = filePath.join('/'); + var path = serviceOptions.folderType + '/' + filePath; + var upload = uploadBody(fileName, contents); + + return $.extend(true, {}, serviceOptions, options, { + url: urlConfig.getAPIPath('file') + path, + data: upload.body, + contentType: 'multipart/form-data; boundary=' + upload.boundary + }); + } + var publicAsyncAPI = { /** - * Get a directory listing, or contents of a file + * Get a directory listing, or contents of a file. * @param {String} `filePath` Path to the file * @param {Object} `options` (Optional) Overrides for configuration options. */ @@ -83,36 +113,48 @@ module.exports = function (config) { }, /** - * Writes to the given file path; replaces the existing file if it exists + * Replaces the file at the given file path. * @param {String} `filePath` Path to the file * @param {String} `contents` Contents to write to file * @param {Object} `options` (Optional) Overrides for configuration options */ - writeToFile: function (filePath, contents, options) { - filePath = filePath.split('/'); - var fileName = filePath.pop(); - filePath = filePath.join('/'); - var path = serviceOptions.folderType + '/' + filePath; - var boundary = '---------------------------7da24f2e50046'; + replace: function (filePath, contents, options) { + var httpOptions = uploadFileOptions(filePath, contents, options); - var body = '--' + boundary + '\r\n' + - 'Content-Disposition: form-data; name="file";' + - 'filename="' + fileName + '"\r\n' + - 'Content-type: text/html\r\n\r\n' + - contents + '\r\n' + - '--' + boundary + '--'; + return http.put(httpOptions.data, httpOptions); + }, - var httpOptions = $.extend(true, {}, serviceOptions, options, { - url: urlConfig.getAPIPath('file') + path, - data: body, - contentType: 'multipart/form-data; boundary=' + boundary - }); + /** + * Creates a file in the given file path. + * @param {String} `filePath` Path to the file + * @param {String} `contents` Contents to write to file + * @param {Object} `options` (Optional) Overrides for configuration options + */ + create: function (filePath, contents, options) { + var httpOptions = uploadFileOptions(filePath, contents, options); + + return http.post(httpOptions.data, httpOptions); + }, - return http.put(body, httpOptions); + /** + * Uploads a file to the given path. It will try to create the file and if there's a conflict error (409) it will try to replace the file instead. + * @param {String} `filePath` Path to the file + * @param {String} `contents` Contents to write to file + * @param {Object} `options` (Optional) Overrides for configuration options + */ + upload: function (filePath, contents, options) { + var self = this; + + return this.create(filePath, contents, options) + .then(null, function (xhr) { + if (xhr.status === 409) { + return self.replace(filePath, contents, options); + } + }); }, /** - * Removes the file + * Removes the file. * @param {String} `filePath` Path to the file * @param {Object} `options` (Optional) Overrides for configuration options */ @@ -125,7 +167,7 @@ module.exports = function (config) { }, /** - * Rename the file + * Renames the file. * @param {String} filePath Path to the file * @param {Stirng} newName New name of file * @param {Object} options (Optional) Overrides for configuration options diff --git a/src/service/introspection-api-service.js b/src/service/introspection-api-service.js new file mode 100644 index 00000000..4cc4d208 --- /dev/null +++ b/src/service/introspection-api-service.js @@ -0,0 +1,82 @@ +/** + * + * ## Introspection API Service + * + * The Introspection API Service allows you to view a list of the variables and operations in a model. Used in conjunction with the [Run API Service](../run-api-service/). + * + * var rm = new F.manager.RunManager({ + * run: { + * account: 'acme-simulations', + * project: 'supply-chain-game', + * model: 'supply-chain-model.py' + * } + * }); + * rm.getRun() + * .then(function() { + * var intro = rm.run.introspection(); + * }); + * + */ + +'use strict'; + +var ConfigService = require('./configuration-service'); +var TransportFactory = require('../transport/http-transport-factory'); + +module.exports = function (config) { + var defaults = { + server: { + versionPath: 'v3/' + } + }; + var serviceOptions = $.extend({}, defaults, config); + + var urlConfig = new ConfigService(serviceOptions).get('server'); + if (serviceOptions.account) { + urlConfig.accountPath = serviceOptions.account; + } + if (serviceOptions.project) { + urlConfig.projectPath = serviceOptions.project; + } + + urlConfig.filter = ';'; + + var httpOptions = { + url: urlConfig.getAPIPath('model') + 'publish' + }; + if (serviceOptions.token) { + httpOptions.headers = { + 'Authorization': 'Bearer ' + serviceOptions.token + }; + } + var http = new TransportFactory(httpOptions); + + var publicAPI = { + /** + * Get the available functions and variables. + * + * **Example** + * + * intro.get() + * .then(function(data) { + * // data contains an object with available functions (used with operations API) and available variables (used with variables API) + * console.log(data.functions); + * console.log(data.variables); + * }); + * + * **Parameters** + * @param {String} `runId` (Optional) Overrides the run id used when the service was created + * @param {Object} `options` (Optional) Overrides for configuration options. + */ + get: function (runId, options) { + var httpOptions = $.extend(true, {}, serviceOptions, options); + var params = { + runId: runId || httpOptions.filter, + commandWrapper: { command: { introspect: {} } }, + reanimate: false + }; + return http.post(params, httpOptions); + } + }; + $.extend(this, publicAPI); +}; diff --git a/src/service/run-api-service.js b/src/service/run-api-service.js index f38975bd..52ff90d9 100644 --- a/src/service/run-api-service.js +++ b/src/service/run-api-service.js @@ -54,6 +54,7 @@ var rutil = require('../util/run-util'); var _pick = require('../util/object-util')._pick; var TransportFactory = require('../transport/http-transport-factory'); var VariablesService = require('./variables-api-service'); +var IntrospectionService = require('./introspection-api-service'); var SessionManager = require('../store/session-manager'); module.exports = function (config) { @@ -494,6 +495,11 @@ module.exports = function (config) { runService: this })); return vs; + }, + + introspection: function (config) { + var introspection = new IntrospectionService($.extend(true, {}, serviceOptions, config)); + return introspection; } }; diff --git a/tests/spec/test-admin-file-service.js b/tests/spec/test-admin-file-service.js index 21b53985..dbf7ec75 100644 --- a/tests/spec/test-admin-file-service.js +++ b/tests/spec/test-admin-file-service.js @@ -4,17 +4,30 @@ var FileService = F.service.File; var account = 'forio'; var project = 'js-libs'; + var projectUpload = 'upload'; var baseURL = (new F.service.URL({ accountPath: account, projectPath: project })).getAPIPath('file'); + var uploadBase = (new F.service.URL({ accountPath: account, projectPath: projectUpload })).getAPIPath('file'); describe('File API Adapter', function () { var server; before(function () { server = sinon.fakeServer.create(); - server.respondWith(/(.*)\/file\/(.*)\/(.*)/, function (xhr, id) { + server.respondWith(/(.*)\/file\/forio\/js-libs\/(model|static)\/file/, function (xhr, id) { xhr.respond(200, { 'Content-Type': 'application/json' }, JSON.stringify({ url: xhr.url })); }); + server.respondWith(/(.*)\/file\/forio\/upload\/static/, function (xhr, id) { + if (xhr.requestBody.indexOf('existing.html') > -1 && xhr.method === 'POST') { + return xhr.respond(409, { 'Content-Type': 'application/json' }, JSON.stringify({ url: xhr.url })); + } else if (xhr.requestBody.indexOf('new.html') > -1 && xhr.method === 'PUT') { + return xhr.respond(404, { 'Content-Type': 'application/json' }, JSON.stringify({ url: xhr.url })); + } else if (xhr.requestBody.indexOf('serverError.html') > -1) { + return xhr.respond(500, { 'Content-Type': 'application/json' }, JSON.stringify({ url: xhr.url })); + } + xhr.respond(200, { 'Content-Type': 'application/json' }, JSON.stringify({ url: xhr.url })); + }); + server.autoRespond = true; }); after(function () { @@ -63,5 +76,134 @@ req.url.should.equal(baseURL + 'model/file'); }); }); + + describe('#replaceFile', function () { + it('Should do a PUT', function () { + var fs = new FileService({ account: account, project: projectUpload, folderType: 'static' }); + fs.replace('test.html', ''); + + var req = server.requests.pop(); + req.method.toUpperCase().should.equal('PUT'); + }); + it('Should use the right url', function () { + var fs = new FileService({ account: account, project: projectUpload, folderType: 'static' }); + fs.replace('test.html', ''); + + var req = server.requests.pop(); + req.url.should.equal(uploadBase + 'static/'); + }); + it('Should set the right content', function () { + var content = ''; + var fs = new FileService({ account: account, project: projectUpload, folderType: 'static' }); + fs.replace('test.html', content); + + var req = server.requests.pop(); + req.requestBody.should.include(content); + req.requestBody.should.include('test.html'); + }); + }); + + describe('#create', function () { + it('Should do a POST', function () { + var fs = new FileService({ account: account, project: projectUpload, folderType: 'static' }); + fs.create('test.html', ''); + + var req = server.requests.pop(); + req.method.toUpperCase().should.equal('POST'); + }); + it('Should use the right url', function () { + var fs = new FileService({ account: account, project: projectUpload, folderType: 'static' }); + fs.create('test.html', ''); + + var req = server.requests.pop(); + req.url.should.equal(uploadBase + 'static/'); + }); + it('Should set the right content', function () { + var content = ''; + var fs = new FileService({ account: account, project: projectUpload, folderType: 'static' }); + fs.create('test.html', content); + + var req = server.requests.pop(); + req.requestBody.should.include(content); + req.requestBody.should.include('test.html'); + }); + }); + describe('#upload', function () { + it('Should do a POST only', function () { + var fs = new FileService({ account: account, project: projectUpload, folderType: 'static' }); + fs.upload('new.html', ''); + + var req = server.requests.pop(); + req.method.toUpperCase().should.equal('POST'); + }); + + it('Should do a POST and PUT after it fails', function (done) { + server.requests = []; + var fs = new FileService({ account: account, project: projectUpload, folderType: 'static' }); + fs.upload('existing.html', '').then(function () { + server.requests.should.have.lengthOf(2); + var req = server.requests.pop(); + req.method.toUpperCase().should.equal('PUT'); + req = server.requests.pop(); + req.method.toUpperCase().should.equal('POST'); + done(); + }, function () { + done(new Error('Should not fail')); + }); + }); + + it('Should only do a POST', function (done) { + server.requests = []; + var fs = new FileService({ account: account, project: projectUpload, folderType: 'static' }); + + fs.upload('new.html', '').then(function () { + server.requests.should.have.lengthOf(1); + var req = server.requests.pop(); + req.method.toUpperCase().should.equal('POST'); + done(); + }, function () { + done(new Error('Should not fail')); + }); + }); + }); + describe('#remove', function () { + it('Should do a DELETE', function () { + var fs = new FileService({ account: account, project: projectUpload, folderType: 'static' }); + fs.remove('test.html'); + + var req = server.requests.pop(); + req.method.toUpperCase().should.equal('DELETE'); + }); + it('Should use the right URL', function () { + var fs = new FileService({ account: account, project: projectUpload, folderType: 'static' }); + fs.remove('test.html'); + + var req = server.requests.pop(); + req.url.should.equal(uploadBase + 'static/test.html'); + }); + }); + describe('#rename', function () { + it('Should do a PATCH', function () { + var fs = new FileService({ account: account, project: projectUpload, folderType: 'static' }); + fs.rename('test.html', 'newName.html'); + + var req = server.requests.pop(); + req.method.toUpperCase().should.equal('PATCH'); + }); + it('Should use the right URL', function () { + var fs = new FileService({ account: account, project: projectUpload, folderType: 'static' }); + fs.rename('test.html', 'newName.html'); + + var req = server.requests.pop(); + req.url.should.equal(uploadBase + 'static/test.html'); + }); + it('Should build the right body', function () { + var fs = new FileService({ account: account, project: projectUpload, folderType: 'static' }); + fs.rename('test.html', 'newName.html'); + + var req = server.requests.pop(); + JSON.parse(req.requestBody).should.eql({ name: 'newName.html' }); + }); + }); }); }()); diff --git a/tests/spec/test-auth-manager.js b/tests/spec/test-auth-manager.js index 9fbf5684..c72a9bfa 100644 --- a/tests/spec/test-auth-manager.js +++ b/tests/spec/test-auth-manager.js @@ -102,7 +102,7 @@ am.login({ userName: 'test', password: 'test' }); var req = server.requests.pop(); req.method.toUpperCase().should.equal('POST'); - req.url.should.match(/https:\/\/api\.forio\.com\/authentication\/?/); + req.url.should.match(/https:\/\/api\.forio\.com\/(.*)\/authentication\/?/); }); it ('It should call members API on sucessful login', function (done) {