saij
Version:
A learning engine.
313 lines (254 loc) • 24.8 kB
JavaScript
"use strict";
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = exports.assertConnectable = void 0;
var _Object = _interopRequireDefault(require("../core/Object"));
var _Collection = _interopRequireDefault(require("../core/Collection"));
var _AssertionError = _interopRequireDefault(require("../core/AssertionError"));
var _Errors = _interopRequireDefault(require("../core/Errors"));
var _Observable = require("../core/Observable");
var _ConnectionType = _interopRequireDefault(require("./ConnectionType"));
/**
* @module saij/connection/Connection
*/
/* eslint max-len: 0 */
/**
* A {@link module:saij/connection/Connection~Connection} will be one of the
* {@link module:saij/connection/ConnectionType}s.
* @typedef {module:saij/connection/ConnectionType} ConnectionType
* @property {module:saij/connection/ConnectionType} type
* @api
*/
/**
* Key created when a new {@link module:saij/connection/Connection~Connection}
* is created.
*
* @typedef {Object} ConnectionKey
* @property {string} id
* @property {module:saij/connection/ConnectionType} type
* @api
*/
/**
* Object requirements for use with this connection object. Must contains the
* `getInput` and `getOuput` functions, that must return {@link module:saij/core/Object}.
* @typedef {Object} Connectable
* @property {function} getInput returns {@link module:saij/core/Object~BaseObject}
* @property {function} getOutput returns {@link module:saij/core/Object~BaseObject}
* @api
*/
/**
* Determine if an object is connectable.
* @param {Object} obj object to check if Connectable
* @return {Boolean} true if object is Connectable
* @function
* @api
*/
const assertConnectable = obj => {
if (!obj || typeof obj.getInput !== 'function' || typeof obj.getOutput !== 'function') {
return false;
}
if (!(obj.getInput() instanceof _Object.default)) {
return false;
}
if (!(obj.getOutput() instanceof _Object.default)) {
return false;
}
return true;
};
/**
* @classdesc
* A connection is an abstract base class to build
* {@link module:saij/connection/ConnectionType}s from.
*
* A Connection will connect the inputs and outputs of two connectable
* objects together. For an object to be connectable it must have `getInput`
* and `getOutput` functions that return a {@link module:saij/core/Object}. A
* connection will set listeners on the inputs and output that match up,
* and forward them on to each other.
*
* @api
*/
exports.assertConnectable = assertConnectable;
class Connection extends _Object.default {
/**
* @param {module:saij/connection/Connection~ConnectionKey} connectionKey connection key
* @param {module:saij/connection/Connection~Connectable} source forward connectable object
* @param {module:saij/connection/Connection~Connectable} destination reverse connectable object
*/
// eslint-disable-next-line max-statements
constructor(connectionKey, source, destination) {
super();
if (!assertConnectable(source) || !assertConnectable(destination)) {
throw new _AssertionError.default(_Errors.default.ASSERT_CONNECTABLE.code);
}
/**
* @private
* @type {module:saij/connection/Connection~ConnectionKey}
*/
this.key_ = null;
/**
* @private
* @type {module:saij/connection/Connection~ConnectionType}
*/
this.type_ = null;
this.setKey(connectionKey);
/**
* @private
* @type {module:saij/core/Collection~Collection.<module:saij/connection/Connection~Connectable>}
*/
this.connectables_ = new _Collection.default([source, destination]);
/**
* @private
* @type {module:saij/connection/Connection~Connectable}
*/
this.source_ = source;
/**
* @private
* @type {module:saij/connection/Connection~Connectable}
*/
this.destination_ = destination;
/**
* @private
* @type {module:saij/core/Collection~Collection.<module:saij/core/utils/events~EventsKey>}
*/
this.listeners_ = new _Collection.default();
/**
* @private
* @type {Boolean}
*/
this.hasConnection_ = false; // Initialise the connection
this.connect();
}
/**
* Connect the outputs of connectable A to the inputs of
* connectable B
* @param {module:saij/connection/Connection~Connectable} conA connectable A
* @param {module:saij/connection/Connection~Connectable} conB connectable B
* @private
*/
connectOutAtoInB_(conA, conB) {
// Get the input and output data objects
const outputA = conA.getOutput();
const inputB = conB.getInput();
for (const keyA of Reflect.ownKeys(outputA.getProperties())) {
for (const keyB of Reflect.ownKeys(inputB.getProperties())) {
if (keyA === keyB) {
// Connect outputs of A to inputs of B
this.listeners_.push(outputA.on(`change:${keyA}`, () => {
inputB.set(keyA, outputA.get(keyA));
}));
}
}
}
}
/**
* Check the connection is setup.
* @return {Boolean} true if connected
* @api
*/
isConnected() {
return this.hasConnection_;
}
/**
* Check the connection has listeners.
* @return {Boolean} true if has listeners
* @api
*/
isListening() {
return this.listeners_.getArray().length > 0;
}
/**
* Connect source to destination in the way described by the type.
* @return {module:saij/core/Collection~Collection.<module:saij/core/utils/events~EventsKey>} listeners
* @api
*/
connect() {
if (!this.hasConnection_) {
switch (this.type_) {
case _ConnectionType.default.SIMPLEX:
{
this.connectOutAtoInB_(this.source_, this.destination_);
this.hasConnection_ = true;
return this.listeners_;
}
case _ConnectionType.default.DUPLEX:
{
this.connectOutAtoInB_(this.source_, this.destination_);
this.connectOutAtoInB_(this.destination_, this.source_);
this.hasConnection_ = true;
return this.listeners_;
}
default:
{
throw new _AssertionError.default(_Errors.default.ASSERT_CONNECTION_TYPE.code);
}
}
}
}
/**
* Disconnect the connection and clear it's listeners.
* @return {Boolean} true if disconnected
* @api
*/
disconnect() {
(0, _Observable.unByKey)(this.listeners_.getArray());
this.listeners_.clear();
this.hasConnection_ = false;
return true;
}
/**
* Set the connection key. It is advised to use a
* {@link module:saij/connection/Connection~ConnectionKey} with a unique id,
* unless you wish to group connections. Changing the key type will trigger
* a reconnection to occur.
* @param {module:saij/connection/Connection~ConnectionKey} key connection key
* @return {Boolean} true if set the key
* @api
*/
// eslint-disable-next-line max-statements
setKey(key) {
if (!key) {
throw new _AssertionError.default(_Errors.default.ASSERT_CONNECTION_KEY.code);
}
const id = key.id;
const type = key.type;
if (typeof id === 'string' && typeof type === 'string') {
// Create new key object in case original object is corrupted
this.key_ = { ...key
};
if (this.hasConnection_ && type !== this.type_) {
this.disconnect();
this.type_ = type;
this.connect();
return true;
}
this.type_ = type;
return true;
} // A connection key id must be defined and a string
if (typeof id !== 'string') {
throw new _AssertionError.default(_Errors.default.ASSERT_CONNECTION_ID.code);
} // A connection key type must be defined and a string
throw new _AssertionError.default(_Errors.default.ASSERT_CONNECTION_TYPE.code);
}
/**
* Get the connection key.
* @return {module:saij/connection/Connection~ConnectionKey} connection key
* @api
*/
getKey() {
return this.key_;
}
/**
* Get the listeners keys for all the input/output listeners on the connection.
* @return {module:saij/core/Collection<module:saij/core/utils/events~EventsKey>} connection key
* @api
*/
getListeners() {
return this.listeners_;
}
}
var _default = Connection;
exports.default = _default;
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy9zYWlqL2Nvbm5lY3Rpb24vQ29ubmVjdGlvbi5qcyJdLCJuYW1lcyI6WyJhc3NlcnRDb25uZWN0YWJsZSIsIm9iaiIsImdldElucHV0IiwiZ2V0T3V0cHV0IiwiQmFzZU9iamVjdCIsIkNvbm5lY3Rpb24iLCJjb25zdHJ1Y3RvciIsImNvbm5lY3Rpb25LZXkiLCJzb3VyY2UiLCJkZXN0aW5hdGlvbiIsIkFzc2VydGlvbkVycm9yIiwiRXJyb3JzIiwiQVNTRVJUX0NPTk5FQ1RBQkxFIiwiY29kZSIsImtleV8iLCJ0eXBlXyIsInNldEtleSIsImNvbm5lY3RhYmxlc18iLCJDb2xsZWN0aW9uIiwic291cmNlXyIsImRlc3RpbmF0aW9uXyIsImxpc3RlbmVyc18iLCJoYXNDb25uZWN0aW9uXyIsImNvbm5lY3QiLCJjb25uZWN0T3V0QXRvSW5CXyIsImNvbkEiLCJjb25CIiwib3V0cHV0QSIsImlucHV0QiIsImtleUEiLCJSZWZsZWN0Iiwib3duS2V5cyIsImdldFByb3BlcnRpZXMiLCJrZXlCIiwicHVzaCIsIm9uIiwic2V0IiwiZ2V0IiwiaXNDb25uZWN0ZWQiLCJpc0xpc3RlbmluZyIsImdldEFycmF5IiwibGVuZ3RoIiwiQ29ubmVjdGlvblR5cGUiLCJTSU1QTEVYIiwiRFVQTEVYIiwiQVNTRVJUX0NPTk5FQ1RJT05fVFlQRSIsImRpc2Nvbm5lY3QiLCJjbGVhciIsImtleSIsIkFTU0VSVF9DT05ORUNUSU9OX0tFWSIsImlkIiwidHlwZSIsIkFTU0VSVF9DT05ORUNUSU9OX0lEIiwiZ2V0S2V5IiwiZ2V0TGlzdGVuZXJzIl0sIm1hcHBpbmdzIjoiOzs7Ozs7Ozs7QUFJQTs7QUFDQTs7QUFDQTs7QUFDQTs7QUFDQTs7QUFDQTs7QUFUQTs7OztBQVlBOztBQUdBOzs7Ozs7OztBQVFBOzs7Ozs7Ozs7O0FBVUE7Ozs7Ozs7OztBQVVBOzs7Ozs7O0FBT08sTUFBTUEsaUJBQWlCLEdBQUlDLEdBQUQsSUFBUTtBQUN2QyxNQUNFLENBQUNBLEdB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Wjs7QUFFQSxVQUFJLEtBQUsxQixjQUFMLElBQXVCNkIsSUFBSSxLQUFLLEtBQUtwQyxLQUF6QyxFQUFnRDtBQUM5QyxhQUFLK0IsVUFBTDtBQUNBLGFBQUsvQixLQUFMLEdBQWFvQyxJQUFiO0FBQ0EsYUFBSzVCLE9BQUw7QUFDQSxlQUFPLElBQVA7QUFDRDs7QUFFRCxXQUFLUixLQUFMLEdBQWFvQyxJQUFiO0FBQ0EsYUFBTyxJQUFQO0FBQ0QsS0FyQlMsQ0FzQlY7OztBQUNBLFFBQUksT0FBT0QsRUFBUCxLQUFjLFFBQWxCLEVBQTRCO0FBQzFCLFlBQU0sSUFBSXhDLHVCQUFKLENBQW1CQyxnQkFBT3lDLG9CQUFQLENBQTRCdkMsSUFBL0MsQ0FBTjtBQUNELEtBekJTLENBMEJWOzs7QUFDQSxVQUFNLElBQUlILHVCQUFKLENBQW1CQyxnQkFBT2tDLHNCQUFQLENBQThCaEMsSUFBakQsQ0FBTjtBQUNEO0FBRUQ7Ozs7Ozs7QUFLQXdDLEVBQUFBLE1BQU0sR0FBRztBQUNQLFdBQU8sS0FBS3ZDLElBQVo7QUFDRDtBQUVEOzs7Ozs7O0FBS0F3QyxFQUFBQSxZQUFZLEdBQUc7QUFDYixXQUFPLEtBQUtqQyxVQUFaO0FBQ0Q7O0FBck1pQzs7ZUF3TXJCaEIsVSIsInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogQG1vZHVsZSBzYWlqL2Nvbm5lY3Rpb24vQ29ubmVjdGlvblxuICovXG5cbmltcG9ydCBCYXNlT2JqZWN0IGZyb20gJy4uL2NvcmUvT2JqZWN0JztcbmltcG9ydCBDb2xsZWN0aW9uIGZyb20gJy4uL2NvcmUvQ29sbGVjdGlvbic7XG5pbXBvcnQgQXNzZXJ0aW9uRXJyb3IgZnJvbSAnLi4vY29yZS9Bc3NlcnRpb25FcnJvcic7XG5pbXBvcnQgRXJyb3JzIGZyb20gJy4uL2NvcmUvRXJyb3JzJztcbmltcG9ydCB7dW5CeUtleX0gZnJvbSAnLi4vY29yZS9PYnNlcnZhYmxlJztcbmltcG9ydCBDb25uZWN0aW9uVHlwZSBmcm9tICcuL0Nvbm5lY3Rpb25UeXBlJztcblxuXG4vKiBlc2xpbnQgbWF4LWxlbjogMCAqL1xuXG5cbi8qKlxuICogQSB7QGxpbmsgbW9kdWxlOnNhaWovY29ubmVjdGlvbi9Db25uZWN0aW9ufkNvbm5lY3Rpb259IHdpbGwgYmUgb25lIG9mIHRoZVxuICoge0BsaW5rIG1vZHVsZTpzYWlqL2Nvbm5lY3Rpb24vQ29ubmVjdGlvblR5cGV9cy5cbiAqIEB0eXBlZGVmIHttb2R1bGU6c2Fpai9jb25uZWN0aW9uL0Nvbm5lY3Rpb25UeXBlfSBDb25uZWN0aW9uVHlwZVxuICogQHByb3BlcnR5IHttb2R1bGU6c2Fpai9jb25uZWN0aW9uL0Nvbm5lY3Rpb25UeXBlfSB0eXBlXG4gKiBAYXBpXG4gKi9cblxuLyoqXG4gKiBLZXkgY3JlYXRlZCB3aGVuIGEgbmV3IHtAbGluayBtb2R1bGU6c2Fpai9jb25uZWN0aW9uL0Nvbm5lY3Rpb25+Q29ubmVjdGlvbn1cbiAqIGlzIGNyZWF0ZWQuXG4gKlxuICogQHR5cGVkZWYge09iamVjdH0gQ29ubmVjdGlvbktleVxuICogQHByb3BlcnR5IHtzdHJpbmd9IGlkXG4gKiBAcHJvcGVydHkge21vZHVsZTpzYWlqL2Nvbm5lY3Rpb24vQ29ubmVjdGlvblR5cGV9IHR5cGVcbiAqIEBhcGlcbiAqL1xuXG4vKipcbiAqIE9iamVjdCByZXF1aXJlbWVudHMgZm9yIHVzZSB3aXRoIHRoaXMgY29ubmVjdGlvbiBvYmplY3QuIE11c3QgY29udGFpbnMgdGhlXG4gKiBgZ2V0SW5wdXRgIGFuZCBgZ2V0T3VwdXRgIGZ1bmN0aW9ucywgdGhhdCBtdXN0IHJldHVybiB7QGxpbmsgbW9kdWxlOnNhaWovY29yZS9PYmplY3R9LlxuICogQHR5cGVkZWYge09iamVjdH0gQ29ubmVjdGFibGVcbiAqIEBwcm9wZXJ0eSB7ZnVuY3Rpb259IGdldElucHV0IHJldHVybnMge0BsaW5rIG1vZHVsZTpzYWlqL2NvcmUvT2JqZWN0fkJhc2VPYmplY3R9XG4gKiBAcHJvcGVydHkge2Z1bmN0aW9ufSBnZXRPdXRwdXQgcmV0dXJucyB7QGxpbmsgbW9kdWxlOnNhaWovY29yZS9PYmplY3R+QmFzZU9iamVjdH1cbiAqIEBhcGlcbiovXG5cblxuLyoqXG4gKiBEZXRlcm1pbmUgaWYgYW4gb2JqZWN0IGlzIGNvbm5lY3RhYmxlLlxuICogQHBhcmFtICB7T2JqZWN0fSBvYmogb2JqZWN0IHRvIGNoZWNrIGlmIENvbm5lY3RhYmxlXG4gKiBAcmV0dXJuIHtCb29sZWFufSB0cnVlIGlmIG9iamVjdCBpcyBDb25uZWN0YWJsZVxuICogQGZ1bmN0aW9uXG4gKiBAYXBpXG4gKi9cbmV4cG9ydCBjb25zdCBhc3NlcnRDb25uZWN0YWJsZSA9IChvYmopPT4ge1xuICBpZiAoXG4gICAgIW9ialxuICAgIHx8IHR5cGVvZiBvYmouZ2V0SW5wdXQgIT09ICdmdW5jdGlvbidcbiAgICB8fCB0eXBlb2Ygb2JqLmdldE91dHB1dCAhPT0gJ2Z1bmN0aW9uJ1xuICApIHtcbiAgICByZXR1cm4gZmFsc2U7XG4gIH1cblxuICBpZiAoIShvYmouZ2V0SW5wdXQoKSBpbnN0YW5jZW9mIEJhc2VPYmplY3QpKSB7XG4gICAgcmV0dXJuIGZhbHNlO1xuICB9XG5cbiAgaWYgKCEob2JqLmdldE91dHB1dCgpIGluc3RhbmNlb2YgQmFzZU9iamVjdCkpIHtcbiAgICByZXR1cm4gZmFsc2U7XG4gIH1cblxuICByZXR1cm4gdHJ1ZTtcbn07XG5cblxuLyoqXG4gKiBAY2xhc3NkZXNjXG4gKiBBIGNvbm5lY3Rpb24gaXMgYW4gYWJzdHJhY3QgYmFzZSBjbGFzcyB0byBidWlsZFxuICoge0BsaW5rIG1vZHVsZTpzYWlqL2Nvbm5lY3Rpb24vQ29ubmVjdGlvblR5cGV9cyBmcm9tLlxuICpcbiAqIEEgQ29ubmVjdGlvbiB3aWxsIGNvbm5lY3QgdGhlIGlucHV0cyBhbmQgb3V0cHV0cyBvZiB0d28gY29ubmVjdGFibGVcbiAqIG9iamVjdHMgdG9nZXRoZXIuICBGb3IgYW4gb2JqZWN0IHRvIGJlIGNvbm5lY3RhYmxlIGl0IG11c3QgaGF2ZSBgZ2V0SW5wdXRgXG4gKiBhbmQgYGdldE91dHB1dGAgZnVuY3Rpb25zIHRoYXQgcmV0dXJuIGEge0BsaW5rIG1vZHVsZTpzYWlqL2NvcmUvT2JqZWN0fS4gQVxuICogY29ubmVjdGlvbiB3aWxsIHNldCBsaXN0ZW5lcnMgb24gdGhlIGlucHV0cyBhbmQgb3V0cHV0IHRoYXQgbWF0Y2ggdXAsXG4gKiBhbmQgZm9yd2FyZCB0aGVtIG9uIHRvIGVhY2ggb3RoZXIuXG4gKlxuICogQGFwaVxuICovXG5jbGFzcyBDb25uZWN0aW9uIGV4dGVuZHMgQmFzZU9iamVjdCB7XG4gIC8qKlxuICAgKiBAcGFyYW0gIHttb2R1bGU6c2Fpai9jb25uZWN0aW9uL0Nvbm5lY3Rpb25+Q29ubmVjdGlvbktleX0gY29ubmVjdGlvbktleSBjb25uZWN0aW9uIGtleVxuICAgKiBAcGFyYW0gIHttb2R1bGU6c2Fpai9jb25uZWN0aW9uL0Nvbm5lY3Rpb25+Q29ubmVjdGFibGV9IHNvdXJjZSBmb3J3YXJkIGNvbm5lY3RhYmxlIG9iamVjdFxuICAgKiBAcGFyYW0gIHttb2R1bGU6c2Fpai9jb25uZWN0aW9uL0Nvbm5lY3Rpb25+Q29ubmVjdGFibGV9IGRlc3RpbmF0aW9uIHJldmVyc2UgY29ubmVjdGFibGUgb2JqZWN0XG4gICAqL1xuICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgbWF4LXN0YXRlbWVudHNcbiAgY29uc3RydWN0b3IoY29ubmVjdGlvbktleSwgc291cmNlLCBkZXN0aW5hdGlvbikge1xuICAgIHN1cGVyKCk7XG5cbiAgICBpZiAoIWFzc2VydENvbm5lY3RhYmxlKHNvdXJjZSkgfHwgIWFzc2VydENvbm5lY3RhYmxlKGRlc3RpbmF0aW9uKSkge1xuICAgICAgdGhyb3cgbmV3IEFzc2VydGlvbkVycm9yKEVycm9ycy5BU1NFUlRfQ09OTkVDVEFCTEUuY29kZSk7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogQHByaXZhdGVcbiAgICAgKiBAdHlwZSB7bW9kdWxlOnNhaWovY29ubmVjdGlvbi9Db25uZWN0aW9ufkNvbm5lY3Rpb25LZXl9XG4gICAgICovXG4gICAgdGhpcy5rZXlfID0gbnVsbDtcbiAgICAvKipcbiAgICAgKiBAcHJpdmF0ZVxuICAgICAqIEB0eXBlIHttb2R1bGU6c2Fpai9jb25uZWN0aW9uL0Nvbm5lY3Rpb25+Q29ubmVjdGlvblR5cGV9XG4gICAgICovXG4gICAgdGhpcy50eXBlXyA9IG51bGw7XG5cbiAgICB0aGlzLnNldEtleShjb25uZWN0aW9uS2V5KTtcblxuICAgIC8qKlxuICAgICAqIEBwcml2YXRlXG4gICAgICogQHR5cGUge21vZHVsZTpzYWlqL2NvcmUvQ29sbGVjdGlvbn5Db2xsZWN0aW9uLjxtb2R1bGU6c2Fpai9jb25uZWN0aW9uL0Nvbm5lY3Rpb25+Q29ubmVjdGFibGU+fVxuICAgICAqL1xuICAgIHRoaXMuY29ubmVjdGFibGVzXyA9IG5ldyBDb2xsZWN0aW9uKFtzb3VyY2UsIGRlc3RpbmF0aW9uXSk7XG4gICAgLyoqXG4gICAgICogQHByaXZhdGVcbiAgICAgKiBAdHlwZSB7bW9kdWxlOnNhaWovY29ubmVjdGlvbi9Db25uZWN0aW9ufkNvbm5lY3RhYmxlfVxuICAgICAqL1xuICAgIHRoaXMuc291cmNlXyA9IHNvdXJjZTtcbiAgICAvKipcbiAgICAgKiBAcHJpdmF0ZVxuICAgICAqIEB0eXBlIHttb2R1bGU6c2Fpai9jb25uZWN0aW9uL0Nvbm5lY3Rpb25+Q29ubmVjdGFibGV9XG4gICAgICovXG4gICAgdGhpcy5kZXN0aW5hdGlvbl8gPSBkZXN0aW5hdGlvbjtcblxuICAgIC8qKlxuICAgICAqIEBwcml2YXRlXG4gICAgICogQHR5cGUge21vZHVsZTpzYWlqL2NvcmUvQ29sbGVjdGlvbn5Db2xsZWN0aW9uLjxtb2R1bGU6c2Fpai9jb3JlL3V0aWxzL2V2ZW50c35FdmVudHNLZXk+fVxuICAgICAqL1xuICAgIHRoaXMubGlzdGVuZXJzXyA9IG5ldyBDb2xsZWN0aW9uKCk7XG5cbiAgICAvKipcbiAgICAgKiBAcHJpdmF0ZVxuICAgICAqIEB0eXBlIHtCb29sZWFufVxuICAgICAqL1xuICAgIHRoaXMuaGFzQ29ubmVjdGlvbl8gPSBmYWxzZTtcblxuICAgIC8vIEluaXRpYWxpc2UgdGhlIGNvbm5lY3Rpb25cbiAgICB0aGlzLmNvbm5lY3QoKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBDb25uZWN0IHRoZSBvdXRwdXRzIG9mIGNvbm5lY3RhYmxlIEEgdG8gdGhlIGlucHV0cyBvZlxuICAgKiBjb25uZWN0YWJsZSBCXG4gICAqIEBwYXJhbSB7bW9kdWxlOnNhaWovY29ubmVjdGlvbi9Db25uZWN0aW9ufkNvbm5lY3RhYmxlfSBjb25BIGNvbm5lY3RhYmxlIEFcbiAgICogQHBhcmFtIHttb2R1bGU6c2Fpai9jb25uZWN0aW9uL0Nvbm5lY3Rpb25+Q29ubmVjdGFibGV9IGNvbkIgY29ubmVjdGFibGUgQlxuICAgKiBAcHJpdmF0ZVxuICAgKi9cbiAgY29ubmVjdE91dEF0b0luQl8oY29uQSwgY29uQikge1xuICAgIC8vIEdldCB0aGUgaW5wdXQgYW5kIG91dHB1dCBkYXRhIG9iamVjdHNcbiAgICBjb25zdCBvdXRwdXRBID0gY29uQS5nZXRPdXRwdXQoKTtcbiAgICBjb25zdCBpbnB1dEIgPSBjb25CLmdldElucHV0KCk7XG5cbiAgICBmb3IgKGNvbnN0IGtleUEgb2YgUmVmbGVjdC5vd25LZXlzKG91dHB1dEEuZ2V0UHJvcGVydGllcygpKSkge1xuICAgICAgZm9yIChjb25zdCBrZXlCIG9mIFJlZmxlY3Qub3duS2V5cyhpbnB1dEIuZ2V0UHJvcGVydGllcygpKSkge1xuICAgICAgICBpZiAoa2V5QSA9PT0ga2V5Qikge1xuICAgICAgICAgIC8vIENvbm5lY3Qgb3V0cHV0cyBvZiBBIHRvIGlucHV0cyBvZiBCXG4gICAgICAgICAgdGhpcy5saXN0ZW5lcnNfLnB1c2goXG4gICAgICAgICAgICBvdXRwdXRBLm9uKGBjaGFuZ2U6JHtrZXlBfWAsICgpPT4ge1xuICAgICAgICAgICAgICBpbnB1dEIuc2V0KGtleUEsIG91dHB1dEEuZ2V0KGtleUEpKTtcbiAgICAgICAgICAgIH0pXG4gICAgICAgICAgKTtcbiAgICAgICAgfVxuICAgICAgfVxuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBDaGVjayB0aGUgY29ubmVjdGlvbiBpcyBzZXR1cC5cbiAgICogQHJldHVybiB7Qm9vbGVhbn0gdHJ1ZSBpZiBjb25uZWN0ZWRcbiAgICogQGFwaVxuICAgKi9cbiAgaXNDb25uZWN0ZWQoKSB7XG4gICAgcmV0dXJuIHRoaXMuaGFzQ29ubmVjdGlvbl87XG4gIH1cblxuICAvKipcbiAgICogQ2hlY2sgdGhlIGNvbm5lY3Rpb24gaGFzIGxpc3RlbmVycy5cbiAgICogQHJldHVybiB7Qm9vbGVhbn0gdHJ1ZSBpZiBoYXMgbGlzdGVuZXJzXG4gICAqIEBhcGlcbiAgICovXG4gIGlzTGlzdGVuaW5nKCkge1xuICAgIHJldHVybiB0aGlzLmxpc3RlbmVyc18uZ2V0QXJyYXkoKS5sZW5ndGggPiAwO1xuICB9XG5cbiAgLyoqXG4gICAqIENvbm5lY3Qgc291cmNlIHRvIGRlc3RpbmF0aW9uIGluIHRoZSB3YXkgZGVzY3JpYmVkIGJ5IHRoZSB0eXBlLlxuICAgKiBAcmV0dXJuIHttb2R1bGU6c2Fpai9jb3JlL0NvbGxlY3Rpb25+Q29sbGVjdGlvbi48bW9kdWxlOnNhaWovY29yZS91dGlscy9ldmVudHN+RXZlbnRzS2V5Pn0gbGlzdGVuZXJzXG4gICAqIEBhcGlcbiAgICovXG4gIGNvbm5lY3QoKSB7XG4gICAgaWYgKCF0aGlzLmhhc0Nvbm5lY3Rpb25fKSB7XG4gICAgICBzd2l0Y2ggKHRoaXMudHlwZV8pIHtcbiAgICAgICAgY2FzZSBDb25uZWN0aW9uVHlwZS5TSU1QTEVYOiB7XG4gICAgICAgICAgdGhpcy5jb25uZWN0T3V0QXRvSW5CXyh0aGlzLnNvdXJjZV8sIHRoaXMuZGVzdGluYXRpb25fKTtcbiAgICAgICAgICB0aGlzLmhhc0Nvbm5lY3Rpb25fID0gdHJ1ZTtcbiAgICAgICAgICByZXR1cm4gdGhpcy5saXN0ZW5lcnNfO1xuICAgICAgICB9XG4gICAgICAgIGNhc2UgQ29ubmVjdGlvblR5cGUuRFVQTEVYOiB7XG4gICAgICAgICAgdGhpcy5jb25uZWN0T3V0QXRvSW5CXyh0aGlzLnNvdXJjZV8sIHRoaXMuZGVzdGluYXRpb25fKTtcbiAgICAgICAgICB0aGlzLmNvbm5lY3RPdXRBdG9JbkJfKHRoaXMuZGVzdGluYXRpb25fLCB0aGlzLnNvdXJjZV8pO1xuICAgICAgICAgIHRoaXMuaGFzQ29ubmVjdGlvbl8gPSB0cnVlO1xuICAgICAgICAgIHJldHVybiB0aGlzLmxpc3RlbmVyc187XG4gICAgICAgIH1cbiAgICAgICAgZGVmYXVsdDoge1xuICAgICAgICAgIHRocm93IG5ldyBBc3NlcnRpb25FcnJvcihFcnJvcnMuQVNTRVJUX0NPTk5FQ1RJT05fVFlQRS5jb2RlKTtcbiAgICAgICAgfVxuICAgICAgfVxuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBEaXNjb25uZWN0IHRoZSBjb25uZWN0aW9uIGFuZCBjbGVhciBpdCdzIGxpc3RlbmVycy5cbiAgICogQHJldHVybiB7Qm9vbGVhbn0gdHJ1ZSBpZiBkaXNjb25uZWN0ZWRcbiAgICogQGFwaVxuICAgKi9cbiAgZGlzY29ubmVjdCgpIHtcbiAgICB1bkJ5S2V5KHRoaXMubGlzdGVuZXJzXy5nZXRBcnJheSgpKTtcbiAgICB0aGlzLmxpc3RlbmVyc18uY2xlYXIoKTtcbiAgICB0aGlzLmhhc0Nvbm5lY3Rpb25fID0gZmFsc2U7XG4gICAgcmV0dXJuIHRydWU7XG4gIH1cblxuICAvKipcbiAgICogU2V0IHRoZSBjb25uZWN0aW9uIGtleS4gSXQgaXMgYWR2aXNlZCB0byB1c2UgYVxuICAgKiB7QGxpbmsgbW9kdWxlOnNhaWovY29ubmVjdGlvbi9Db25uZWN0aW9ufkNvbm5lY3Rpb25LZXl9IHdpdGggYSB1bmlxdWUgaWQsXG4gICAqIHVubGVzcyB5b3Ugd2lzaCB0byBncm91cCBjb25uZWN0aW9ucy4gIENoYW5naW5nIHRoZSBrZXkgdHlwZSB3aWxsIHRyaWdnZXJcbiAgICogYSByZWNvbm5lY3Rpb24gdG8gb2NjdXIuXG4gICAqIEBwYXJhbSB7bW9kdWxlOnNhaWovY29ubmVjdGlvbi9Db25uZWN0aW9ufkNvbm5lY3Rpb25LZXl9IGtleSBjb25uZWN0aW9uIGtleVxuICAgKiBAcmV0dXJuIHtCb29sZWFufSB0cnVlIGlmIHNldCB0aGUga2V5XG4gICAqIEBhcGlcbiAgICovXG4gIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBtYXgtc3RhdGVtZW50c1xuICBzZXRLZXkoa2V5KSB7XG4gICAgaWYgKCFrZXkpIHtcbiAgICAgIHRocm93IG5ldyBBc3NlcnRpb25FcnJvcihFcnJvcnMuQVNTRVJUX0NPTk5FQ1RJT05fS0VZLmNvZGUpO1xuICAgIH1cblxuICAgIGNvbnN0IGlkID0ga2V5LmlkO1xuICAgIGNvbnN0IHR5cGUgPSBrZXkudHlwZTtcblxuICAgIGlmICh0eXBlb2YgaWQgPT09ICdzdHJpbmcnICYmIHR5cGVvZiB0eXBlID09PSAnc3RyaW5nJykge1xuICAgICAgLy8gQ3JlYXRlIG5ldyBrZXkgb2JqZWN0IGluIGNhc2Ugb3JpZ2luYWwgb2JqZWN0IGlzIGNvcnJ1cHRlZFxuICAgICAgdGhpcy5rZXlfID0gey4uLmtleX07XG5cbiAgICAgIGlmICh0aGlzLmhhc0Nvbm5lY3Rpb25fICYmIHR5cGUgIT09IHRoaXMudHlwZV8pIHtcbiAgICAgICAgdGhpcy5kaXNjb25uZWN0KCk7XG4gICAgICAgIHRoaXMudHlwZV8gPSB0eXBlO1xuICAgICAgICB0aGlzLmNvbm5lY3QoKTtcbiAgICAgICAgcmV0dXJuIHRydWU7XG4gICAgICB9XG5cbiAgICAgIHRoaXMudHlwZV8gPSB0eXBlO1xuICAgICAgcmV0dXJuIHRydWU7XG4gICAgfVxuICAgIC8vIEEgY29ubmVjdGlvbiBrZXkgaWQgbXVzdCBiZSBkZWZpbmVkIGFuZCBhIHN0cmluZ1xuICAgIGlmICh0eXBlb2YgaWQgIT09ICdzdHJpbmcnKSB7XG4gICAgICB0aHJvdyBuZXcgQXNzZXJ0aW9uRXJyb3IoRXJyb3JzLkFTU0VSVF9DT05ORUNUSU9OX0lELmNvZGUpO1xuICAgIH1cbiAgICAvLyBBIGNvbm5lY3Rpb24ga2V5IHR5cGUgbXVzdCBiZSBkZWZpbmVkIGFuZCBhIHN0cmluZ1xuICAgIHRocm93IG5ldyBBc3NlcnRpb25FcnJvcihFcnJvcnMuQVNTRVJUX0NPTk5FQ1RJT05fVFlQRS5jb2RlKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBHZXQgdGhlIGNvbm5lY3Rpb24ga2V5LlxuICAgKiBAcmV0dXJuIHttb2R1bGU6c2Fpai9jb25uZWN0aW9uL0Nvbm5lY3Rpb25+Q29ubmVjdGlvbktleX0gY29ubmVjdGlvbiBrZXlcbiAgICogQGFwaVxuICAgKi9cbiAgZ2V0S2V5KCkge1xuICAgIHJldHVybiB0aGlzLmtleV87XG4gIH1cblxuICAvKipcbiAgICogR2V0IHRoZSBsaXN0ZW5lcnMga2V5cyBmb3IgYWxsIHRoZSBpbnB1dC9vdXRwdXQgbGlzdGVuZXJzIG9uIHRoZSBjb25uZWN0aW9uLlxuICAgKiBAcmV0dXJuIHttb2R1bGU6c2Fpai9jb3JlL0NvbGxlY3Rpb248bW9kdWxlOnNhaWovY29yZS91dGlscy9ldmVudHN+RXZlbnRzS2V5Pn0gY29ubmVjdGlvbiBrZXlcbiAgICogQGFwaVxuICAgKi9cbiAgZ2V0TGlzdGVuZXJzKCkge1xuICAgIHJldHVybiB0aGlzLmxpc3RlbmVyc187XG4gIH1cbn1cblxuZXhwb3J0IGRlZmF1bHQgQ29ubmVjdGlvbjtcbiJdfQ==