UNPKG

sugo-actor

Version:
974 lines (795 loc) 61.9 kB
/** * @class SugoActor * @augments {SugoClient} * @param {string} url - Cloud server url * @param {object} config - Configurations * @param {string} config.key - Key of actor * @param {object} config.auth - Auth object * @param {object.<String, SugoActorModule>} config.modules - Modules to load. * @param {string} config.path - Socket.IO option. */ 'use strict'; var _getIterator = require("@babel/runtime/core-js/get-iterator"); var _defineProperty = require("@babel/runtime/helpers/defineProperty"); var _regeneratorRuntime = require("@babel/runtime/regenerator"); var _typeof = require("@babel/runtime/helpers/typeof"); var _JSON$stringify = require("@babel/runtime/core-js/json/stringify"); var _asyncToGenerator = require("@babel/runtime/helpers/asyncToGenerator"); var _Promise = require("@babel/runtime/core-js/promise"); var _Object$assign = require("@babel/runtime/core-js/object/assign"); var _Object$keys = require("@babel/runtime/core-js/object/keys"); var _Object$getPrototypeOf = require("@babel/runtime/core-js/object/get-prototype-of"); var _classCallCheck = require("@babel/runtime/helpers/classCallCheck"); var _createClass = require("@babel/runtime/helpers/createClass"); var _possibleConstructorReturn = require("@babel/runtime/helpers/possibleConstructorReturn"); var _get = require("@babel/runtime/helpers/get"); var _inherits = require("@babel/runtime/helpers/inherits"); var _assertThisInitialized = require("@babel/runtime/helpers/assertThisInitialized"); var _require = require('sugo-client'), SugoClient = _require.SugoClient; var sgSocketClient = require('sg-socket-client'); var assert = require('assert'); var asleep = require('asleep'); var Module = require('./module'); var sgQueue = require('sg-queue'); var _require2 = require('sg-socket-constants'), ReservedEvents = _require2.ReservedEvents, GreetingEvents = _require2.GreetingEvents, RemoteEvents = _require2.RemoteEvents; var _require3 = require('sugo-constants'), ClientTypes = _require3.ClientTypes, CallerEvents = _require3.CallerEvents, HubNotices = _require3.HubNotices; var CALLER_GONE = HubNotices.CALLER_GONE; var _require4 = require('./validating'), validatePerformConfig = _require4.validatePerformConfig, validateModules = _require4.validateModules; var ERROR = ReservedEvents.ERROR; var HI = GreetingEvents.HI, BYE = GreetingEvents.BYE; var JOIN = RemoteEvents.JOIN, LEAVE = RemoteEvents.LEAVE, SPEC = RemoteEvents.SPEC, DESPEC = RemoteEvents.DESPEC, PERFORM = RemoteEvents.PERFORM, RESULT = RemoteEvents.RESULT, NOTICE = RemoteEvents.NOTICE; var ACTOR = ClientTypes.ACTOR; var _require5 = require('sugo-client-auth'), authorize = _require5.authorize; var _require6 = require('./parsing'), _parseActorUrl = _require6.parseActorUrl; var _require7 = require('./emitting'), messageFormatter = _require7.messageFormatter, ModulePipeEmitter = _require7.ModulePipeEmitter, ActorPipeEmitter = _require7.ActorPipeEmitter; var ok = messageFormatter.ok, ng = messageFormatter.ng; var argx = require('argx'); var _require8 = require('sg-serializer'), parse = _require8.parse, format = _require8.format; var debug = require('debug')('sg:actor'); var _connectQueue = sgQueue(); /** @lends SugoActor */ var SugoActor = /*#__PURE__*/ function (_SugoClient) { _inherits(SugoActor, _SugoClient); function SugoActor(url) { var _this; var config = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; _classCallCheck(this, SugoActor); var args = argx(arguments); url = args.shift('string'); config = args.shift('object') || {}; if (!url) { url = _parseActorUrl(config); } _this = _possibleConstructorReturn(this, (SugoActor.__proto__ || _Object$getPrototypeOf(SugoActor)).call(this)); _this.url = url; _this.socket = null; _this.modulePipes = {}; _this.actorPipe = null; if (config.interfaces) { console.warn('`config.interfaces` is now deprecated. Use `config.modules` instead. '); config.modules = config.interfaces; delete config.interfaces; } var _config = config, key = _config.key, _config$auth = _config.auth, auth = _config$auth === void 0 ? false : _config$auth, _config$multiplex = _config.multiplex, multiplex = _config$multiplex === void 0 ? true : _config$multiplex, _config$reconnection = _config.reconnection, reconnection = _config$reconnection === void 0 ? true : _config$reconnection, _config$path = _config.path, path = _config$path === void 0 ? '/socket.io' : _config$path, _config$modules = _config.modules, modules = _config$modules === void 0 ? {} : _config$modules; { var noModuleFound = _Object$keys(modules).length === 0; if (noModuleFound) { console.warn('[SUGO-Actor] config.modules is empty. You should pass at lease one module'); } } { var modulesError = validateModules(modules); if (modulesError) { throw modulesError; } } _Object$assign(_assertThisInitialized(_this), { key: key, auth: auth, multiplex: multiplex, reconnection: reconnection, path: path }); _this.modules = Module.compose(modules); _this.loadedModules = {}; _this.onError = function (err) { return _this.emitLocally(err) || _Promise.reject(err); }; return _this; } /** * Connect to hub. * By call this, actor share specification of the modules to hub so that callers can access them. * @returns {Promise} */ _createClass(SugoActor, [{ key: "connect", value: function () { var _connect = _asyncToGenerator( /*#__PURE__*/ _regeneratorRuntime.mark(function _callee3() { var _this2 = this; var key, auth, multiplex, reconnection, modules, url, path, doConnect, connectQueue; return _regeneratorRuntime.wrap(function _callee3$(_context3) { while (1) { switch (_context3.prev = _context3.next) { case 0: key = this.key, auth = this.auth, multiplex = this.multiplex, reconnection = this.reconnection, modules = this.modules, url = this.url, path = this.path; assert.ok(key, '[SUGO-Actor] key is missing'); doConnect = /*#__PURE__*/ function () { var _ref = _asyncToGenerator( /*#__PURE__*/ _regeneratorRuntime.mark(function _callee2() { var isBrowser, socket, hi, payload, _arr, _i, name; return _regeneratorRuntime.wrap(function _callee2$(_context2) { while (1) { switch (_context2.prev = _context2.next) { case 0: if (!_this2.socket) { _context2.next = 2; break; } throw new Error('Already connected'); case 2: _context2.next = 4; return asleep(0); case 4: isBrowser = typeof window !== 'undefined'; socket = _this2.socket = sgSocketClient(url, { multiplex: multiplex, reconnection: reconnection, path: path, transports: isBrowser ? ['polling', 'websocket'] : ['websocket'] }); socket.on(ERROR, function (err) { _this2.emitLocally(ERROR, err); }); if (!auth) { _context2.next = 16; break; } _context2.prev = 8; _context2.next = 11; return authorize(socket, auth); case 11: _context2.next = 16; break; case 13: _context2.prev = 13; _context2.t0 = _context2["catch"](8); throw new Error("[SUGO-Actor] Authentication failed: ".concat(_context2.t0.message, " ( url: ").concat(_JSON$stringify(url), ", auth: ").concat(_JSON$stringify(auth), " )")); case 16: _context2.next = 18; return socket.waitToConnect(); case 18: _this2.actorPipe = new ActorPipeEmitter(socket, { key: key }); _this2.actorPipe.open(); _context2.next = 22; return socket.call(HI, { key: key }); case 22: hi = _context2.sent; payload = hi.payload; _this2.key = _this2.key || payload.key; _arr = _Object$keys(modules || {}); _i = 0; case 27: if (!(_i < _arr.length)) { _context2.next = 34; break; } name = _arr[_i]; _context2.next = 31; return _this2.load(name, modules[name]); case 31: _i++; _context2.next = 27; break; case 34: socket.on(JOIN, function (data) { var _ref2 = data || {}, caller = _ref2.caller, messages = _ref2.messages; debug('Caller joined', caller); _this2.emitLocally(CallerEvents.JOIN, { caller: _this2.asCallerInstance(caller), messages: messages }); }); socket.on(LEAVE, function (data) { var caller = data.caller, messages = data.messages; debug('Caller left', caller); _this2.emitLocally(CallerEvents.LEAVE, { caller: _this2.asCallerInstance(caller), messages: messages }); }); socket.on(NOTICE, function (_ref3) { var name = _ref3.name, data = _ref3.data; switch (name) { case CALLER_GONE: { var caller = _this2.asCallerInstance({ key: data.key }); debug('Caller gone', caller); _this2.emitLocally(CallerEvents.LEAVE, { caller: caller }); break; } default: { break; } } }); socket.on(PERFORM, /*#__PURE__*/ function () { var _ref4 = _asyncToGenerator( /*#__PURE__*/ _regeneratorRuntime.mark(function _callee(data) { var _data, _data$meta, meta, pid, callback, types, result, isObject, _ref5, _payload, _types, _meta; return _regeneratorRuntime.wrap(function _callee$(_context) { while (1) { switch (_context.prev = _context.next) { case 0: _data = data, _data$meta = _data.meta, meta = _data$meta === void 0 ? {} : _data$meta, pid = _data.pid; if (pid) { _context.next = 3; break; } throw new Error("[SUGO-Actor] pid not found in PERFORM action. You need to use sugo-hub@6.x or later"); case 3: callback = function callback(data) { return socket.emit(RESULT, _Object$assign(data, { key: key, pid: pid })); }; types = meta.types; if (types) { data = parse(data, types, {}); } _context.prev = 6; _context.next = 9; return _this2.perform(data); case 9: result = _context.sent; isObject = _typeof(result) === 'object' && result !== null; _ref5 = isObject ? format(result) : { payload: result }, _payload = _ref5.payload, _types = _ref5.meta; _meta = { types: _types }; callback(ok(_payload, _meta)); _context.next = 19; break; case 16: _context.prev = 16; _context.t0 = _context["catch"](6); callback(ng(_context.t0)); case 19: case "end": return _context.stop(); } } }, _callee, this, [[6, 16]]); })); return function (_x) { return _ref4.apply(this, arguments); }; }()); case 38: case "end": return _context2.stop(); } } }, _callee2, this, [[8, 13]]); })); return function doConnect() { return _ref.apply(this, arguments); }; }(); connectQueue = SugoActor.connectQueue; return _context3.abrupt("return", connectQueue.push(doConnect)); case 5: case "end": return _context3.stop(); } } }, _callee3, this); })); return function connect() { return _connect.apply(this, arguments); }; }() /** * Disconnect from the hub * @returns {Promise} */ }, { key: "disconnect", value: function () { var _disconnect = _asyncToGenerator( /*#__PURE__*/ _regeneratorRuntime.mark(function _callee4() { var key, actorPipe, modulePipes, loadedModules, socket, _arr2, _i2, name, _arr3, _i3, _name, modulePipe; return _regeneratorRuntime.wrap(function _callee4$(_context4) { while (1) { switch (_context4.prev = _context4.next) { case 0: key = this.key, actorPipe = this.actorPipe, modulePipes = this.modulePipes, loadedModules = this.loadedModules; socket = this.socket; if (socket) { _context4.next = 4; break; } return _context4.abrupt("return"); case 4: _arr2 = _Object$keys(loadedModules || {}); _i2 = 0; case 6: if (!(_i2 < _arr2.length)) { _context4.next = 13; break; } name = _arr2[_i2]; _context4.next = 10; return this.unload(name); case 10: _i2++; _context4.next = 6; break; case 13: _arr3 = _Object$keys(modulePipes); for (_i3 = 0; _i3 < _arr3.length; _i3++) { _name = _arr3[_i3]; modulePipe = modulePipes[_name]; modulePipe.close(); delete modulePipes[_name]; } if (actorPipe) { actorPipe.close(); this.actorPipe = null; } _context4.next = 18; return socket.call(BYE, { key: key }); case 18: socket.off(PERFORM); socket.close(); _context4.next = 22; return socket.waitToDisconnect(); case 22: this.socket = null; case 23: case "end": return _context4.stop(); } } }, _callee4, this); })); return function disconnect() { return _disconnect.apply(this, arguments); }; }() /** * Handle perform event * @param {object} data * @returns {Promise} */ }, { key: "perform", value: function () { var _perform = _asyncToGenerator( /*#__PURE__*/ _regeneratorRuntime.mark(function _callee5(data) { var loadedModules, error, modulesName, method, params, module; return _regeneratorRuntime.wrap(function _callee5$(_context5) { while (1) { switch (_context5.prev = _context5.next) { case 0: loadedModules = this.loadedModules; error = validatePerformConfig(data); if (!error) { _context5.next = 4; break; } throw error; case 4: modulesName = data.module, method = data.method, params = data.params; module = loadedModules[modulesName]; if (module) { _context5.next = 8; break; } throw new Error("[SUGO-Actor] Module not loaded: ".concat(modulesName)); case 8: return _context5.abrupt("return", module.$$invoke(method, params)); case 9: case "end": return _context5.stop(); } } }, _callee5, this); })); return function perform(_x2) { return _perform.apply(this, arguments); }; }() /** * Load a module * @param {string} moduleName - Name of module * @param {Object} module - Module to load * @returns {Promise} */ }, { key: "load", value: function () { var _load = _asyncToGenerator( /*#__PURE__*/ _regeneratorRuntime.mark(function _callee6(moduleName, module) { var isModule, key, socket, $$actor, spec, modulePipe, _arr4, _i4, _key, val, hasEmitter; return _regeneratorRuntime.wrap(function _callee6$(_context6) { while (1) { switch (_context6.prev = _context6.next) { case 0: this.assertConnection(); isModule = Module.isModule(module); if (isModule) { _context6.next = 4; break; } throw new Error("[SUGO-Actor] Failed to load since it is not a module: ".concat(moduleName)); case 4: key = this.key, socket = this.socket; $$actor = module.$$actor; if (!$$actor) { _context6.next = 8; break; } throw new Error("[SUGO-Actor] Module already loaded: \"".concat(moduleName, "\" to actor: ").concat($$actor.key)); case 8: spec = module.$spec; _context6.next = 11; return socket.call(SPEC, { name: moduleName, spec: spec, key: key }); case 11: modulePipe = new ModulePipeEmitter(socket, moduleName, { key: key }); module.$$registerEmitter(modulePipe); module.$$actor = this; modulePipe.open(); this.modulePipes[moduleName] = modulePipe; this.loadedModules[moduleName] = module; // Load sub modules _arr4 = _Object$keys(module); _i4 = 0; case 19: if (!(_i4 < _arr4.length)) { _context6.next = 30; break; } _key = _arr4[_i4]; val = module[_key]; if (!Module.isModule(val)) { _context6.next = 27; break; } hasEmitter = !!val.$emitter; if (hasEmitter) { _context6.next = 27; break; } _context6.next = 27; return this.loadSub(moduleName, _defineProperty({}, _key, val)); case 27: _i4++; _context6.next = 19; break; case 30: case "end": return _context6.stop(); } } }, _callee6, this); })); return function load(_x3, _x4) { return _load.apply(this, arguments); }; }() /** * Load sub modules * @param {string} moduleName * @param {Object} subModules * @returns {Promise} */ }, { key: "loadSub", value: function () { var _loadSub2 = _asyncToGenerator( /*#__PURE__*/ _regeneratorRuntime.mark(function _callee7(moduleName, subModules) { var _arr5, _i5, subModuleName, fullName; return _regeneratorRuntime.wrap(function _callee7$(_context7) { while (1) { switch (_context7.prev = _context7.next) { case 0: this.assertConnection(); subModules = Module.compose(subModules); _arr5 = _Object$keys(subModules); _i5 = 0; case 4: if (!(_i5 < _arr5.length)) { _context7.next = 12; break; } subModuleName = _arr5[_i5]; fullName = [moduleName, subModuleName].join('.'); _context7.next = 9; return this.load(fullName, subModules[subModuleName]); case 9: _i5++; _context7.next = 4; break; case 12: case "end": return _context7.stop(); } } }, _callee7, this); })); return function loadSub(_x5, _x6) { return _loadSub2.apply(this, arguments); }; }() /** * Unload a module * @param {string} moduleName - Name of module * @returns {Promise} */ }, { key: "unload", value: function () { var _unload = _asyncToGenerator( /*#__PURE__*/ _regeneratorRuntime.mark(function _callee8(moduleName) { var key, socket, loadedModules, module, modulePipe; return _regeneratorRuntime.wrap(function _callee8$(_context8) { while (1) { switch (_context8.prev = _context8.next) { case 0: this.assertConnection(); key = this.key, socket = this.socket, loadedModules = this.loadedModules; module = loadedModules[moduleName]; _context8.next = 5; return socket.call(DESPEC, { name: moduleName, key: key }); case 5: modulePipe = this.modulePipes[moduleName]; module.$$unregisterEmitter(modulePipe); delete module.$$actor; modulePipe.close(); delete this.modulePipes[moduleName]; delete this.loadedModules[moduleName]; case 11: case "end": return _context8.stop(); } } }, _callee8, this); })); return function unload(_x7) { return _unload.apply(this, arguments); }; }() /** * Unload sub module * @param {string} moduleName - Name of module * @param {string[]} subModuleNames - Name of sub modules * @returns {*} */ }, { key: "unloadSub", value: function () { var _unloadSub = _asyncToGenerator( /*#__PURE__*/ _regeneratorRuntime.mark(function _callee9(moduleName, subModuleNames) { var _iteratorNormalCompletion, _didIteratorError, _iteratorError, _iterator, _step, _subModuleName; return _regeneratorRuntime.wrap(function _callee9$(_context9) { while (1) { switch (_context9.prev = _context9.next) { case 0: _iteratorNormalCompletion = true; _didIteratorError = false; _iteratorError = undefined; _context9.prev = 3; _iterator = _getIterator(subModuleNames); case 5: if (_iteratorNormalCompletion = (_step = _iterator.next()).done) { _context9.next = 12; break; } _subModuleName = _step.value; _context9.next = 9; return this.unload([moduleName, _subModuleName].join('.')); case 9: _iteratorNormalCompletion = true; _context9.next = 5; break; case 12: _context9.next = 18; break; case 14: _context9.prev = 14; _context9.t0 = _context9["catch"](3); _didIteratorError = true; _iteratorError = _context9.t0; case 18: _context9.prev = 18; _context9.prev = 19; if (!_iteratorNormalCompletion && _iterator.return != null) { _iterator.return(); } case 21: _context9.prev = 21; if (!_didIteratorError) { _context9.next = 24; break; } throw _iteratorError; case 24: return _context9.finish(21); case 25: return _context9.finish(18); case 26: case "end": return _context9.stop(); } } }, _callee9, this, [[3, 14, 18, 26], [19,, 21, 25]]); })); return function unloadSub(_x8, _x9) { return _unloadSub.apply(this, arguments); }; }() }, { key: "emit", value: function emit(event, data) { var options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {}; var _options$local = options.local, local = _options$local === void 0 ? false : _options$local, _options$only = options.only, only = _options$only === void 0 ? null : _options$only; _get(SugoActor.prototype.__proto__ || _Object$getPrototypeOf(SugoActor.prototype), "emit", this).call(this, event, data); if (!local) { this.emitToRemote(event, data, { only: only }); } } }, { key: "emitLocally", value: function emitLocally(event, data) { this.emit(event, data, { local: true }); } }, { key: "emitToRemote", value: function emitToRemote(event, data) { var options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {}; var actorPipe = this.actorPipe; if (actorPipe) { actorPipe.emit(event, data, options); } else { console.warn('[SUGO-Actor] Not connected!'); } } }, { key: "asCallerInstance", value: function asCallerInstance(caller) { var _this3 = this; var only = [caller.key]; var emit = function emit(event, data) { return _this3.emitToRemote(event, data, { only: only }); }; return _Object$assign({}, caller, { emit: emit }); } /** * Assert if the connected to hub * @throws {Error} */ }, { key: "assertConnection", value: function assertConnection() { assert.ok(this.socket, '[SUGO-Actor] Not connected!'); } /** @override */ }, { key: "clientType", get: function get() { return ACTOR; } /** @deprecated */ }], [{ key: "urlFromConfig", value: function urlFromConfig() { console.warn('`SugoActor.urlFromConfig` is now deprecated. Use `SugoActor.parseActorUrl` instead'); return this.parseActorUrl.apply(this, arguments); } /** * Parse actor url */ }, { key: "parseActorUrl", value: function parseActorUrl() { return _parseActorUrl.apply(void 0, arguments); } }, { key: "connectQueue", get: function get() { return _connectQueue; } }]); return SugoActor; }(SugoClient); module.exports = SugoActor; //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbInN1Z29fYWN0b3IuanMiXSwibmFtZXMiOlsicmVxdWlyZSIsIlN1Z29DbGllbnQiLCJzZ1NvY2tldENsaWVudCIsImFzc2VydCIsImFzbGVlcCIsIk1vZHVsZSIsInNnUXVldWUiLCJSZXNlcnZlZEV2ZW50cyIsIkdyZWV0aW5nRXZlbnRzIiwiUmVtb3RlRXZlbnRzIiwiQ2xpZW50VHlwZXMiLCJDYWxsZXJFdmVudHMiLCJIdWJOb3RpY2VzIiwiQ0FMTEVSX0dPTkUiLCJ2YWxpZGF0ZVBlcmZvcm1Db25maWciLCJ2YWxpZGF0ZU1vZHVsZXMiLCJFUlJPUiIsIkhJIiwiQllFIiwiSk9JTiIsIkxFQVZFIiwiU1BFQyIsIkRFU1BFQyIsIlBFUkZPUk0iLCJSRVNVTFQiLCJOT1RJQ0UiLCJBQ1RPUiIsImF1dGhvcml6ZSIsInBhcnNlQWN0b3JVcmwiLCJtZXNzYWdlRm9ybWF0dGVyIiwiTW9kdWxlUGlwZUVtaXR0ZXIiLCJBY3RvclBpcGVFbWl0dGVyIiwib2siLCJuZyIsImFyZ3giLCJwYXJzZSIsImZvcm1hdCIsImRlYnVnIiwiX2Nvbm5lY3RRdWV1ZSIsIlN1Z29BY3RvciIsInVybCIsImNvbmZpZyIsImFyZ3MiLCJhcmd1bWVudHMiLCJzaGlmdCIsInNvY2tldCIsIm1vZHVsZVBpcGVzIiwiYWN0b3JQaXBlIiwiaW50ZXJmYWNlcyIsImNvbnNvbGUiLCJ3YXJuIiwibW9kdWxlcyIsImtleSIsImF1dGgiLCJtdWx0aXBsZXgiLCJyZWNvbm5lY3Rpb24iLCJwYXRoIiwibm9Nb2R1bGVGb3VuZCIsImxlbmd0aCIsIm1vZHVsZXNFcnJvciIsImNvbXBvc2UiLCJsb2FkZWRNb2R1bGVzIiwib25FcnJvciIsImVyciIsImVtaXRMb2NhbGx5IiwicmVqZWN0IiwiZG9Db25uZWN0IiwiRXJyb3IiLCJpc0Jyb3dzZXIiLCJ3aW5kb3ciLCJ0cmFuc3BvcnRzIiwib24iLCJtZXNzYWdlIiwid2FpdFRvQ29ubmVjdCIsIm9wZW4iLCJjYWxsIiwiaGkiLCJwYXlsb2FkIiwibmFtZSIsImxvYWQiLCJkYXRhIiwiY2FsbGVyIiwibWVzc2FnZXMiLCJhc0NhbGxlckluc3RhbmNlIiwibWV0YSIsInBpZCIsImNhbGxiYWNrIiwiZW1pdCIsInR5cGVzIiwicGVyZm9ybSIsInJlc3VsdCIsImlzT2JqZWN0IiwiY29ubmVjdFF1ZXVlIiwicHVzaCIsInVubG9hZCIsIm1vZHVsZVBpcGUiLCJjbG9zZSIsIm9mZiIsIndhaXRUb0Rpc2Nvbm5lY3QiLCJlcnJvciIsIm1vZHVsZXNOYW1lIiwibW9kdWxlIiwibWV0aG9kIiwicGFyYW1zIiwiJCRpbnZva2UiLCJtb2R1bGVOYW1lIiwiYXNzZXJ0Q29ubmVjdGlvbiIsImlzTW9kdWxlIiwiJCRhY3RvciIsInNwZWMiLCIkc3BlYyIsIiQkcmVnaXN0ZXJFbWl0dGVyIiwidmFsIiwiaGFzRW1pdHRlciIsIiRlbWl0dGVyIiwibG9hZFN1YiIsInN1Yk1vZHVsZXMiLCJzdWJNb2R1bGVOYW1lIiwiZnVsbE5hbWUiLCJqb2luIiwiJCR1bnJlZ2lzdGVyRW1pdHRlciIsInN1Yk1vZHVsZU5hbWVzIiwiZXZlbnQiLCJvcHRpb25zIiwibG9jYWwiLCJvbmx5IiwiZW1pdFRvUmVtb3RlIiwiZXhwb3J0cyJdLCJtYXBwaW5ncyI6IkFBQUE7Ozs7Ozs7Ozs7QUFVQTs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztlQUVxQkEsUUFBUSxhQUFSLEM7SUFBZEMsVSxZQUFBQSxVOztBQUNQLElBQU1DLGlCQUFpQkYsUUFBUSxrQkFBUixDQUF2Qjs7QUFDQSxJQUFNRyxTQUFTSCxRQUFRLFFBQVIsQ0FBZjs7QUFDQSxJQUFNSSxTQUFTSixRQUFRLFFBQVIsQ0FBZjs7QUFDQSxJQUFNSyxTQUFTTCxRQUFRLFVBQVIsQ0FBZjs7QUFFQSxJQUFNTSxVQUFVTixRQUFRLFVBQVIsQ0FBaEI7O2dCQUN1REEsUUFBUSxxQkFBUixDO0lBQWhETyxjLGFBQUFBLGM7SUFBZ0JDLGMsYUFBQUEsYztJQUFnQkMsWSxhQUFBQSxZOztnQkFDU1QsUUFBUSxnQkFBUixD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QURrQzs7QUFFdkMsVUFBSUEsU0FBSixFQUFlO0FBQ2JBLGtCQUFVd0MsSUFBVixDQUFlbUMsS0FBZixFQUFzQjFDLElBQXRCLEVBQTRCMkMsT0FBNUI7QUFDRCxPQUZELE1BRU87QUFDTDFFLGdCQUFRQyxJQUFSLENBQWEsNkJBQWI7QUFDRDtBQUNGOzs7cUNBRWlCK0IsTSxFQUFRO0FBQUE7O0FBQ3hCLFVBQU00QyxPQUFPLENBQUM1QyxPQUFPN0IsR0FBUixDQUFiOztBQUNBLFVBQU1tQyxPQUFPLFNBQVBBLElBQU8sQ0FBQ21DLEtBQUQsRUFBUTFDLElBQVI7QUFBQSxlQUFpQixPQUFLOEMsWUFBTCxDQUFrQkosS0FBbEIsRUFBeUIxQyxJQUF6QixFQUErQjtBQUFDNkM7QUFBRCxTQUEvQixDQUFqQjtBQUFBLE9BQWI7O0FBQ0EsYUFBTyxlQUFjLEVBQWQsRUFBa0I1QyxNQUFsQixFQUEwQjtBQUFDTTtBQUFELE9BQTFCLENBQVA7QUFDRDtBQUVEOzs7Ozs7O3VDQUlvQjtBQUNsQnBGLGFBQU82QixFQUFQLENBQVUsS0FBS2EsTUFBZixFQUF1Qiw2QkFBdkI7QUFDRDtBQUVEOzs7O3dCQUNrQjtBQUNoQixhQUFPbkIsS0FBUDtBQUNEO0FBRUQ7Ozs7b0NBQ3dCO0FBQ3RCdUIsY0FBUUMsSUFBUixDQUFhLG9GQUFiO0FBQ0EsYUFBTyxLQUFLdEIsYUFBTCxhQUFzQmUsU0FBdEIsQ0FBUDtBQUNEO0FBRUQ7Ozs7OztvQ0FHd0I7QUFDdEIsYUFBT2YsNkJBQWlCZSxTQUFqQixDQUFQO0FBQ0Q7Ozt3QkFFMEI7QUFDekIsYUFBT0wsYUFBUDtBQUNEOzs7O0VBeldxQnJDLFU7O0FBNFd4Qm9HLE9BQU8wQixPQUFQLEdBQWlCeEYsU0FBakIiLCJmaWxlIjoic3Vnb19hY3Rvci5qcyIsInNvdXJjZVJvb3QiOiIuLi8uLi9saWIiLCJzb3VyY2VzQ29udGVudCI6WyIvKipcbiAqIEBjbGFzcyBTdWdvQWN0b3JcbiAqIEBhdWdtZW50cyB7U3Vnb0NsaWVudH1cbiAqIEBwYXJhbSB7c3RyaW5nfSB1cmwgLSBDbG91ZCBzZXJ2ZXIgdXJsXG4gKiBAcGFyYW0ge29iamVjdH0gY29uZmlnIC0gQ29uZmlndXJhdGlvbnNcbiAqIEBwYXJhbSB7c3RyaW5nfSBjb25maWcua2V5IC0gS2V5IG9mIGFjdG9yXG4gKiBAcGFyYW0ge29iamVjdH0gY29uZmlnLmF1dGggLSBBdXRoIG9iamVjdFxuICogQHBhcmFtIHtvYmplY3QuPFN0cmluZywgU3Vnb0FjdG9yTW9kdWxlPn0gY29uZmlnLm1vZHVsZXMgLSBNb2R1bGVzIHRvIGxvYWQuXG4gKiBAcGFyYW0ge3N0cmluZ30gY29uZmlnLnBhdGggLSBTb2NrZXQuSU8gb3B0aW9uLlxuICovXG4ndXNlIHN0cmljdCdcblxuY29uc3Qge1N1Z29DbGllbnR9ID0gcmVxdWlyZSgnc3Vnby1jbGllbnQnKVxuY29uc3Qgc2dTb2NrZXRDbGllbnQgPSByZXF1aXJlKCdzZy1zb2NrZXQtY2xpZW50JylcbmNvbnN0IGFzc2VydCA9IHJlcXVpcmUoJ2Fzc2VydCcpXG5jb25zdCBhc2xlZXAgPSByZXF1aXJlKCdhc2xlZXAnKVxuY29uc3QgTW9kdWxlID0gcmVxdWlyZSgnLi9tb2R1bGUnKVxuXG5jb25zdCBzZ1F1ZXVlID0gcmVxdWlyZSgnc2ctcXVldWUnKVxuY29uc3Qge1Jlc2VydmVkRXZlbnRzLCBHcmVldGluZ0V2ZW50cywgUmVtb3RlRXZlbnRzfSA9IHJlcXVpcmUoJ3NnLXNvY2tldC1jb25zdGFudHMnKVxuY29uc3Qge0NsaWVudFR5cGVzLCBDYWxsZXJFdmVudHMsIEh1Yk5vdGljZXN9ID0gcmVxdWlyZSgnc3Vnby1jb25zdGFudHMnKVxuY29uc3Qge0NBTExFUl9HT05FfSA9IEh1Yk5vdGljZXNcblxuY29uc3Qge3ZhbGlkYXRlUGVyZm9ybUNvbmZpZywgdmFsaWRhdGVNb2R1bGVzfSA9IHJlcXVpcmUoJy4vdmFsaWRhdGluZycpXG5jb25zdCB7RVJST1J9ID0gUmVzZXJ2ZWRFdmVudHNcbmNvbnN0IHtISSwgQllFfSA9IEdyZWV0aW5nRXZlbnRzXG5jb25zdCB7Sk9JTiwgTEVBVkUsIFNQRUMsIERFU1BFQywgUEVSRk9STSwgUkVTVUxULCBOT1RJQ0V9ID0gUmVtb3RlRXZlbnRzXG5jb25zdCB7QUNUT1J9ID0gQ2xpZW50VHlwZXNcbmNvbnN0IHthdXRob3JpemV9ID0gcmVxdWlyZSgnc3Vnby1jbGllbnQtYXV0aCcpXG5jb25zdCB7cGFyc2VBY3RvclVybH0gPSByZXF1aXJlKCcuL3BhcnNpbmcnKVxuXG5jb25zdCB7bWVzc2FnZUZvcm1hdHRlciwgTW9kdWxlUGlwZUVtaXR0ZXIsIEFjdG9yUGlwZUVtaXR0ZXJ9ID0gcmVxdWlyZSgnLi9lbWl0dGluZycpXG5jb25zdCB7b2ssIG5nfSA9IG1lc3NhZ2VGb3JtYXR0ZXJcbmNvbnN0IGFyZ3ggPSByZXF1aXJlKCdhcmd4JylcbmNvbnN0IHtwYXJzZSwgZm9ybWF0fSA9IHJlcXVpcmUoJ3NnLXNlcmlhbGl6ZXInKVxuY29uc3QgZGVidWcgPSByZXF1aXJlKCdkZWJ1ZycpKCdzZzphY3RvcicpXG5cbmxldCBfY29ubmVjdFF1ZXVlID0gc2dRdWV1ZSgpXG5cbi8qKiBAbGVuZHMgU3Vnb0FjdG9yICovXG5jbGFzcyBTdWdvQWN0b3IgZXh0ZW5kcyBTdWdvQ2xpZW50IHtcbiAgY29uc3RydWN0b3IgKHVybCwgY29uZmlnID0ge30pIHtcbiAgICBsZXQgYXJncyA9IGFyZ3goYXJndW1lbnRzKVxuXG4gICAgdXJsID0gYXJncy5zaGlmdCgnc3RyaW5nJylcbiAgICBjb25maWcgPSBhcmdzLnNoaWZ0KCdvYmplY3QnKSB8fCB7fVxuXG4gICAgaWYgKCF1cmwpIHtcbiAgICAgIHVybCA9IHBhcnNlQWN0b3JVcmwoY29uZmlnKVxuICAgIH1cblxuICAgIHN1cGVyKClcbiAgICB0aGlzLnVybCA9IHVybFxuICAgIHRoaXMuc29ja2V0ID0gbnVsbFxuICAgIHRoaXMubW9kdWxlUGlwZXMgPSB7fVxuICAgIHRoaXMuYWN0b3JQaXBlID0gbnVsbFxuXG4gICAgaWYgKGNvbmZpZy5pbnRlcmZhY2VzKSB7XG4gICAgICBjb25zb2xlLndhcm4oJ2Bjb25maWcuaW50ZXJmYWNlc2AgaXMgbm93IGRlcHJlY2F0ZWQuIFVzZSBgY29uZmlnLm1vZHVsZXNgIGluc3RlYWQuICcpXG4gICAgICBjb25maWcubW9kdWxlcyA9IGNvbmZpZy5pbnRlcmZhY2VzXG4gICAgICBkZWxldGUgY29uZmlnLmludGVyZmFjZXNcbiAgICB9XG5cbiAgICBsZXQge1xuICAgICAga2V5LFxuICAgICAgYXV0aCA9IGZhbHNlLFxuICAgICAgbXVsdGlwbGV4ID0gdHJ1ZSxcbiAgICAgIHJlY29ubmVjdGlvbiA9IHRydWUsXG4gICAgICBwYXRoID0gJy9zb2NrZXQuaW8nLFxuICAgICAgbW9kdWxlcyA9IHt9XG4gICAgfSA9IGNvbmZpZ1xuXG4gICAge1xuICAgICAgbGV0IG5vTW9kdWxlRm91bmQgPSBPYmplY3Qua2V5cyhtb2R1bGVzKS5sZW5ndGggPT09IDBcbiAgICAgIGlmIChub01vZHVsZUZvdW5kKSB7XG4gICAgICAgIGNvbnNvbGUud2FybignW1NVR08tQWN0b3Jd