UNPKG

loopback-softdelete-mixin4

Version:

A mixin to provide soft deletes by adding a deletedAt attribute for loopback Models

226 lines (172 loc) 27.2 kB
'use strict'; Object.defineProperty(exports, "__esModule", { value: true }); var _promise = require('babel-runtime/core-js/promise'); var _promise2 = _interopRequireDefault(_promise); var _defineProperty2 = require('babel-runtime/helpers/defineProperty'); var _defineProperty3 = _interopRequireDefault(_defineProperty2); var _extends8 = require('babel-runtime/helpers/extends'); var _extends9 = _interopRequireDefault(_extends8); var _keys = require('babel-runtime/core-js/object/keys'); var _keys2 = _interopRequireDefault(_keys); var _debug2 = require('./debug'); var _debug3 = _interopRequireDefault(_debug2); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } var crypto = require('crypto'); var debug = (0, _debug3.default)(); exports.default = function (Model, _ref) { var _ref$deletedAt = _ref.deletedAt, deletedAt = _ref$deletedAt === undefined ? 'deletedAt' : _ref$deletedAt, _ref$scrub = _ref.scrub, scrub = _ref$scrub === undefined ? false : _ref$scrub, _ref$index = _ref.index, index = _ref$index === undefined ? false : _ref$index, _ref$deletedById = _ref.deletedById, deletedById = _ref$deletedById === undefined ? false : _ref$deletedById, _ref$deleteOp = _ref.deleteOp, deleteOp = _ref$deleteOp === undefined ? false : _ref$deleteOp; debug('SoftDelete mixin for Model %s', Model.modelName); debug('options', { deletedAt: deletedAt, scrub: scrub, index: index }); var properties = Model.definition.properties; var idName = Model.dataSource.idName(Model.modelName); var scrubbed = {}; if (scrub !== false) { var propertiesToScrub = scrub; if (!Array.isArray(propertiesToScrub)) { propertiesToScrub = (0, _keys2.default)(properties).filter(function (prop) { return !properties[prop][idName] && prop !== deletedAt; }); } scrubbed = propertiesToScrub.reduce(function (obj, prop) { return (0, _extends9.default)({}, obj, (0, _defineProperty3.default)({}, prop, null)); }, {}); } Model.defineProperty(deletedAt, { type: Date, required: false, default: null }); if (index) Model.defineProperty('deleteIndex', { type: String, required: true, default: 'null' }); if (deletedById) Model.defineProperty('deletedById', { type: Number, required: false, default: null }); if (deleteOp) Model.defineProperty('deleteOp', { type: String, required: false, default: null }); Model.destroyAll = function softDestroyAll(where, cb) { var _extends3; var deletePromise = index ? Model.updateAll(where, (0, _extends9.default)({}, scrubbed, (_extends3 = {}, (0, _defineProperty3.default)(_extends3, deletedAt, new Date()), (0, _defineProperty3.default)(_extends3, 'deleteIndex', genKey()), _extends3))) : Model.updateAll(where, (0, _extends9.default)({}, scrubbed, (0, _defineProperty3.default)({}, deletedAt, new Date()))); return deletePromise.then(function (result) { return typeof cb === 'function' ? cb(null, result) : result; }).catch(function (error) { return typeof cb === 'function' ? cb(error) : _promise2.default.reject(error); }); }; Model.remove = Model.destroyAll; Model.deleteAll = Model.destroyAll; Model.destroyById = function softDestroyById(id, cb) { var _extends5; var deletePromise = index ? Model.updateAll((0, _defineProperty3.default)({}, idName, id), (0, _extends9.default)({}, scrubbed, (_extends5 = {}, (0, _defineProperty3.default)(_extends5, deletedAt, new Date()), (0, _defineProperty3.default)(_extends5, 'deleteIndex', genKey()), _extends5))) : Model.updateAll((0, _defineProperty3.default)({}, idName, id), (0, _extends9.default)({}, scrubbed, (0, _defineProperty3.default)({}, deletedAt, new Date()))); return deletePromise.then(function (result) { return typeof cb === 'function' ? cb(null, result) : result; }).catch(function (error) { return typeof cb === 'function' ? cb(error) : _promise2.default.reject(error); }); }; Model.removeById = Model.destroyById; Model.deleteById = Model.destroyById; Model.prototype.destroy = function softDestroy(options, cb) { var callback = cb === undefined && typeof options === 'function' ? options : cb; var data = (0, _extends9.default)({}, scrubbed, (0, _defineProperty3.default)({}, deletedAt, new Date())); options = options || {}; options.delete = true; if (index) data.deleteIndex = genKey(); if (deletedById && options.deletedById) data.deletedById = options.deletedById; if (deleteOp && options.deleteOp) data.deleteOp = options.deleteOp; return this.updateAttributes(data, options).then(function (result) { return typeof cb === 'function' ? callback(null, result) : result; }).catch(function (error) { return typeof cb === 'function' ? callback(error) : _promise2.default.reject(error); }); }; Model.prototype.remove = Model.prototype.destroy; Model.prototype.delete = Model.prototype.destroy; // Emulate default scope but with more flexibility. var queryNonDeleted = (0, _defineProperty3.default)({}, deletedAt, null); var _findOrCreate = Model.findOrCreate; Model.findOrCreate = function findOrCreateDeleted() { var query = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; if (!query.deleted) { if (!query.where || (0, _keys2.default)(query.where).length === 0) { query.where = queryNonDeleted; } else { query.where = { and: [query.where, queryNonDeleted] }; } } for (var _len = arguments.length, rest = Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) { rest[_key - 1] = arguments[_key]; } return _findOrCreate.call.apply(_findOrCreate, [Model, query].concat(rest)); }; var _find = Model.find; Model.find = function findDeleted() { var query = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; if (!query.deleted) { if (!query.where || (0, _keys2.default)(query.where).length === 0) { query.where = queryNonDeleted; } else { query.where = { and: [query.where, queryNonDeleted] }; } } for (var _len2 = arguments.length, rest = Array(_len2 > 1 ? _len2 - 1 : 0), _key2 = 1; _key2 < _len2; _key2++) { rest[_key2 - 1] = arguments[_key2]; } return _find.call.apply(_find, [Model, query].concat(rest)); }; var _count = Model.count; Model.count = function countDeleted() { var where = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; // Because count only receives a 'where', there's nowhere to ask for the deleted entities. var whereNotDeleted = void 0; if (!where || (0, _keys2.default)(where).length === 0) { whereNotDeleted = queryNonDeleted; } else { whereNotDeleted = { and: [where, queryNonDeleted] }; } for (var _len3 = arguments.length, rest = Array(_len3 > 1 ? _len3 - 1 : 0), _key3 = 1; _key3 < _len3; _key3++) { rest[_key3 - 1] = arguments[_key3]; } return _count.call.apply(_count, [Model, whereNotDeleted].concat(rest)); }; var _update = Model.update; Model.update = Model.updateAll = function updateDeleted() { var where = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; // Because update/updateAll only receives a 'where', there's nowhere to ask for the deleted entities. var whereNotDeleted = void 0; if (!where || (0, _keys2.default)(where).length === 0) { whereNotDeleted = queryNonDeleted; } else { whereNotDeleted = { and: [where, queryNonDeleted] }; } for (var _len4 = arguments.length, rest = Array(_len4 > 1 ? _len4 - 1 : 0), _key4 = 1; _key4 < _len4; _key4++) { rest[_key4 - 1] = arguments[_key4]; } return _update.call.apply(_update, [Model, whereNotDeleted].concat(rest)); }; if (Model.settings.remoting && Model.settings.remoting.sharedMethods.deleteById !== false && (deletedById || deleteOp)) { Model.disableRemoteMethodByName('deleteById'); Model.remoteMethod('deleteById', { accessType: 'WRITE', isStatic: false, accepts: [{ arg: 'options', type: 'object', http: 'optionsFromRequest' }], returns: { arg: 'data', type: 'object', root: true }, http: { verb: 'delete', path: '/' } }); Model.prototype.deleteById = function () { var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; if (deletedById) options.deletedById = options.accessToken ? options.accessToken.userId : null; if (deleteOp && options.deletedById) options.deleteOp = 'user'; return this.destroy(options).then(function () { return { count: 1 }; }); }; } }; var genKey = function genKey() { return crypto.createHmac('sha256', Math.random().toString(12).substr(2)).digest('hex').substr(0, 8); }; module.exports = exports['default']; //# sourceMappingURL=data:application/json;charset=utf8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbInNvZnQtZGVsZXRlLmpzIl0sIm5hbWVzIjpbImNyeXB0byIsInJlcXVpcmUiLCJkZWJ1ZyIsIk1vZGVsIiwiZGVsZXRlZEF0Iiwic2NydWIiLCJpbmRleCIsImRlbGV0ZWRCeUlkIiwiZGVsZXRlT3AiLCJtb2RlbE5hbWUiLCJwcm9wZXJ0aWVzIiwiZGVmaW5pdGlvbiIsImlkTmFtZSIsImRhdGFTb3VyY2UiLCJzY3J1YmJlZCIsInByb3BlcnRpZXNUb1NjcnViIiwiQXJyYXkiLCJpc0FycmF5IiwiZmlsdGVyIiwicHJvcCIsInJlZHVjZSIsIm9iaiIsImRlZmluZVByb3BlcnR5IiwidHlwZSIsIkRhdGUiLCJyZXF1aXJlZCIsImRlZmF1bHQiLCJTdHJpbmciLCJOdW1iZXIiLCJkZXN0cm95QWxsIiwic29mdERlc3Ryb3lBbGwiLCJ3aGVyZSIsImNiIiwiZGVsZXRlUHJvbWlzZSIsInVwZGF0ZUFsbCIsImdlbktleSIsInRoZW4iLCJyZXN1bHQiLCJjYXRjaCIsImVycm9yIiwicmVqZWN0IiwicmVtb3ZlIiwiZGVsZXRlQWxsIiwiZGVzdHJveUJ5SWQiLCJzb2Z0RGVzdHJveUJ5SWQiLCJpZCIsInJlbW92ZUJ5SWQiLCJkZWxldGVCeUlkIiwicHJvdG90eXBlIiwiZGVzdHJveSIsInNvZnREZXN0cm95Iiwib3B0aW9ucyIsImNhbGxiYWNrIiwidW5kZWZpbmVkIiwiZGF0YSIsImRlbGV0ZSIsImRlbGV0ZUluZGV4IiwidXBkYXRlQXR0cmlidXRlcyIsInF1ZXJ5Tm9uRGVsZXRlZCIsIl9maW5kT3JDcmVhdGUiLCJmaW5kT3JDcmVhdGUiLCJmaW5kT3JDcmVhdGVEZWxldGVkIiwicXVlcnkiLCJkZWxldGVkIiwibGVuZ3RoIiwiYW5kIiwicmVzdCIsImNhbGwiLCJfZmluZCIsImZpbmQiLCJmaW5kRGVsZXRlZCIsIl9jb3VudCIsImNvdW50IiwiY291bnREZWxldGVkIiwid2hlcmVOb3REZWxldGVkIiwiX3VwZGF0ZSIsInVwZGF0ZSIsInVwZGF0ZURlbGV0ZWQiLCJzZXR0aW5ncyIsInJlbW90aW5nIiwic2hhcmVkTWV0aG9kcyIsImRpc2FibGVSZW1vdGVNZXRob2RCeU5hbWUiLCJyZW1vdGVNZXRob2QiLCJhY2Nlc3NUeXBlIiwiaXNTdGF0aWMiLCJhY2NlcHRzIiwiYXJnIiwiaHR0cCIsInJldHVybnMiLCJyb290IiwidmVyYiIsInBhdGgiLCJhY2Nlc3NUb2tlbiIsInVzZXJJZCIsImNyZWF0ZUhtYWMiLCJNYXRoIiwicmFuZG9tIiwidG9TdHJpbmciLCJzdWJzdHIiLCJkaWdlc3QiXSwibWFwcGluZ3MiOiI7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7QUFFQTs7Ozs7O0FBRkEsSUFBSUEsU0FBU0MsUUFBUSxRQUFSLENBQWI7O0FBR0EsSUFBTUMsUUFBUSxzQkFBZDs7a0JBRWUsVUFBQ0MsS0FBRCxRQUE2RztBQUFBLDRCQUFuR0MsU0FBbUc7QUFBQSxNQUFuR0EsU0FBbUcsa0NBQXZGLFdBQXVGO0FBQUEsd0JBQTFFQyxLQUEwRTtBQUFBLE1BQTFFQSxLQUEwRSw4QkFBbEUsS0FBa0U7QUFBQSx3QkFBMURDLEtBQTBEO0FBQUEsTUFBMURBLEtBQTBELDhCQUFsRCxLQUFrRDtBQUFBLDhCQUEzQ0MsV0FBMkM7QUFBQSxNQUEzQ0EsV0FBMkMsb0NBQTdCLEtBQTZCO0FBQUEsMkJBQXRCQyxRQUFzQjtBQUFBLE1BQXRCQSxRQUFzQixpQ0FBWCxLQUFXOztBQUMxSE4sUUFBTSwrQkFBTixFQUF1Q0MsTUFBTU0sU0FBN0M7O0FBRUFQLFFBQU0sU0FBTixFQUFpQixFQUFFRSxvQkFBRixFQUFhQyxZQUFiLEVBQW9CQyxZQUFwQixFQUFqQjs7QUFFQSxNQUFNSSxhQUFhUCxNQUFNUSxVQUFOLENBQWlCRCxVQUFwQztBQUNBLE1BQU1FLFNBQVNULE1BQU1VLFVBQU4sQ0FBaUJELE1BQWpCLENBQXdCVCxNQUFNTSxTQUE5QixDQUFmOztBQUVBLE1BQUlLLFdBQVcsRUFBZjtBQUNBLE1BQUlULFVBQVUsS0FBZCxFQUFxQjtBQUNuQixRQUFJVSxvQkFBb0JWLEtBQXhC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Q2pCLFVBQUlyRixZQUFZMkMsUUFBUTVDLFdBQXhCLEVBQXFDNEMsUUFBUTNDLFFBQVIsR0FBbUIsTUFBbkI7QUFDckMsYUFBTyxLQUFLeUMsT0FBTCxDQUFhRSxPQUFiLEVBQXNCZixJQUF0QixDQUEyQixZQUFXO0FBQzNDLGVBQU8sRUFBRW9DLE9BQU8sQ0FBVCxFQUFQO0FBQ0QsT0FGTSxDQUFQO0FBR0QsS0FORDtBQU9EO0FBQ0YsQzs7QUFFRCxJQUFJckMsU0FBUyxTQUFUQSxNQUFTLEdBQVc7QUFDdEIsU0FBT25DLE9BQU84RixVQUFQLENBQWtCLFFBQWxCLEVBQTRCQyxLQUFLQyxNQUFMLEdBQWNDLFFBQWQsQ0FBdUIsRUFBdkIsRUFBMkJDLE1BQTNCLENBQWtDLENBQWxDLENBQTVCLEVBQWtFQyxNQUFsRSxDQUF5RSxLQUF6RSxFQUFnRkQsTUFBaEYsQ0FBdUYsQ0FBdkYsRUFBMEYsQ0FBMUYsQ0FBUDtBQUNELENBRkQiLCJmaWxlIjoic29mdC1kZWxldGUuanMiLCJzb3VyY2VzQ29udGVudCI6WyJ2YXIgY3J5cHRvID0gcmVxdWlyZSgnY3J5cHRvJyk7XG5cbmltcG9ydCBfZGVidWcgZnJvbSAnLi9kZWJ1Zyc7XG5jb25zdCBkZWJ1ZyA9IF9kZWJ1ZygpO1xuXG5leHBvcnQgZGVmYXVsdCAoTW9kZWwsIHsgZGVsZXRlZEF0ID0gJ2RlbGV0ZWRBdCcsIHNjcnViID0gZmFsc2UgLCBpbmRleCA9IGZhbHNlLCBkZWxldGVkQnlJZCA9IGZhbHNlLCBkZWxldGVPcCA9IGZhbHNlfSkgPT4ge1xuICBkZWJ1ZygnU29mdERlbGV0ZSBtaXhpbiBmb3IgTW9kZWwgJXMnLCBNb2RlbC5tb2RlbE5hbWUpO1xuXG4gIGRlYnVnKCdvcHRpb25zJywgeyBkZWxldGVkQXQsIHNjcnViLCBpbmRleCB9KTtcblxuICBjb25zdCBwcm9wZXJ0aWVzID0gTW9kZWwuZGVmaW5pdGlvbi5wcm9wZXJ0aWVzO1xuICBjb25zdCBpZE5hbWUgPSBNb2RlbC5kYXRhU291cmNlLmlkTmFtZShNb2RlbC5tb2RlbE5hbWUpO1xuXG4gIGxldCBzY3J1YmJlZCA9IHt9O1xuICBpZiAoc2NydWIgIT09IGZhbHNlKSB7XG4gICAgbGV0IHByb3BlcnRpZXNUb1NjcnViID0gc2NydWI7XG4gICAgaWYgKCFBcnJheS5pc0FycmF5KHByb3BlcnRpZXNUb1NjcnViKSkge1xuICAgICAgcHJvcGVydGllc1RvU2NydWIgPSBPYmplY3Qua2V5cyhwcm9wZXJ0aWVzKVxuICAgICAgICAuZmlsdGVyKHByb3AgPT4gIXByb3BlcnRpZXNbcHJvcF1baWROYW1lXSAmJiBwcm9wICE9PSBkZWxldGVkQXQpO1xuICAgIH1cbiAgICBzY3J1YmJlZCA9IHByb3BlcnRpZXNUb1NjcnViLnJlZHVjZSgob2JqLCBwcm9wKSA9PiAoeyAuLi5vYmosIFtwcm9wXTogbnVsbCB9KSwge30pO1xuICB9XG5cbiAgTW9kZWwuZGVmaW5lUHJvcGVydHkoZGVsZXRlZEF0LCB7dHlwZTogRGF0ZSwgcmVxdWlyZWQ6IGZhbHNlLCBkZWZhdWx0OiBudWxsfSk7XG4gIGlmIChpbmRleCkgTW9kZWwuZGVmaW5lUHJvcGVydHkoJ2RlbGV0ZUluZGV4JywgeyB0eXBlOiBTdHJpbmcsIHJlcXVpcmVkOiB0cnVlLCBkZWZhdWx0OiAnbnVsbCcgfSk7XG4gIGlmIChkZWxldGVkQnlJZCkgTW9kZWwuZGVmaW5lUHJvcGVydHkoJ2RlbGV0ZWRCeUlkJywgeyB0eXBlOiBOdW1iZXIsIHJlcXVpcmVkOiBmYWxzZSwgZGVmYXVsdDogbnVsbCB9KTtcbiAgaWYgKGRlbGV0ZU9wKSBNb2RlbC5kZWZpbmVQcm9wZXJ0eSgnZGVsZXRlT3AnLCB7IHR5cGU6IFN0cmluZywgcmVxdWlyZWQ6IGZhbHNlLCBkZWZhdWx0OiBudWxsIH0pO1xuXG4gIE1vZGVsLmRlc3Ryb3lBbGwgPSBmdW5jdGlvbiBzb2Z0RGVzdHJveUFsbCh3aGVyZSwgY2IpIHtcbiAgICB2YXIgZGVsZXRlUHJvbWlzZSA9IGluZGV4ID8gTW9kZWwudXBkYXRlQWxsKHdoZXJlLCB7IC4uLnNjcnViYmVkLCBbZGVsZXRlZEF0XTogbmV3IERhdGUoKSwgZGVsZXRlSW5kZXg6IGdlbktleSgpIH0pIDpcbiAgICAgIE1vZGVsLnVwZGF0ZUFsbCh3aGVyZSwgeyAuLi5zY3J1YmJlZCwgW2RlbGV0ZWRBdF06IG5ldyBEYXRlKCkgfSlcbiAgICBcbiAgICByZXR1cm4gZGVsZXRlUHJvbWlzZVxuICAgICAgLnRoZW4ocmVzdWx0ID0+ICh0eXBlb2YgY2IgPT09ICdmdW5jdGlvbicpID8gY2IobnVsbCwgcmVzdWx0KSA6IHJlc3VsdClcbiAgICAgIC5jYXRjaChlcnJvciA9PiAodHlwZW9mIGNiID09PSAnZnVuY3Rpb24nKSA/IGNiKGVycm9yKSA6IFByb21pc2UucmVqZWN0KGVycm9yKSk7XG4gIH07XG5cbiAgTW9kZWwucmVtb3ZlID0gTW9kZWwuZGVzdHJveUFsbDtcbiAgTW9kZWwuZGVsZXRlQWxsID0gTW9kZWwuZGVzdHJveUFsbDtcblxuICBNb2RlbC5kZXN0cm95QnlJZCA9IGZ1bmN0aW9uIHNvZnREZXN0cm95QnlJZChpZCwgY2IpIHtcbiAgICB2YXIgZGVsZXRlUHJvbWlzZSA9IGluZGV4ID8gTW9kZWwudXBkYXRlQWxsKHsgW2lkTmFtZV06IGlkIH0sIHsgLi4uc2NydWJiZWQsIFtkZWxldGVkQXRdOiBuZXcgRGF0ZSgpLCBkZWxldGVJbmRleDogZ2VuS2V5KCkgfSkgOlxuICAgICAgTW9kZWwudXBkYXRlQWxsKHsgW2lkTmFtZV06IGlkIH0sIHsgLi4uc2NydWJiZWQsIFtkZWxldGVkQXRdOiBuZXcgRGF0ZSgpIH0pO1xuXG4gICAgcmV0dXJuIGRlbGV0ZVByb21pc2VcbiAgICAgIC50aGVuKHJlc3VsdCA9PiAodHlwZW9mIGNiID09PSAnZnVuY3Rpb24nKSA/IGNiKG51bGwsIHJlc3VsdCkgOiByZXN1bHQpXG4gICAgICAuY2F0Y2goZXJyb3IgPT4gKHR5cGVvZiBjYiA9PT0gJ2Z1bmN0aW9uJykgPyBjYihlcnJvcikgOiBQcm9taXNlLnJlamVjdChlcnJvcikpO1xuICB9O1xuXG4gIE1vZGVsLnJlbW92ZUJ5SWQgPSBNb2RlbC5kZXN0cm95QnlJZDtcbiAgTW9kZWwuZGVsZXRlQnlJZCA9IE1vZGVsLmRlc3Ryb3lCeUlkO1xuXG4gIE1vZGVsLnByb3RvdHlwZS5kZXN0cm95ID0gZnVuY3Rpb24gc29mdERlc3Ryb3kob3B0aW9ucywgY2IpIHtcbiAgICBjb25zdCBjYWxsYmFjayA9IChjYiA9PT0gdW5kZWZpbmVkICYmIHR5cGVvZiBvcHRpb25zID09PSAnZnVuY3Rpb24nKSA/IG9wdGlvbnMgOiBjYjtcbiAgICBsZXQgZGF0YSA9IHtcbiAgICAgIC4uLnNjcnViYmVkLCBcbiAgICAgIFtkZWxldGVkQXRdOiBuZXcgRGF0ZSgpXG4gICAgfTtcbiAgICBvcHRpb25zID0gb3B0aW9ucyB8fCB7fTtcbiAgICBvcHRpb25zLmRlbGV0ZSA9IHRydWU7XG4gICAgaWYgKGluZGV4KSBkYXRhLmRlbGV0ZUluZGV4ID0gZ2VuS2V5KCk7XG4gICAgaWYgKGRlbGV0ZWRCeUlkICYmIG9wdGlvbnMuZGVsZXRlZEJ5SWQpIGRhdGEuZGVsZXRlZEJ5SWQgPSBvcHRpb25zLmRlbGV0ZWRCeUlkO1xuICAgIGlmIChkZWxldGVPcCAmJiBvcHRpb25zLmRlbGV0ZU9wKSBkYXRhLmRlbGV0ZU9wID0gb3B0aW9ucy5kZWxldGVPcDtcbiAgICBcbiAgICByZXR1cm4gdGhpcy51cGRhdGVBdHRyaWJ1dGVzKGRhdGEsIG9wdGlvbnMpXG4gICAgICAudGhlbihyZXN1bHQgPT4gKHR5cGVvZiBjYiA9PT0gJ2Z1bmN0aW9uJykgPyBjYWxsYmFjayhudWxsLCByZXN1bHQpIDogcmVzdWx0KVxuICAgICAgLmNhdGNoKGVycm9yID0+ICh0eXBlb2YgY2IgPT09ICdmdW5jdGlvbicpID8gY2FsbGJhY2soZXJyb3IpIDogUHJvbWlzZS5yZWplY3QoZXJyb3IpKTtcbiAgfTtcblxuICBNb2RlbC5wcm90b3R5cGUucmVtb3ZlID0gTW9kZWwucHJvdG90eXBlLmRlc3Ryb3k7XG4gIE1vZGVsLnByb3RvdHlwZS5kZWxldGUgPSBNb2RlbC5wcm90b3R5cGUuZGVzdHJveTtcblxuICAvLyBFbXVsYXRlIGRlZmF1bHQgc2NvcGUgYnV0IHdpdGggbW9yZSBmbGV4aWJpbGl0eS5cbiAgY29uc3QgcXVlcnlOb25EZWxldGVkID0ge1tkZWxldGVkQXRdOiBudWxsfTtcblxuICBjb25zdCBfZmluZE9yQ3JlYXRlID0gTW9kZWwuZmluZE9yQ3JlYXRlO1xuICBNb2RlbC5maW5kT3JDcmVhdGUgPSBmdW5jdGlvbiBmaW5kT3JDcmVhdGVEZWxldGVkKHF1ZXJ5ID0ge30sIC4uLnJlc3QpIHtcbiAgICBpZiAoIXF1ZXJ5LmRlbGV0ZWQpIHtcbiAgICAgIGlmICghcXVlcnkud2hlcmUgfHwgT2JqZWN0LmtleXMocXVlcnkud2hlcmUpLmxlbmd0aCA9PT0gMCkge1xuICAgICAgICBxdWVyeS53aGVyZSA9IHF1ZXJ5Tm9uRGVsZXRlZDtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIHF1ZXJ5LndoZXJlID0geyBhbmQ6IFsgcXVlcnkud2hlcmUsIHF1ZXJ5Tm9uRGVsZXRlZCBdIH07XG4gICAgICB9XG4gICAgfVxuXG4gICAgcmV0dXJuIF9maW5kT3JDcmVhdGUuY2FsbChNb2RlbCwgcXVlcnksIC4uLnJlc3QpO1xuICB9O1xuXG4gIGNvbnN0IF9maW5kID0gTW9kZWwuZmluZDtcbiAgTW9kZWwuZmluZCA9IGZ1bmN0aW9uIGZpbmREZWxldGVkKHF1ZXJ5ID0ge30sIC4uLnJlc3QpIHtcbiAgICBpZiAoIXF1ZXJ5LmRlbGV0ZWQpIHtcbiAgICAgIGlmICghcXVlcnkud2hlcmUgfHwgT2JqZWN0LmtleXMocXVlcnkud2hlcmUpLmxlbmd0aCA9PT0gMCkge1xuICAgICAgICBxdWVyeS53aGVyZSA9IHF1ZXJ5Tm9uRGVsZXRlZDtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIHF1ZXJ5LndoZXJlID0geyBhbmQ6IFsgcXVlcnkud2hlcmUsIHF1ZXJ5Tm9uRGVsZXRlZCBdIH07XG4gICAgICB9XG4gICAgfVxuXG4gICAgcmV0dXJuIF9maW5kLmNhbGwoTW9kZWwsIHF1ZXJ5LCAuLi5yZXN0KTtcbiAgfTtcblxuICBjb25zdCBfY291bnQgPSBNb2RlbC5jb3VudDtcbiAgTW9kZWwuY291bnQgPSBmdW5jdGlvbiBjb3VudERlbGV0ZWQod2hlcmUgPSB7fSwgLi4ucmVzdCkge1xuICAgIC8vIEJlY2F1c2UgY291bnQgb25seSByZWNlaXZlcyBhICd3aGVyZScsIHRoZXJlJ3Mgbm93aGVyZSB0byBhc2sgZm9yIHRoZSBkZWxldGVkIGVudGl0aWVzLlxuICAgIGxldCB3aGVyZU5vdERlbGV0ZWQ7XG4gICAgaWYgKCF3aGVyZSB8fCBPYmplY3Qua2V5cyh3aGVyZSkubGVuZ3RoID09PSAwKSB7XG4gICAgICB3aGVyZU5vdERlbGV0ZWQgPSBxdWVyeU5vbkRlbGV0ZWQ7XG4gICAgfSBlbHNlIHtcbiAgICAgIHdoZXJlTm90RGVsZXRlZCA9IHsgYW5kOiBbIHdoZXJlLCBxdWVyeU5vbkRlbGV0ZWQgXSB9O1xuICAgIH1cbiAgICByZXR1cm4gX2NvdW50LmNhbGwoTW9kZWwsIHdoZXJlTm90RGVsZXRlZCwgLi4ucmVzdCk7XG4gIH07XG5cbiAgY29uc3QgX3VwZGF0ZSA9IE1vZGVsLnVwZGF0ZTtcbiAgTW9kZWwudXBkYXRlID0gTW9kZWwudXBkYXRlQWxsID0gZnVuY3Rpb24gdXBkYXRlRGVsZXRlZCh3aGVyZSA9IHt9LCAuLi5yZXN0KSB7XG4gICAgLy8gQmVjYXVzZSB1cGRhdGUvdXBkYXRlQWxsIG9ubHkgcmVjZWl2ZXMgYSAnd2hlcmUnLCB0aGVyZSdzIG5vd2hlcmUgdG8gYXNrIGZvciB0aGUgZGVsZXRlZCBlbnRpdGllcy5cbiAgICBsZXQgd2hlcmVOb3REZWxldGVkO1xuICAgIGlmICghd2hlcmUgfHwgT2JqZWN0LmtleXMod2hlcmUpLmxlbmd0aCA9PT0gMCkge1xuICAgICAgd2hlcmVOb3REZWxldGVkID0gcXVlcnlOb25EZWxldGVkO1xuICAgIH0gZWxzZSB7XG4gICAgICB3aGVyZU5vdERlbGV0ZWQgPSB7IGFuZDogWyB3aGVyZSwgcXVlcnlOb25EZWxldGVkIF0gfTtcbiAgICB9XG4gICAgcmV0dXJuIF91cGRhdGUuY2FsbChNb2RlbCwgd2hlcmVOb3REZWxldGVkLCAuLi5yZXN0KTtcbiAgfTtcblxuICBpZiAoTW9kZWwuc2V0dGluZ3MucmVtb3RpbmcgJiYgTW9kZWwuc2V0dGluZ3MucmVtb3Rpbmcuc2hhcmVkTWV0aG9kcy5kZWxldGVCeUlkICE9PSBmYWxzZSAmJiAoZGVsZXRlZEJ5SWQgfHwgZGVsZXRlT3ApKSB7XG4gICAgTW9kZWwuZGlzYWJsZVJlbW90ZU1ldGhvZEJ5TmFtZSgnZGVsZXRlQnlJZCcpO1xuXG4gICAgTW9kZWwucmVtb3RlTWV0aG9kKCdkZWxldGVCeUlkJywge1xuICAgICAgYWNjZXNzVHlwZTogJ1dSSVRFJyxcbiAgICAgIGlzU3RhdGljOiBmYWxzZSxcbiAgICAgIGFjY2VwdHM6IFtcbiAgICAgICAgeyBhcmc6ICdvcHRpb25zJywgdHlwZTogJ29iamVjdCcsIGh0dHA6ICdvcHRpb25zRnJvbVJlcXVlc3QnIH1cbiAgICAgIF0sXG4gICAgICByZXR1cm5zOiB7YXJnOiAnZGF0YScsIHR5cGU6ICdvYmplY3QnLCByb290OiB0cnVlfSxcbiAgICAgIGh0dHA6IHt2ZXJiOiAnZGVsZXRlJywgcGF0aDogJy8nfSxcbiAgICB9KTtcblxuICAgIE1vZGVsLnByb3RvdHlwZS5kZWxldGVCeUlkID0gZnVuY3Rpb24ob3B0aW9ucyA9IHt9KSB7XG4gICAgICBpZiAoZGVsZXRlZEJ5SWQpIG9wdGlvbnMuZGVsZXRlZEJ5SWQgPSBvcHRpb25zLmFjY2Vzc1Rva2VuID8gb3B0aW9ucy5hY2Nlc3NUb2tlbi51c2VySWQgOiBudWxsO1xuICAgICAgaWYgKGRlbGV0ZU9wICYmIG9wdGlvbnMuZGVsZXRlZEJ5SWQpIG9wdGlvbnMuZGVsZXRlT3AgPSAndXNlcic7XG4gICAgICByZXR1cm4gdGhpcy5kZXN0cm95KG9wdGlvbnMpLnRoZW4oZnVuY3Rpb24oKSB7XG4gICAgICAgIHJldHVybiB7IGNvdW50OiAxIH1cbiAgICAgIH0pXG4gICAgfTtcbiAgfVxufTtcblxudmFyIGdlbktleSA9IGZ1bmN0aW9uKCkge1xuICByZXR1cm4gY3J5cHRvLmNyZWF0ZUhtYWMoJ3NoYTI1NicsIE1hdGgucmFuZG9tKCkudG9TdHJpbmcoMTIpLnN1YnN0cigyKSkuZGlnZXN0KCdoZXgnKS5zdWJzdHIoMCwgOCk7XG59O1xuIl19