sugo-actor
Version:
Actor component of SUGOS.
974 lines (795 loc) • 61.9 kB
JavaScript
/**
* @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