UNPKG

bpm-engine

Version:

Business Process Management Engine for JavaScript

387 lines (300 loc) 36.1 kB
'use strict'; Object.defineProperty(exports, "__esModule", { value: true }); exports.Plugins = undefined; var _assign = require('babel-runtime/core-js/object/assign'); var _assign2 = _interopRequireDefault(_assign); var _asyncToGenerator2 = require('babel-runtime/helpers/asyncToGenerator'); var _asyncToGenerator3 = _interopRequireDefault(_asyncToGenerator2); var _Plugins = require('./lib/Plugins'); Object.defineProperty(exports, 'Plugins', { enumerable: true, get: function get() { return _interopRequireDefault(_Plugins).default; } }); require('source-map-support/register'); var _defaults = require('./lib/defaults'); var _defaults2 = _interopRequireDefault(_defaults); var _loadPlugins = require('./lib/loadPlugins'); var _loadPlugins2 = _interopRequireDefault(_loadPlugins); var _debug = require('./lib/debug'); var _debug2 = _interopRequireDefault(_debug); var _TokenInstance = require('./lib/TokenInstance'); var _TokenInstance2 = _interopRequireDefault(_TokenInstance); var _Clock = require('./lib/Clock'); var _Clock2 = _interopRequireDefault(_Clock); var _iso8601RepeatingInterval = require('iso8601-repeating-interval'); var _iso8601RepeatingInterval2 = _interopRequireDefault(_iso8601RepeatingInterval); var _constants = require('./lib/constants'); var constants = _interopRequireWildcard(_constants); var _getNextFlowObjects = require('./lib/getNextFlowObjects'); var _getNextFlowObjects2 = _interopRequireDefault(_getNextFlowObjects); function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } } function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } const log = (0, _debug2.default)('engine'); const isTimerStartEvent = flowObject => { if (flowObject.$type === 'bpmn:StartEvent') { const eventDefinitions = flowObject.eventDefinitions; if (eventDefinitions) { const firstEventDefinition = eventDefinitions[0]; // if this start event has timereventdefinitions if (firstEventDefinition.$type === 'bpmn:TimerEventDefinition') { // if it's timer is of type cycle (repetition) if (firstEventDefinition.timeCycle) { return firstEventDefinition; } } } } return false; }; /** * */ class BPMEngine { constructor({ generateId = _defaults2.default.generateId, evalCondition = _defaults2.default.evalCondition, persist = new _defaults2.default.MemoryPersist(), enableClock = true, plugins = [] } = {}) { var _this = this; this.onTick = (0, _asyncToGenerator3.default)(function* () { log('onTick'); const currentTimestamp = new Date().getTime(); const timerEvent = yield _this.persist.timer.getNext(currentTimestamp); if (timerEvent) { // set this timer to done, so it won't be returned by above `getNext` again yield _this.persist.timer.update({ timerId: timerEvent.timerId }, { status: 'done' }); yield _this.handleTimerEvent(timerEvent); // get the next timer after the current one const interval = (0, _iso8601RepeatingInterval2.default)(timerEvent.interval); // the + 1 is to not get the same timer again const nextTimerEvent = interval.firstAfter(timerEvent.time + 1); // if there is no next, complete this tick if (!nextTimerEvent) { return; } // if the nextTimerEvent's index is lower than the maximum amount of repetitions // create a next timer event const hasPendingRepetitions = nextTimerEvent.index < interval._repeatCount; if (hasPendingRepetitions && timerEvent.intent !== constants.CONTINUE_TOKEN_INSTANCE_INTENT) { yield _this.persist.timer.create({ timerId: _this.generateId(), index: nextTimerEvent.index, interval: timerEvent.interval, time: nextTimerEvent.date / 1, previousTimerId: timerEvent.timerId, intent: timerEvent.intent, workflowDefinitionId: timerEvent.workflowDefinitionId }); } } }); (0, _assign2.default)(this, { generateId, evalCondition, persist, plugins: (0, _loadPlugins2.default)(plugins) }); if (enableClock) { this.clock = new _Clock2.default({ onTick: this.onTick, interval: 100 }); } log('Initiated'); } handleTimerEvent(timerEvent) { var _this2 = this; return (0, _asyncToGenerator3.default)(function* () { let token; const intent = timerEvent.intent; // if the intention of the timer is to start a process instance // create a new process instance and get its token if (intent === constants.START_PROCESS_INSTANCE_INTENT) { const workflowDefinitionId = timerEvent.workflowDefinitionId; token = yield _this2.createProcessInstance({ workflowDefinitionId }); } // if the intention of the timer is to continue a token instance // get the token instance if (intent === constants.CONTINUE_TOKEN_INSTANCE_INTENT) { const tokenId = timerEvent.tokenId; token = yield _this2.continueTokenInstance({ tokenId }); } // if a token was created/fetched, continue its execution if (token) { token.execute(); } })(); } createProcessInstance({ workflowDefinition, workflowDefinitionId, payload = {} } = {}) { var _this3 = this; return (0, _asyncToGenerator3.default)(function* () { let workflowDefinitionXML; if (workflowDefinition) { workflowDefinitionXML = workflowDefinition; } else if (workflowDefinitionId) { const deployedWorkflowDefinition = yield _this3.findWorkflowDefinition(workflowDefinitionId); if (deployedWorkflowDefinition) { workflowDefinitionXML = deployedWorkflowDefinition.xml; } } if (!workflowDefinitionXML) { throw new Error('Invalid WorkflowDefinition'); } const processId = _this3.generateId(); log(`Creating processInstance ${processId}`); yield _this3.persist.processInstance.create({ processId, workflowDefinition: workflowDefinitionXML, payload }); log(`processInstance ${processId} created`); const tokenInstance = yield _this3.createTokenInstance({ processId, payload, workflowDefinition: workflowDefinitionXML }); return tokenInstance; })(); } createTokenInstance({ processId, payload, workflowDefinition, tokenId = this.generateId(), status, parent, isSubProcess, currentActivity, flowObjects }) { var _this4 = this; return (0, _asyncToGenerator3.default)(function* () { log(`Creating tokenInstance ${tokenId}`); const tokenInstance = new _TokenInstance2.default({ processId, tokenId, payload, workflowDefinition, status, parent, isSubProcess, currentActivity, engine: _this4 }); if (!flowObjects) { yield tokenInstance.initialize(); } else { tokenInstance.flowObjects = flowObjects; } log(`tokenInstance ${tokenId} created`); return tokenInstance; })(); } continueTokenInstance({ tokenId, payload = {} }) { var _this5 = this; return (0, _asyncToGenerator3.default)(function* () { log(`Continuing tokenInstance ${tokenId}`); const persistedTokenInstance = yield _this5.findTokenInstance(tokenId); const persistedProcessInstance = yield _this5.findProcessInstance(persistedTokenInstance.processId); const workflowDefinition = persistedProcessInstance.workflowDefinition; const mergedPayload = (0, _assign2.default)(persistedProcessInstance.payload, persistedTokenInstance.payload, payload); const tokenInstance = yield _this5.createTokenInstance({ processId: persistedProcessInstance.processId, payload: mergedPayload, workflowDefinition, tokenId, status: 'paused', currentActivity: persistedTokenInstance.next, isSubProcess: persistedTokenInstance.isSubProcess, parent: persistedTokenInstance.parent }); tokenInstance.flowObjects = (0, _getNextFlowObjects2.default)(tokenInstance.flowObjects, persistedTokenInstance.currentActivity); tokenInstance.next = tokenInstance.flowObjects.find(function (el) { return el.id === persistedTokenInstance.currentActivity; }); return tokenInstance; })(); } findTokenInstance(tokenId) { return this.persist.tokenInstance.find({ tokenId }); } findProcessInstance(processId) { return this.persist.processInstance.find({ processId }); } findWorkflowDefinition(workflowDefinitionId) { return this.persist.workflowDefinition.find({ workflowDefinitionId }); } // create listeners for timer and message start events createStartEvents(dummyTokenInstance, workflowDefinitionId) { var _this6 = this; return (0, _asyncToGenerator3.default)(function* () { const flowObjects = dummyTokenInstance.flowObjects; flowObjects.forEach((() => { var _ref2 = (0, _asyncToGenerator3.default)(function* (flowObject) { const eventDefinition = isTimerStartEvent(flowObject); if (eventDefinition) { // evaluate the interval const intervalExpression = `return \`${eventDefinition.timeCycle.body}\`;`; const intervalExpressionFunction = new Function('timestamp', intervalExpression); const intervalString = intervalExpressionFunction(new Date().toISOString()); // create the interval and get the first iteration const interval = (0, _iso8601RepeatingInterval2.default)(intervalString); const firstAfter = interval.firstAfter(new Date() - 1000); // if the first iteration is not bigger than the max amount of repetitions const hasPendingRepetitions = firstAfter.index <= interval._repeatCount; if (hasPendingRepetitions) { // create a timer event yield _this6.persist.timer.create({ timerId: _this6.generateId(), index: firstAfter.index, time: firstAfter.date / 1, interval: intervalString, intent: constants.START_PROCESS_INSTANCE_INTENT, workflowDefinitionId }); } } }); return function (_x) { return _ref2.apply(this, arguments); }; })()); })(); } deployWorkflowDefinition({ xml, workflowDefinitionId = this.generateId() }) { var _this7 = this; return (0, _asyncToGenerator3.default)(function* () { const dummyTokenInstance = new _TokenInstance2.default({ workflowDefinition: xml }); // initialize the tokenInstance so flowObjects get parsed, // we use them to get all the StartEvents yield dummyTokenInstance.initialize(); const alreadyExistingWorkflowDefinition = yield _this7.persist.workflowDefinition.find({ workflowDefinitionId }); let workflowDefinition; if (alreadyExistingWorkflowDefinition) { workflowDefinition = yield _this7.persist.workflowDefinition.update({ workflowDefinitionId }, { xml }); } else { workflowDefinition = yield _this7.persist.workflowDefinition.create({ xml, workflowDefinitionId }); } // remove already existing start events for this workflowDefinition yield _this7.persist.timer.update({ workflowDefinitionId }, { status: 'done' }, { multi: true }); // we need to create the start events after the creation of the workflowDefinition // so that a timer can not happen before the workflowDefinition is deployed. yield _this7.createStartEvents(dummyTokenInstance, workflowDefinition.workflowDefinitionId); return workflowDefinition; })(); } } exports.default = BPMEngine; //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uL3NyYy9pbmRleC5qcyJdLCJuYW1lcyI6WyJkZWZhdWx0IiwiY29uc3RhbnRzIiwibG9nIiwiaXNUaW1lclN0YXJ0RXZlbnQiLCJmbG93T2JqZWN0IiwiJHR5cGUiLCJldmVudERlZmluaXRpb25zIiwiZmlyc3RFdmVudERlZmluaXRpb24iLCJ0aW1lQ3ljbGUiLCJCUE1FbmdpbmUiLCJjb25zdHJ1Y3RvciIsImdlbmVyYXRlSWQiLCJkZWZhdWx0cyIsImV2YWxDb25kaXRpb24iLCJwZXJzaXN0IiwiTWVtb3J5UGVyc2lzdCIsImVuYWJsZUNsb2NrIiwicGx1Z2lucyIsIm9uVGljayIsImN1cnJlbnRUaW1lc3RhbXAiLCJEYXRlIiwiZ2V0VGltZSIsInRpbWVyRXZlbnQiLCJ0aW1lciIsImdldE5leHQiLCJ1cGRhdGUiLCJ0aW1lcklkIiwic3RhdHVzIiwiaGFuZGxlVGltZXJFdmVudCIsImludGVydmFsIiwibmV4dFRpbWVyRXZlbnQiLCJmaXJzdEFmdGVyIiwidGltZSIsImhhc1BlbmRpbmdSZXBldGl0aW9ucyIsImluZGV4IiwiX3JlcGVhdENvdW50IiwiaW50ZW50IiwiQ09OVElOVUVfVE9LRU5fSU5TVEFOQ0VfSU5URU5UIiwiY3JlYXRlIiwiZGF0ZSIsInByZXZpb3VzVGltZXJJZCIsIndvcmtmbG93RGVmaW5pdGlvbklkIiwiY2xvY2siLCJDbG9jayIsInRva2VuIiwiU1RBUlRfUFJPQ0VTU19JTlNUQU5DRV9JTlRFTlQiLCJjcmVhdGVQcm9jZXNzSW5zdGFuY2UiLCJ0b2tlbklkIiwiY29udGludWVUb2tlbkluc3RhbmNlIiwiZXhlY3V0ZSIsIndvcmtmbG93RGVmaW5pdGlvbiIsInBheWxvYWQiLCJ3b3JrZmxvd0RlZmluaXRpb25YTUwiLCJkZXBsb3llZFdvcmtmbG93RGVmaW5pdGlvbiIsImZpbmRXb3JrZmxvd0RlZmluaXRpb24iLCJ4bWwiLCJFcnJvciIsInByb2Nlc3NJZCIsInByb2Nlc3NJbnN0YW5jZSIsInRva2VuSW5zdGFuY2UiLCJjcmVhdGVUb2tlbkluc3RhbmNlIiwicGFyZW50IiwiaXNTdWJQcm9jZXNzIiwiY3VycmVudEFjdGl2aXR5IiwiZmxvd09iamVjdHMiLCJUb2tlbkluc3RhbmNlIiwiZW5naW5lIiwiaW5pdGlhbGl6ZSIsInBlcnNpc3RlZFRva2VuSW5zdGFuY2UiLCJmaW5kVG9rZW5JbnN0YW5jZSIsInBlcnNpc3RlZFByb2Nlc3NJbnN0YW5jZSIsImZpbmRQcm9jZXNzSW5zdGFuY2UiLCJtZXJnZWRQYXlsb2FkIiwibmV4dCIsImZpbmQiLCJlbCIsImlkIiwiY3JlYXRlU3RhcnRFdmVudHMiLCJkdW1teVRva2VuSW5zdGFuY2UiLCJmb3JFYWNoIiwiZXZlbnREZWZpbml0aW9uIiwiaW50ZXJ2YWxFeHByZXNzaW9uIiwiYm9keSIsImludGVydmFsRXhwcmVzc2lvbkZ1bmN0aW9uIiwiRnVuY3Rpb24iLCJpbnRlcnZhbFN0cmluZyIsInRvSVNPU3RyaW5nIiwiZGVwbG95V29ya2Zsb3dEZWZpbml0aW9uIiwiYWxyZWFkeUV4aXN0aW5nV29ya2Zsb3dEZWZpbml0aW9uIiwibXVsdGkiXSwibWFwcGluZ3MiOiI7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OzRDQXFUU0EsTzs7OztBQXJUVDs7QUFFQTs7OztBQUNBOzs7O0FBQ0E7Ozs7QUFDQTs7OztBQUNBOzs7O0FBQ0E7Ozs7QUFFQTs7SUFBWUMsUzs7QUFDWjs7Ozs7Ozs7QUFFQSxNQUFNQyxNQUFNLHFCQUFNLFFBQU4sQ0FBWjs7QUFFQSxNQUFNQyxvQkFBcUJDLFVBQUQsSUFBZ0I7QUFDeEMsTUFBSUEsV0FBV0MsS0FBWCxLQUFxQixpQkFBekIsRUFBNEM7QUFBQSxVQUNsQ0MsZ0JBRGtDLEdBQ2JGLFVBRGEsQ0FDbENFLGdCQURrQzs7QUFFMUMsUUFBSUEsZ0JBQUosRUFBc0I7QUFDcEIsWUFBTUMsdUJBQXVCRCxpQkFBaUIsQ0FBakIsQ0FBN0I7QUFDQTtBQUNBLFVBQUlDLHFCQUFxQkYsS0FBckIsS0FBK0IsMkJBQW5DLEVBQWdFO0FBQzlEO0FBQ0EsWUFBSUUscUJB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WCxVQUFuQixFQUFOOztBQUVBLFlBQU1xQixvQ0FBb0MsTUFBTSxPQUFLMUUsT0FBTCxDQUFhb0Msa0JBQWIsQ0FBZ0N3QixJQUFoQyxDQUFxQztBQUNuRmpDO0FBRG1GLE9BQXJDLENBQWhEOztBQUlBLFVBQUlTLGtCQUFKOztBQUVBLFVBQUlzQyxpQ0FBSixFQUF1QztBQUNyQ3RDLDZCQUFxQixNQUFNLE9BQUtwQyxPQUFMLENBQWFvQyxrQkFBYixDQUFnQ3pCLE1BQWhDLENBQ3pCLEVBQUVnQixvQkFBRixFQUR5QixFQUV6QjtBQUNFYztBQURGLFNBRnlCLENBQTNCO0FBTUQsT0FQRCxNQVFLO0FBQ0hMLDZCQUFxQixNQUFNLE9BQUtwQyxPQUFMLENBQWFvQyxrQkFBYixDQUFnQ1osTUFBaEMsQ0FBdUM7QUFDaEVpQixhQURnRTtBQUVoRWQ7QUFGZ0UsU0FBdkMsQ0FBM0I7QUFJRDs7QUFFRDtBQUNBLFlBQU0sT0FBSzNCLE9BQUwsQ0FBYVMsS0FBYixDQUFtQkUsTUFBbkIsQ0FBMEIsRUFBRWdCLG9CQUFGLEVBQTFCLEVBQW9ELEVBQUVkLFFBQVEsTUFBVixFQUFwRCxFQUF3RSxFQUFFOEQsT0FBTyxJQUFULEVBQXhFLENBQU47O0FBRUE7QUFDQTtBQUNBLFlBQU0sT0FBS1osaUJBQUwsQ0FBdUJDLGtCQUF2QixFQUEyQzVCLG1CQUFtQlQsb0JBQTlELENBQU47O0FBRUEsYUFBT1Msa0JBQVA7QUFyQ2dGO0FBc0NqRjtBQS9RYTs7a0JBa1JEekMsUyIsImZpbGUiOiJpbmRleC5qcyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCAnc291cmNlLW1hcC1zdXBwb3J0L3JlZ2lzdGVyJztcblxuaW1wb3J0IGRlZmF1bHRzIGZyb20gJ2xpYi9kZWZhdWx0cyc7XG5pbXBvcnQgbG9hZFBsdWdpbnMgZnJvbSAnbGliL2xvYWRQbHVnaW5zJztcbmltcG9ydCBkZWJ1ZyBmcm9tICdsaWIvZGVidWcnO1xuaW1wb3J0IFRva2VuSW5zdGFuY2UgZnJvbSAnbGliL1Rva2VuSW5zdGFuY2UnO1xuaW1wb3J0IENsb2NrIGZyb20gJ2xpYi9DbG9jayc7XG5pbXBvcnQgbWFrZUludGVydmFsIGZyb20gJ2lzbzg2MDEtcmVwZWF0aW5nLWludGVydmFsJztcblxuaW1wb3J0ICogYXMgY29uc3RhbnRzIGZyb20gJ2xpYi9jb25zdGFudHMnO1xuaW1wb3J0IGdldE5leHRGbG93T2JqZWN0cyBmcm9tICdsaWIvZ2V0TmV4dEZsb3dPYmplY3RzJztcblxuY29uc3QgbG9nID0gZGVidWcoJ2VuZ2luZScpO1xuXG5jb25zdCBpc1RpbWVyU3RhcnRFdmVudCA9IChmbG93T2JqZWN0KSA9PiB7XG4gIGlmIChmbG93T2JqZWN0LiR0eXBlID09PSAnYnBtbjpTdGFydEV2ZW50Jykge1xuICAgIGNvbnN0IHsgZXZlbnREZWZpbml0aW9ucyB9ID0gZmxvd09iamVjdDtcbiAgICBpZiAoZXZlbnREZWZpbml0aW9ucykge1xuICAgICAgY29uc3QgZmlyc3RFdmVudERlZmluaXRpb24gPSBldmVudERlZmluaXRpb25zWzBdO1xuICAgICAgLy8gaWYgdGhpcyBzdGFydCBldmVudCBoYXMgdGltZXJldmVudGRlZmluaXRpb25zXG4gICAgICBpZiAoZmlyc3RFdmVudERlZmluaXRpb24uJHR5cGUgPT09ICdicG1uOlRpbWVyRXZlbnREZWZpbml0aW9uJykge1xuICAgICAgICAvLyBpZiBpdCdzIHRpbWVyIGlzIG9mIHR5cGUgY3ljbGUgKHJlcGV0aXRpb24pXG4gICAgICAgIGlmIChmaXJzdEV2ZW50RGVmaW5pdGlvbi50aW1lQ3ljbGUpIHtcbiAgICAgICAgICByZXR1cm4gZmlyc3RFdmVudERlZmluaXRpb247XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9XG4gIH1cbiAgcmV0dXJuIGZhbHNlO1xufTtcblxuLyoqXG4gKlxuICovXG5jbGFzcyBCUE1FbmdpbmUge1xuICBjb25zdHJ1Y3Rvcih7XG4gICAgZ2VuZXJhdGVJZCA9IGRlZmF1bHRzLmdlbmVyYXRlSWQsXG4gICAgZXZhbENvbmRpdGlvbiA9IGRlZmF1bHRzLmV2YWxDb25kaXRpb24sXG4gICAgcGVyc2lzdCA9IG5ldyBkZWZhdWx0cy5NZW1vcnlQZXJzaXN0KCksXG4gICAgZW5hYmxlQ2xvY2sgPSB0cnVlLFxuICAgIHBsdWdpbnMgPSBbXSxcbiAgfSA9IHt9KSB7XG4gICAgT2JqZWN0LmFzc2lnbih0aGlzLCB7XG4gICAgICBnZW5lcmF0ZUlkLFxuICAgICAgZXZhbENvbmRpdGlvbixcbiAgICAgIHBlcnNpc3QsXG4gICAgICBwbHVnaW5zOiBsb2FkUGx1Z2lucyhwbHVnaW5zKSxcbiAgICB9KTtcblxuICAgIGlmIChlbmFibGVDbG9jaykge1xuICAgICAgdGhpcy5jbG9jayA9IG5ldyBDbG9jayh7IG9uVGljazogdGhpcy5vblRpY2ssIGludGVydmFsOiAxMDAgfSk7XG4gICAgfVxuXG4gICAgbG9nKCdJbml0aWF0ZWQnKTtcbiAgfVxuXG4gIG9uVGljayA9IGFzeW5jICgpID0+IHtcbiAgICBsb2coJ29uVGljaycpO1xuICAgIGNvbnN0IGN1cnJlbnRUaW1lc3RhbXAgPSBuZXcgRGF0ZSgpLmdldFRpbWUoKTtcbiAgICBjb25zdCB0aW1lckV2ZW50ID0gYXdhaXQgdGhpcy5wZXJzaXN0LnRpbWVyLmdldE5leHQoY3VycmVudFRpbWVzdGFtcCk7XG5cbiAgICBpZiAodGltZXJFdmVudCkge1xuICAgICAgLy8gc2V0IHRoaXMgdGltZXIgdG8gZG9uZSwgc28gaXQgd29uJ3QgYmUgcmV0dXJuZWQgYnkgYWJvdmUgYGdldE5leHRgIGFnYWluXG4gICAgICBhd2FpdCB0aGlzLnBlcnNpc3QudGltZXIudXBkYXRlKHsgdGltZXJJZDogdGltZXJFdmVudC50aW1lcklkIH0sIHsgc3RhdHVzOiAnZG9uZScgfSk7XG5cbiAgICAgIGF3YWl0IHRoaXMuaGFuZGxlVGltZXJFdmVudCh0aW1lckV2ZW50KTtcblxuICAgICAgLy8gZ2V0IHRoZSBuZXh0IHRpbWVyIGFmdGVyIHRoZSBjdXJyZW50IG9uZVxuICAgICAgY29uc3QgaW50ZXJ2YWwgPSBtYWtlSW50ZXJ2YWwodGltZXJFdmVudC5pbnRlcnZhbCk7XG5cbiAgICAgIC8vIHRoZSArIDEgaXMgdG8gbm90IGdldCB0aGUgc2FtZSB0aW1lciBhZ2FpblxuICAgICAgY29uc3QgbmV4dFRpbWVyRXZlbnQgPSBpbnRlcnZhbC5maXJzdEFmdGVyKHRpbWVyRXZlbnQudGltZSArIDEpO1xuXG4gICAgICAvLyBpZiB0aGVyZSBpcyBubyBuZXh0LCBjb21wbGV0ZSB0aGlzIHRpY2tcbiAgICAgIGlmICghbmV4dFRpbWVyRXZlbnQpIHtcbiAgICAgICAgcmV0dXJuO1xuICAgICAgfVxuXG4gICAgICAvLyBpZiB0aGUgbmV4dFRpbWVyRXZlbnQncyBpbmRleCBpcyBsb3dlciB0aGFuIHRoZSBtYXhpbXVtIGFtb3VudCBvZiByZXBldGl0aW9uc1xuICAgICAgLy8gY3JlYXRlIGEgbmV4dCB0aW1lciBldmVudFxuICAgICAgY29uc3QgaGFzUGVuZGluZ1JlcGV0aXRpb25zID0gbmV4dFRpbWVyRXZlbnQuaW5kZXggPCBpbnRlcnZhbC5fcmVwZWF0Q291bnQ7XG4gICAgICBpZiAoaGFzUGVuZGluZ1JlcGV0aXRpb25zICYmIHRpbWVyRXZlbnQuaW50ZW50ICE9PSBjb25zdGFudHMuQ09OVElOVUVfVE9LRU5fSU5TVEFOQ0VfSU5URU5UKSB7XG4gICAgICAgIGF3YWl0IHRoaXMucGVyc2lzdC50aW1lci5jcmVhdGUoe1xuICAgICAgICAgIHRpbWVySWQ6IHRoaXMuZ2VuZXJhdGVJZCgpLFxuICAgICAgICAgIGluZGV4OiBuZXh0VGltZXJFdmVudC5pbmRleCxcbiAgICAgICAgICBpbnRlcnZhbDogdGltZXJFdmVudC5pbnRlcnZhbCxcbiAgICAgICAgICB0aW1lOiBuZXh0VGltZXJFdmVudC5kYXRlIC8gMSxcbiAgICAgICAgICBwcmV2aW91c1RpbWVySWQ6IHRpbWVyRXZlbnQudGltZXJJZCxcbiAgICAgICAgICBpbnRlbnQ6IHRpbWVyRXZlbnQuaW50ZW50LFxuICAgICAgICAgIHdvcmtmbG93RGVmaW5pdGlvbklkOiB0aW1lckV2ZW50LndvcmtmbG93RGVmaW5pdGlvbklkLFxuICAgICAgICB9KTtcbiAgICAgIH1cbiAgICB9XG4gIH07XG5cbiAgYXN5bmMgaGFuZGxlVGltZXJFdmVudCh0aW1lckV2ZW50KSB7XG4gICAgbGV0IHRva2VuO1xuICAgIGNvbnN0IHsgaW50ZW50IH0gPSB0aW1lckV2ZW50O1xuXG4gICAgLy8gaWYgdGhlIGludGVudGlvbiBvZiB0aGUgdGltZXIgaXMgdG8gc3RhcnQgYSBwcm9jZXNzIGluc3RhbmNlXG4gICAgLy8gY3JlYXRlIGEgbmV3IHByb2Nlc3MgaW5zdGFuY2UgYW5kIGdldCBpdHMgdG9rZW5cbiAgICBpZiAoaW50ZW50ID09PSBjb25zdGFudHMuU1RBUlRfUFJPQ0VTU19JTlNUQU5DRV9JTlRFTlQpIHtcbiAgICAgIGNvbnN0IHsgd29ya2Zsb3dEZWZpbml0aW9uSWQgfSA9IHRpbWVyRXZlbnQ7XG4gICAgICB0b2tlbiA9IGF3YWl0IHRoaXMuY3JlYXRlUHJvY2Vzc0luc3RhbmNlKHsgd29ya2Zsb3dEZWZpbml0aW9uSWQgfSk7XG4gICAgfVxuXG4gICAgLy8gaWYgdGhlIGludGVudGlvbiBvZiB0aGUgdGltZXIgaXMgdG8gY29udGludWUgYSB0b2tlbiBpbnN0YW5jZVxuICAgIC8vIGdldCB0aGUgdG9rZW4gaW5zdGFuY2VcbiAgICBpZiAoaW50ZW50ID09PSBjb25zdGFudHMuQ09OVElOVUVfVE9LRU5fSU5TVEFOQ0VfSU5URU5UKSB7XG4gICAgICBjb25zdCB7IHRva2VuSWQgfSA9IHRpbWVyRXZlbnQ7XG4gICAgICB0b2tlbiA9IGF3YWl0IHRoaXMuY29udGludWVUb2tlbkluc3RhbmNlKHsgdG9rZW5JZCB9KTtcbiAgICB9XG5cbiAgICAvLyBpZiBhIHRva2VuIHdhcyBjcmVhdGVkL2ZldGNoZWQsIGNvbnRpbnVlIGl0cyBleGVjdXRpb25cbiAgICBpZiAodG9rZW4pIHtcbiAgICAgIHRva2VuLmV4ZWN1dGUoKTtcbiAgICB9XG4gIH1cblxuICBhc3luYyBjcmVhdGVQcm9jZXNzSW5zdGFuY2UoeyB3b3JrZmxvd0RlZmluaXRpb24sIHdvcmtmbG93RGVmaW5pdGlvbklkLCBwYXlsb2FkID0ge30gfSA9IHt9KSB7XG4gICAgbGV0IHdvcmtmbG93RGVmaW5pdGlvblhNTDtcblxuICAgIGlmICh3b3JrZmxvd0RlZmluaXRpb24pIHtcbiAgICAgIHdvcmtmbG93RGVmaW5pdGlvblhNTCA9IHdvcmtmbG93RGVmaW5pdGlvbjtcbiAgICB9XG4gICAgZWxzZSBpZiAod29ya2Zsb3dEZWZpbml0aW9uSWQpIHtcbiAgICAgIGNvbnN0IGRlcGxveWVkV29ya2Zsb3dEZWZpbml0aW9uID0gYXdhaXQgdGhpcy5maW5kV29ya2Zsb3dEZWZpbml0aW9uKHdvcmtmbG93RGVmaW5pdGlvbklkKTtcbiAgICAgIGlmIChkZXBsb3llZFdvcmtmbG93RGVmaW5pdGlvbikge1xuICAgICAgICB3b3JrZmxvd0RlZmluaXRpb25YTUwgPSBkZXBsb3llZFdvcmtmbG93RGVmaW5pdGlvbi54bWw7XG4gICAgICB9XG4gICAgfVxuXG4gICAgaWYgKCF3b3JrZmxvd0RlZmluaXRpb25YTUwpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcignSW52YWxpZCBXb3JrZmxvd0RlZmluaXRpb24nKTtcbiAgICB9XG5cbiAgICBjb25zdCBwcm9jZXNzSWQgPSB0aGlzLmdlbmVyYXRlSWQoKTtcbiAgICBsb2coYENyZWF0aW5nIHByb2Nlc3NJbnN0YW5jZSAke3Byb2Nlc3NJZH1gKTtcbiAgICBhd2FpdCB0aGlzLnBlcnNpc3QucHJvY2Vzc0luc3RhbmNlLmNyZWF0ZSh7XG4gICAgICBwcm9jZXNzSWQsXG4gICAgICB3b3JrZmxvd0RlZmluaXRpb246IHdvcmtmbG93RGVmaW5pdGlvblhNTCxcbiAgICAgIHBheWxvYWQsXG4gICAgfSk7XG4gICAgbG9nKGBwcm9jZXNzSW5zdGFuY2UgJHtwcm9jZXNzSWR9IGNyZWF0ZWRgKTtcblxuICAgIGNvbnN0IHRva2VuSW5zdGFuY2UgPSBhd2FpdCB0aGlzLmNyZWF0ZVRva2VuSW5zdGFuY2Uoe1xuICAgICAgcHJvY2Vzc0lkLFxuICAgICAgcGF5bG9hZCxcbiAgICAgIHdvcmtmbG93RGVmaW5pdGlvbjogd29ya2Zsb3dEZWZpbml0aW9uWE1MLFxuICAgIH0pO1xuXG4gICAgcmV0dXJuIHRva2VuSW5zdGFuY2U7XG4gIH1cblxuICBhc3luYyBjcmVhdGVUb2tlbkluc3RhbmNlKHtcbiAgICBwcm9jZXNzSWQsXG4gICAgcGF5bG9hZCxcbiAgICB3b3JrZmxvd0RlZmluaXRpb24sXG4gICAgdG9rZW5JZCA9IHRoaXMuZ2VuZXJhdGVJZCgpLFxuICAgIHN0YXR1cyxcbiAgICBwYXJlbnQsXG4gICAgaXNTdWJQcm9jZXNzLFxuICAgIGN1cnJlbnRBY3Rpdml0eSxcbiAgICBmbG93T2JqZWN0cyxcbiAgfSkge1xuICAgIGxvZyhgQ3JlYXRpbmcgdG9rZW5JbnN0YW5jZSAke3Rva2VuSWR9YCk7XG4gICAgY29uc3QgdG9rZW5JbnN0YW5jZSA9IG5ldyBUb2tlbkluc3RhbmNlKHtcbiAgICAgIHByb2Nlc3NJZCxcbiAgICAgIHRva2VuSWQsXG4gICAgICBwYXlsb2FkLFxuICAgICAgd29ya2Zsb3dEZWZpbml0aW9uLFxuICAgICAgc3RhdHVzLFxuICAgICAgcGFyZW50LFxuICAgICAgaXNTdWJQcm9jZXNzLFxuICAgICAgY3VycmVudEFjdGl2aXR5LFxuICAgICAgZW5naW5lOiB0aGlzLFxuICAgIH0pO1xuICAgIGlmICghZmxvd09iamVjdHMpIHtcbiAgICAgIGF3YWl0IHRva2VuSW5zdGFuY2UuaW5pdGlhbGl6ZSgpO1xuICAgIH1cbiAgICBlbHNlIHtcbiAgICAgIHRva2VuSW5zdGFuY2UuZmxvd09iamVjdHMgPSBmbG93T2JqZWN0cztcbiAgICB9XG4gICAgbG9nKGB0b2tlbkluc3RhbmNlICR7dG9rZW5JZH0gY3JlYXRlZGApO1xuXG4gICAgcmV0dXJuIHRva2VuSW5zdGFuY2U7XG4gIH1cblxuICBhc3luYyBjb250aW51ZVRva2VuSW5zdGFuY2UoeyB0b2tlbklkLCBwYXlsb2FkID0ge30gfSkge1xuICAgIGxvZyhgQ29udGludWluZyB0b2tlbkluc3RhbmNlICR7dG9rZW5JZH1gKTtcbiAgICBjb25zdCBwZXJzaXN0ZWRUb2tlbkluc3RhbmNlID0gYXdhaXQgdGhpcy5maW5kVG9rZW5JbnN0YW5jZSh0b2tlbklkKTtcbiAgICBjb25zdCBwZXJzaXN0ZWRQcm9jZXNzSW5zdGFuY2UgPSBhd2FpdCB0aGlzLmZpbmRQcm9jZXNzSW5zdGFuY2UocGVyc2lzdGVkVG9rZW5JbnN0YW5jZS5wcm9jZXNzSWQpO1xuXG4gICAgY29uc3QgeyB3b3JrZmxvd0RlZmluaXRpb24gfSA9IHBlcnNpc3RlZFByb2Nlc3NJbnN0YW5jZTtcbiAgICBjb25zdCBtZXJnZWRQYXlsb2FkID0gT2JqZWN0LmFzc2lnbihcbiAgICAgIHBlcnNpc3RlZFByb2Nlc3NJbnN0YW5jZS5wYXlsb2FkLFxuICAgICAgcGVyc2lzdGVkVG9rZW5JbnN0YW5jZS5wYXlsb2FkLFxuICAgICAgcGF5bG9hZCxcbiAgICApO1xuXG4gICAgY29uc3QgdG9rZW5JbnN0YW5jZSA9IGF3YWl0IHRoaXMuY3JlYXRlVG9rZW5JbnN0YW5jZSh7XG4gICAgICBwcm9jZXNzSWQ6IHBlcnNpc3RlZFByb2Nlc3NJbnN0YW5jZS5wcm9jZXNzSWQsXG4gICAgICBwYXlsb2FkOiBtZXJnZWRQYXlsb2FkLFxuICAgICAgd29ya2Zsb3dEZWZpbml0aW9uLFxuICAgICAgdG9rZW5JZCxcbiAgICAgIHN0YXR1czogJ3BhdXNlZCcsXG4gICAgICBjdXJyZW50QWN0aXZpdHk6IHBlcnNpc3RlZFRva2VuSW5zdGFuY2UubmV4dCxcbiAgICAgIGlzU3ViUHJvY2VzczogcGVyc2lzdGVkVG9rZW5JbnN0YW5jZS5pc1N1YlByb2Nlc3MsXG4gICAgICBwYXJlbnQ6IHBlcnNpc3RlZFRva2VuSW5zdGFuY2UucGFyZW50LFxuICAgIH0pO1xuXG4gICAgdG9rZW5JbnN0YW5jZS5mbG93T2JqZWN0cyA9IGdldE5leHRGbG93T2JqZWN0cyhcbiAgICAgIHRva2VuSW5zdGFuY2UuZmxvd09iamVjdHMsXG4gICAgICBwZXJzaXN0ZWRUb2tlbkluc3RhbmNlLmN1cnJlbnRBY3Rpdml0eSxcbiAgICApO1xuXG4gICAgdG9rZW5JbnN0YW5jZS5uZXh0ID0gdG9rZW5JbnN0YW5jZS5mbG93T2JqZWN0cy5maW5kKGVsID0+IGVsLmlkID09PSBwZXJzaXN0ZWRUb2tlbkluc3RhbmNlLmN1cnJlbnRBY3Rpdml0eSk7XG5cbiAgICByZXR1cm4gdG9rZW5JbnN0YW5jZTtcbiAgfVxuXG4gIGZpbmRUb2tlbkluc3RhbmNlKHRva2VuSWQpIHtcbiAgICByZXR1cm4gdGhpcy5wZXJzaXN0LnRva2VuSW5zdGFuY2UuZmluZCh7IHRva2VuSWQgfSk7XG4gIH1cblxuICBmaW5kUHJvY2Vzc0luc3RhbmNlKHByb2Nlc3NJZCkge1xuICAgIHJldHVybiB0aGlzLnBlcnNpc3QucHJvY2Vzc0luc3RhbmNlLmZpbmQoeyBwcm9jZXNzSWQgfSk7XG4gIH1cblxuICBmaW5kV29ya2Zsb3dEZWZpbml0aW9uKHdvcmtmbG93RGVmaW5pdGlvbklkKSB7XG4gICAgcmV0dXJuIHRoaXMucGVyc2lzdC53b3JrZmxvd0RlZmluaXRpb24uZmluZCh7IHdvcmtmbG93RGVmaW5pdGlvbklkIH0pO1xuICB9XG5cbiAgLy8gY3JlYXRlIGxpc3RlbmVycyBmb3IgdGltZXIgYW5kIG1lc3NhZ2Ugc3RhcnQgZXZlbnRzXG4gIGFzeW5jIGNyZWF0ZVN0YXJ0RXZlbnRzKGR1bW15VG9rZW5JbnN0YW5jZSwgd29ya2Zsb3dEZWZpbml0aW9uSWQpIHtcbiAgICBjb25zdCB7IGZsb3dPYmplY3RzIH0gPSBkdW1teVRva2VuSW5zdGFuY2U7XG5cbiAgICBmbG93T2JqZWN0cy5mb3JFYWNoKGFzeW5jIChmbG93T2JqZWN0KSA9PiB7XG4gICAgICBjb25zdCBldmVudERlZmluaXRpb24gPSBpc1RpbWVyU3RhcnRFdmVudChmbG93T2JqZWN0KTtcbiAgICAgIGlmIChldmVudERlZmluaXRpb24pIHtcbiAgICAgICAgLy8gZXZhbHVhdGUgdGhlIGludGVydmFsXG4gICAgICAgIGNvbnN0IGludGVydmFsRXhwcmVzc2lvbiA9IGByZXR1cm4gXFxgJHtldmVudERlZmluaXRpb24udGltZUN5Y2xlLmJvZHl9XFxgO2A7XG4gICAgICAgIGNvbnN0IGludGVydmFsRXhwcmVzc2lvbkZ1bmN0aW9uID0gbmV3IEZ1bmN0aW9uKCd0aW1lc3RhbXAnLCBpbnRlcnZhbEV4cHJlc3Npb24pO1xuICAgICAgICBjb25zdCBpbnRlcnZhbFN0cmluZyA9IGludGVydmFsRXhwcmVzc2lvbkZ1bmN0aW9uKG5ldyBEYXRlKCkudG9JU09TdHJpbmcoKSk7XG5cbiAgICAgICAgLy8gY3JlYXRlIHRoZSBpbnRlcnZhbCBhbmQgZ2V0IHRoZSBmaXJzdCBpdGVyYXRpb25cbiAgICAgICAgY29uc3QgaW50ZXJ2YWwgPSBtYWtlSW50ZXJ2YWwoaW50ZXJ2YWxTdHJpbmcpO1xuICAgICAgICBjb25zdCBmaXJzdEFmdGVyID0gaW50ZXJ2YWwuZmlyc3RBZnRlcihuZXcgRGF0ZSgpIC0gMTAwMCk7XG5cbiAgICAgICAgLy8gaWYgdGhlIGZpcnN0IGl0ZXJhdGlvbiBpcyBub3QgYmlnZ2VyIHRoYW4gdGhlIG1heCBhbW91bnQgb2YgcmVwZXRpdGlvbnNcbiAgICAgICAgY29uc3QgaGFzUGVuZGluZ1JlcGV0aXRpb25zID0gZmlyc3RBZnRlci5pbmRleCA8PSBpbnRlcnZhbC5fcmVwZWF0Q291bnQ7XG5cbiAgICAgICAgaWYgKGhhc1BlbmRpbmdSZXBldGl0aW9ucykge1xuICAgICAgICAgIC8vIGNyZWF0ZSBhIHRpbWVyIGV2ZW50XG4gICAgICAgICAgYXdhaXQgdGhpcy5wZXJzaXN0LnRpbWVyLmNyZWF0ZSh7XG4gICAgICAgICAgICB0aW1lcklkOiB0aGlzLmdlbmVyYXRlSWQoKSxcbiAgICAgICAgICAgIGluZGV4OiBmaXJzdEFmdGVyLmluZGV4LFxuICAgICAgICAgICAgdGltZTogZmlyc3RBZnRlci5kYXRlIC8gMSxcbiAgICAgICAgICAgIGludGVydmFsOiBpbnRlcnZhbFN0cmluZyxcbiAgICAgICAgICAgIGludGVudDogY29uc3RhbnRzLlNUQVJUX1BST0NFU1NfSU5TVEFOQ0VfSU5URU5ULFxuICAgICAgICAgICAgd29ya2Zsb3dEZWZpbml0aW9uSWQsXG4gICAgICAgICAgfSk7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9KTtcbiAgfVxuXG4gIGFzeW5jIGRlcGxveVdvcmtmbG93RGVmaW5pdGlvbih7IHhtbCwgd29ya2Zsb3dEZWZpbml0aW9uSWQgPSB0aGlzLmdlbmVyYXRlSWQoKSB9KSB7XG4gICAgY29uc3QgZHVtbXlUb2tlbkluc3RhbmNlID0gbmV3IFRva2VuSW5zdGFuY2Uoe1xuICAgICAgd29ya2Zsb3dEZWZpbml0aW9uOiB4bWwsXG4gICAgfSk7XG5cbiAgICAvLyBpbml0aWFsaXplIHRoZSB0b2tlbkluc3RhbmNlIHNvIGZsb3dPYmplY3RzIGdldCBwYXJzZWQsXG4gICAgLy8gd2UgdXNlIHRoZW0gdG8gZ2V0IGFsbCB0aGUgU3RhcnRFdmVudHNcbiAgICBhd2FpdCBkdW1teVRva2VuSW5zdGFuY2UuaW5pdGlhbGl6ZSgpO1xuXG4gICAgY29uc3QgYWxyZWFkeUV4aXN0aW5nV29ya2Zsb3dEZWZpbml0aW9uID0gYXdhaXQgdGhpcy5wZXJzaXN0LndvcmtmbG93RGVmaW5pdGlvbi5maW5kKHtcbiAgICAgIHdvcmtmbG93RGVmaW5pdGlvbklkLFxuICAgIH0pO1xuXG4gICAgbGV0IHdvcmtmbG93RGVmaW5pdGlvbjtcblxuICAgIGlmIChhbHJlYWR5RXhpc3RpbmdXb3JrZmxvd0RlZmluaXRpb24pIHtcbiAgICAgIHdvcmtmbG93RGVmaW5pdGlvbiA9IGF3YWl0IHRoaXMucGVyc2lzdC53b3JrZmxvd0RlZmluaXRpb24udXBkYXRlKFxuICAgICAgICB7IHdvcmtmbG93RGVmaW5pdGlvbklkIH0sXG4gICAgICAgIHtcbiAgICAgICAgICB4bWwsXG4gICAgICAgIH0sXG4gICAgICApO1xuICAgIH1cbiAgICBlbHNlIHtcbiAgICAgIHdvcmtmbG93RGVmaW5pdGlvbiA9IGF3YWl0IHRoaXMucGVyc2lzdC53b3JrZmxvd0RlZmluaXRpb24uY3JlYXRlKHtcbiAgICAgICAgeG1sLFxuICAgICAgICB3b3JrZmxvd0RlZmluaXRpb25JZCxcbiAgICAgIH0pO1xuICAgIH1cblxuICAgIC8vIHJlbW92ZSBhbHJlYWR5IGV4aXN0aW5nIHN0YXJ0IGV2ZW50cyBmb3IgdGhpcyB3b3JrZmxvd0RlZmluaXRpb25cbiAgICBhd2FpdCB0aGlzLnBlcnNpc3QudGltZXIudXBkYXRlKHsgd29ya2Zsb3dEZWZpbml0aW9uSWQgfSwgeyBzdGF0dXM6ICdkb25lJyB9LCB7IG11bHRpOiB0cnVlIH0pO1xuXG4gICAgLy8gd2UgbmVlZCB0byBjcmVhdGUgdGhlIHN0YXJ0IGV2ZW50cyBhZnRlciB0aGUgY3JlYXRpb24gb2YgdGhlIHdvcmtmbG93RGVmaW5pdGlvblxuICAgIC8vIHNvIHRoYXQgYSB0aW1lciBjYW4gbm90IGhhcHBlbiBiZWZvcmUgdGhlIHdvcmtmbG93RGVmaW5pdGlvbiBpcyBkZXBsb3llZC5cbiAgICBhd2FpdCB0aGlzLmNyZWF0ZVN0YXJ0RXZlbnRzKGR1bW15VG9rZW5JbnN0YW5jZSwgd29ya2Zsb3dEZWZpbml0aW9uLndvcmtmbG93RGVmaW5pdGlvbklkKTtcblxuICAgIHJldHVybiB3b3JrZmxvd0RlZmluaXRpb247XG4gIH1cbn1cblxuZXhwb3J0IGRlZmF1bHQgQlBNRW5naW5lO1xuZXhwb3J0IHsgZGVmYXVsdCBhcyBQbHVnaW5zIH0gZnJvbSAnbGliL1BsdWdpbnMnO1xuIl19