diff --git a/.gitignore b/.gitignore index 6704566..adb2c19 100644 --- a/.gitignore +++ b/.gitignore @@ -80,7 +80,6 @@ typings/ # Nuxt.js build / generate output .nuxt -dist # Gatsby files .cache/ diff --git a/README.md b/README.md index 8175fe5..f6013dd 100644 --- a/README.md +++ b/README.md @@ -12,9 +12,7 @@ This library implements following features: ## Demo -see `./demo` folder - -Regenerate demo using `browserify -r ./lib/kalman-filter.js:KalmanFilter -r ./script/demo/generate-noisy-observation.js:generateNoisyObservation -r ./script/demo/calculate-observation-covariance.js:calculateObservationCovariance > demo/kalman-filter.js` +See a demo in the web browser [here](http://piercus.github.io/kalman-filter) ## Installation diff --git a/demo/bikes.html b/demo/bikes.html index 898804f..c98fcca 100644 --- a/demo/bikes.html +++ b/demo/bikes.html @@ -3,85 +3,7 @@ Kalman Filter Demo on Bike Image - + @@ -97,53 +19,59 @@

Correction

+
+ + + + + - - - - - + + + + + + +
- - - - - - - + + - diff --git a/demo/dist/demo.js b/demo/dist/demo.js new file mode 100644 index 0000000..0a1b584 --- /dev/null +++ b/demo/dist/demo.js @@ -0,0 +1,1619 @@ +require=(function(){function r(e,n,t){function o(i,f){if(!n[i]){if(!e[i]){var c="function"==typeof require&&require;if(!f&&c)return c(i,!0);if(u)return u(i,!0);var a=new Error("Cannot find module '"+i+"'");throw a.code="MODULE_NOT_FOUND",a}var p=n[i]={exports:{}};e[i][0].call(p.exports,function(r){var n=e[i][1][r];return o(n||r)},p,p.exports,r,e,n,t)}return n[i].exports}for(var u="function"==typeof require&&require,i=0;i> | ObservationCallback} stateProjection, +* @property {Array.Array.> | ObservationCallback} covariance +*/ + +/** +* @callback DynamicCallback +* @param {Object} opts +* @param {Number} opts.index +* @param {State} opts.predicted +* @param {Observation} opts.observation +*/ + +/** +* @typedef {Object} DynamicConfig +* @property {Number} dimension +* @property {Array.Array.> | DynamicCallback} transition, +* @property {Array.Array.> | DynamicCallback} covariance +*/ + +const defaultLogger = { + info: (...args) => console.log(...args), + debug: () => {}, + warn: (...args) => console.log(...args), + error: (...args) => console.log(...args) +}; + +/** +* @class +* @property {DynamicConfig} dynamic the system's dynamic model +* @property {ObservationConfig} observation the system's observation model +*@property logger a Winston-like logger +*/ +class CoreKalmanFilter { + /** + * @param {DynamicConfig} dynamic + * @param {ObservationConfig} observation the system's observation model + */ + + constructor({dynamic, observation, logger = defaultLogger}) { + this.dynamic = dynamic; + this.observation = observation; + this.logger = logger; + } + + getValue(fn, options) { + return (typeof (fn) === 'function' ? fn(options) : fn); + } + + getInitState() { + const {mean: meanInit, covariance: covarianceInit, index: indexInit} = this.dynamic.init; + const initState = new State({ + mean: meanInit, + covariance: covarianceInit, + index: indexInit}); + return initState; + } + + /** + This will return the predicted covariance of a given previousCorrected State, this will help us to build the asymptoticState. + * @param {State} previousCorrected + * @returns{Array.>} + */ + + getPredictedCovariance({previousCorrected} = {}) { + previousCorrected = previousCorrected || this.getInitState(); + + const getValueOptions = {previousCorrected, index: previousCorrected.index}; + const d = this.getValue(this.dynamic.transition, getValueOptions); + const dTransposed = transpose(d); + const covarianceInter = matMul(d, previousCorrected.covariance); + const covariancePrevious = matMul(covarianceInter, dTransposed); + const dynCov = this.getValue(this.dynamic.covariance, getValueOptions); + + const covariance = add( + dynCov, + covariancePrevious + ); + return covariance; + } + + /** + This will return the new prediction, relatively to the dynamic model chosen + * @param {State} previousCorrected State relative to our dynamic model + * @returns{State} predicted State + */ + + predict({previousCorrected} = {}) { + previousCorrected = previousCorrected || this.getInitState(); + + State.check(previousCorrected, {dimension: this.dynamic.dimension}); + + const getValueOptions = {previousCorrected, index: previousCorrected.index}; + const d = this.getValue(this.dynamic.transition, getValueOptions); + + const mean = matMul(d, previousCorrected.mean); + + const covariance = this.getPredictedCovariance({previousCorrected}); + let index; + if (typeof (previousCorrected.index) === 'number') { + index = previousCorrected.index + 1; + } + else { + index = null; + } + + const predicted = new State({mean, covariance, index}); + this.logger.debug('Prediction done', predicted); + return predicted; + } + /** + This will return the new correction, taking into account the prediction made + and the observation of the sensor + * @param {State} predicted the previous State + * @returns{Array} kalmanGain + */ + + getGain({predicted, stateProjection}) { + const getValueOptions = {predicted, index: predicted.index}; + stateProjection = stateProjection || this.getValue(this.observation.stateProjection, getValueOptions); + const obsCovariance = this.getValue(this.observation.covariance, getValueOptions); + const stateProjTransposed = transpose(stateProjection); + const noiselessInnovation = matMul( + matMul(stateProjection, predicted.covariance), + stateProjTransposed + ); + const innovationCovariance = add(noiselessInnovation, obsCovariance); + const optimalKalmanGain = matMul( + matMul(predicted.covariance, stateProjTransposed), + invert(innovationCovariance) + ); + return optimalKalmanGain; + } + + /** + This will return the corrected covariance of a given predicted State, this will help us to build the asymptoticState. + * @param {State} predicted the previous State + * @returns{Array.>} + */ + + getCorrectedCovariance({predicted}) { + const getValueOptions = {predicted, index: predicted.index}; + const identity = getIdentity(predicted.covariance.length); + const stateProj = this.getValue(this.observation.stateProjection, getValueOptions); + const optimalKalmanGain = this.getGain({predicted, stateProjection: stateProj}); + return matMul( + sub(identity, matMul(optimalKalmanGain, stateProj)), + predicted.covariance + ); + } + + /** + This will return the new correction, taking into account the prediction made + and the observation of the sensor + * @param {State} predicted the previous State + * @param {Array} observation the observation of the sensor + * @returns{State} corrected State of the Kalman Filter + */ + + correct({predicted, observation}) { + State.check(predicted, {dimension: this.dynamic.dimension}); + if (!observation) { + throw (new Error('no measure available')); + } + + const getValueOptions = {predicted, index: predicted.index}; + const stateProj = this.getValue(this.observation.stateProjection, getValueOptions); + + const optimalKalmanGain = this.getGain({predicted, stateProjection: stateProj}); + const innovation = sub( + observation, + matMul(stateProj, predicted.mean) + ); + const mean = add( + predicted.mean, + matMul(optimalKalmanGain, innovation) + ); + if(isNaN(mean[0][0])){ + throw(new Error('Mean is NaN after correction')) + } + + const covariance = this.getCorrectedCovariance({predicted}); + const corrected = new State({mean, covariance, index: predicted.index}); + this.logger.debug('Correction done', corrected); + return corrected; + } +} + +module.exports = CoreKalmanFilter; + +},{"../lib/linalgebra/add.js":14,"../lib/linalgebra/identity.js":18,"../lib/linalgebra/invert.js":19,"../lib/linalgebra/mat-mul.js":20,"../lib/linalgebra/sub.js":22,"../lib/linalgebra/transpose.js":25,"./state.js":33}],10:[function(require,module,exports){ +const identity = require('../linalgebra/identity.js'); + +/** +*Creates a dynamic model, following constant acceleration model with respect with the dimensions provided in the observation parameters +* @param {DynamicConfig} dynamic +* @param {ObservationConfig} observation +* @returns {DynamicConfig} +*/ + +module.exports = function (dynamic, observation) { + const timeStep = dynamic.timeStep || 1; + const observedProjection = observation.observedProjection; + const stateProjection = observation.stateProjection; + const observationDimension = observation.dimension; + let dimension; + + if (stateProjection && Number.isInteger(stateProjection[0].length / 3)) { + dimension = observation.stateProjection[0].length; + } else if (observedProjection) { + dimension = observedProjection[0].length * 3; + } else if (observationDimension) { + dimension = observationDimension * 3; + } else { + throw (new Error('observedProjection or stateProjection should be defined in observation in order to use constant-speed filter')); + } + + const baseDimension = dimension / 3; + // We construct the transition and covariance matrices + const transition = identity(dimension); + for (let i = 0; i < baseDimension; i++) { + transition[i][i + baseDimension] = timeStep; + transition[i][i + (2 * baseDimension)] = 0.5 * (timeStep ** 2); + transition[i + baseDimension][i + (2 * baseDimension)] = timeStep; + } + + const arrayCovariance = new Array(baseDimension).fill(1) + .concat(new Array(baseDimension).fill(timeStep * timeStep)) + .concat(new Array(baseDimension).fill(timeStep ** 4)); + const covariance = dynamic.covariance || arrayCovariance; + return Object.assign({}, dynamic, {dimension, transition, covariance}); +}; + +},{"../linalgebra/identity.js":18}],11:[function(require,module,exports){ +const identity = require('../linalgebra/identity.js'); +/** +*Creates a dynamic model, following constant position model with respect with the dimensions provided in the observation parameters +* @param {DynamicConfig} dynamic +* @param {ObservationConfig} observation +* @returns {DynamicConfig} +*/ + +module.exports = function (dynamic, observation) { + let dimension = dynamic.dimension; + const observationDimension = observation.dimension; + const observedProjection = observation.observedProjection; + const stateProjection = observation.stateProjection; + let covariance = dynamic.covariance; + + if (!dynamic.dimension) { + if (observationDimension) { + dimension = observationDimension; + } else if (observedProjection) { + dimension = observedProjection[0].length; + } else if (stateProjection) { + dimension = stateProjection[0].length; + } + } + + const transition = identity(dimension); + covariance = covariance || identity(dimension); + return Object.assign({}, dynamic, {dimension, transition, covariance}); +}; + +},{"../linalgebra/identity.js":18}],12:[function(require,module,exports){ +const identity = require('../linalgebra/identity.js'); + +/** +*Creates a dynamic model, following constant position model with respect with the dimensions provided in the observation parameters +* @param {DynamicConfig} dynamic +* @param {ObservationConfig} observation +* @returns {DynamicConfig} +*/ + +module.exports = function (dynamic, observation) { + const timeStep = dynamic.timeStep || 1; + const observedProjection = observation.observedProjection; + const stateProjection = observation.stateProjection; + const observationDimension = observation.dimension; + let dimension; + + if (stateProjection && Number.isInteger(stateProjection[0].length / 2)) { + dimension = observation.stateProjection[0].length; + } else if (observedProjection) { + dimension = observedProjection[0].length * 2; + } else if (observationDimension) { + dimension = observationDimension * 2; + } else { + throw (new Error('observedProjection or stateProjection should be defined in observation in order to use constant-speed filter')); + } + + const baseDimension = dimension / 2; + // We construct the transition and covariance matrices + const transition = identity(dimension); + for (let i = 0; i < baseDimension; i++) { + transition[i][i + baseDimension] = timeStep; + } + + const arrayCovariance = new Array(baseDimension).fill(1).concat(new Array(baseDimension).fill(timeStep * timeStep)); + const covariance = dynamic.covariance || arrayCovariance; + return Object.assign({}, dynamic, {dimension, transition, covariance}); +}; + +},{"../linalgebra/identity.js":18}],13:[function(require,module,exports){ +const CoreKalmanFilter = require('./core-kalman-filter.js'); + +const arrayToMatrix = require('../lib/utils/array-to-matrix.js'); +const setDimensions = require('../lib/setup/set-dimensions.js'); +const checkDimensions = require('../lib/setup/check-dimensions.js'); +const buildStateProjection = require('../lib/setup/build-state-projection.js'); +const extendDynamicInit = require('../lib/setup/extend-dynamic-init.js'); +const modelCollection = require('./model-collection.js'); +const toFunction = require('../lib/utils/to-function.js'); +const deepAssign = require('../lib/utils/deep-assign.js'); +const polymorphMatrix = require('../lib/utils/polymorph-matrix.js'); +const State = require('./state.js'); +const distanceMat = require('../lib/linalgebra/distance-mat.js'); + +/** +*This function fills the given options by successively checking if it uses a registered model, +* it builds and checks the dynamic and observation dimensions, build the stateProjection if only observedProjection +*is given, and initialize dynamic.init +*@param {DynamicConfig} options.dynamic +*@param {ObservationConfig} options.observation +*/ + +const setupModelsParameters = function ({observation, dynamic}) { + if (typeof (observation.name) === 'string') { + observation = modelCollection.buildObservation(observation); + } + + if (typeof (dynamic.name) === 'string') { + dynamic = modelCollection.buildDynamic(dynamic, observation); + } + + const withDimensionOptions = setDimensions({observation, dynamic}); + const checkedDimensionOptions = checkDimensions(withDimensionOptions); + const buildStateProjectionOptions = buildStateProjection(checkedDimensionOptions); + return extendDynamicInit(buildStateProjectionOptions); +}; + +/** +*Returns the corresponding model without arrays as values but only functions +*@param {ObservationConfig} observation +*@param {DynamicConfig} dynamic +*@returns {ObservationConfig, DynamicConfig} model with respect of the Core Kalman Filter properties +*/ +const modelsParametersToCoreOptions = function (modelToBeChanged) { + const {observation, dynamic} = modelToBeChanged; + return deepAssign(modelToBeChanged, { + observation: { + stateProjection: toFunction(polymorphMatrix(observation.stateProjection)), + covariance: toFunction(polymorphMatrix(observation.covariance, {dimension: observation.dimension})) + }, + dynamic: { + transition: toFunction(polymorphMatrix(dynamic.transition)), + covariance: toFunction(polymorphMatrix(dynamic.covariance, {dimension: dynamic.dimension})) + } + }); +}; + +class KalmanFilter extends CoreKalmanFilter { + /** + * @param {DynamicConfig} options.dynamic + * @param {ObservationConfig} options.observation the system's observation model + */ + constructor(options) { + const modelsParameters = setupModelsParameters(options); + const coreOptions = modelsParametersToCoreOptions(modelsParameters); + + super(Object.assign({}, options, coreOptions)); + } + + correct({predicted, observation}) { + const coreObservation = arrayToMatrix({observation, dimension: this.observation.dimension}); + return super.correct({predicted, observation: coreObservation}); + } + + /** + *Performs the prediction and the correction steps + *@param {State} previousCorrected + *@param {>} observation + *@returns {Array.} the mean of the corrections + */ + + filter({previousCorrected, observation}) { + const predicted = super.predict({previousCorrected}); + return this.correct({predicted, observation}); + } + + /** +*Filters all the observations +*@param {Array.>} observations +*@returns {Array.} the mean of the corrections +*/ + filterAll(observations) { + const {mean: meanInit, covariance: covarianceInit, index: indexInit} = this.dynamic.init; + let previousCorrected = new State({ + mean: meanInit, + covariance: covarianceInit, + index: indexInit}); + const results = []; + for (const observation of observations) { + const predicted = this.predict({previousCorrected}); + previousCorrected = this.correct({ + predicted, + observation + }); + results.push(previousCorrected.mean); + } + + return results; + } + + /** + * Returns an estimation of the asymptotic state covariance as explained in https://en.wikipedia.org/wiki/Kalman_filter#Asymptotic_form + * in practice this can be used as a init.covariance value but is very costful calculation (that's why this is not made by default) + * @param {Number} [tolerance=1e-6] returns when the last values differences are less than tolerance + * @return {>>} covariance + */ + asymptoticStateCovariance(limitIterations = 1e2, tolerance = 1e-6) { + let previousCorrected = super.getInitState(); + let predicted; + const results = []; + for (let i = 0; i < limitIterations; i++) { + let count = 0; + predicted = new State({covariance: super.getPredictedCovariance({previousCorrected})}); + previousCorrected = new State({covariance: super.getCorrectedCovariance({predicted})}); + results.push(previousCorrected.covariance); + for (let j = 1; j < 4; j++) { + if (distanceMat(previousCorrected.covariance, results[i - j]) < tolerance) { + count += 1; + } + } + + if (count === 3) { + return results[i]; + } + } + + throw (new Error('The state covariance does not converge asymptotically')); + } + + /** + * Returns an estimation of the asymptotic gain, as explained in https://en.wikipedia.org/wiki/Kalman_filter#Asymptotic_form + * @param {Number} [tolerance=1e-6] returns when the last values differences are less than tolerance + * @return {>>} gain + */ + asymptoticGain(tolerance = 1e-6) { + const asymptoticState = new State({covariance: this.asymptoticStateCovariance(tolerance)}); + return super.getGain({previousCorrected: asymptoticState}); + } +} + +module.exports = KalmanFilter; + +},{"../lib/linalgebra/distance-mat.js":16,"../lib/setup/build-state-projection.js":29,"../lib/setup/check-dimensions.js":30,"../lib/setup/extend-dynamic-init.js":31,"../lib/setup/set-dimensions.js":32,"../lib/utils/array-to-matrix.js":34,"../lib/utils/deep-assign.js":35,"../lib/utils/polymorph-matrix.js":36,"../lib/utils/to-function.js":37,"./core-kalman-filter.js":9,"./model-collection.js":27,"./state.js":33}],14:[function(require,module,exports){ +const elemWise = require('./elem-wise'); +/** +* Add matrixes together +* @param {...>} args list of matrix +* @returns {Array.>} sum +*/ +module.exports = function (...args) { + return elemWise(args, args2 => { + return args2.reduce((a, b) => a + b, 0); + }); +}; + +},{"./elem-wise":17}],15:[function(require,module,exports){ +const zeros = require('./zeros'); + +module.exports = function (mat) { + const result = zeros(mat.length, mat.length); + + for (const [i, element] of mat.entries()) { + result[i][i] = element; + } + + return result; +}; + +},{"./zeros":26}],16:[function(require,module,exports){ +const trace = require('./trace.js'); +const transpose = require('./transpose.js'); +const matSub = require('./sub.js'); +const matMul = require('./mat-mul.js'); +const sum = require('./sum.js'); + +// [Frobenius norm](https://en.wikipedia.org/wiki/Matrix_norm#Frobenius_norm ) +module.exports = function (array1, array2) { + if (typeof (array1) === 'undefined') { + return sum(array2); + } + + if (typeof (array2) === 'undefined') { + return sum(array1); + } + + const m = matSub(array1, array2); + const p = matMul(transpose(m), m); + return Math.sqrt(trace(p)); +}; + +},{"./mat-mul.js":20,"./sub.js":22,"./sum.js":23,"./trace.js":24,"./transpose.js":25}],17:[function(require,module,exports){ +/** +* @callback elemWiseCb +* @param {Array.} arr +* @param {Number} rowId +* @param {Number} colId +*/ +/** +* run a function on cell per cell for each Matrixes +* @param {>>} arrMatrixes list of matrixes +* @param {elemWiseCb} fn +* @returns {Array.>} resulting matrix +* @example +// this will do m1 + m2 + m3 + m4 on matrixes +elemWise([m1, m2, m3, m4], args2 => { + return args2.reduce((a, b) => a + b, 0); +}); +*/ + +module.exports = function (arrayMatrixes, fn) { + return arrayMatrixes[0].map((row, rowId) => { + return row.map((cell, colId) => { + const array = arrayMatrixes.map(m => m[rowId][colId]); + return fn(array, rowId, colId); + }); + }); +}; + + +},{}],18:[function(require,module,exports){ +module.exports = function (stateSize) { + const identityArray = []; + for (let i = 0; i < stateSize; i++) { + const rowIdentity = []; + for (let j = 0; j < stateSize; j++) { + if (i === j) { + rowIdentity.push(1); + } else { + rowIdentity.push(0); + } + } + + identityArray.push(rowIdentity); + } + + return identityArray; +}; + +},{}],19:[function(require,module,exports){ +const matrixInverse = require('matrix-inverse'); + +module.exports = function (m) { + return matrixInverse(m); +}; + +},{"matrix-inverse":39}],20:[function(require,module,exports){ +/** +* Multiply 2 matrixes together +* @param {>} m1 +* @param {>} m2 +* @returns {Array.>} +*/ +module.exports = function (m1, m2) { + // Console.log({m1, m2}); + const result = []; + for (let i = 0; i < m1.length; i++) { + result[i] = []; + for (let j = 0; j < m2[0].length; j++) { + let sum = 0; + for (let k = 0; k < m1[0].length; k++) { + sum += m1[i][k] * m2[k][j]; + } + + result[i][j] = sum; + } + } + + return result; +}; + +},{}],21:[function(require,module,exports){ +/** +*This function returns the stateProjection paded with zeros with respect to a given +*observedProjection +*@param {Array. | Array.>} array the array we need to pad +*@param {Number} dimension in our case, the dynamic dimension +*@returns {Array. | Array.>} paded array +*/ +module.exports = function (array, {dimension}) { + const l = array[0].length; + if (dimension < l) { + throw (new TypeError('Dynamic dimension does not match with observedProjection')); + } + + for (let i = 0; i < l; i++) { + for (let j = 0; j < dimension - l; j++) { + array[i].push(0); + } + } + + return array; +}; + +},{}],22:[function(require,module,exports){ +const elemWise = require('./elem-wise'); + +module.exports = function (...args) { + return elemWise(args, ([a, b]) => a - b); +}; + +},{"./elem-wise":17}],23:[function(require,module,exports){ +// Sum all the terms of a given matrix +module.exports = function (array) { + let s = 0; + for (let i = 0; i < array.length; i++) { + for (let j = 0; j < array.length; j++) { + s += array[i][j]; + } + } + + return s; +}; + +},{}],24:[function(require,module,exports){ +module.exports = function (array) { + let diag = 0; + for (const [row, element] of array.entries()) { + diag += element[row]; + } + + return diag; +}; + +},{}],25:[function(require,module,exports){ +module.exports = function (array) { + return array[0].map((col, i) => array.map(row => row[i])); +}; + +},{}],26:[function(require,module,exports){ +module.exports = function (rows, cols) { + return new Array(rows).fill(1).map(() => new Array(cols).fill(0)); +}; + +},{}],27:[function(require,module,exports){ +const registeredDynamicModels = { + 'constant-position': require('../lib/dynamic/constant-position.js'), + 'constant-speed': require('../lib/dynamic/constant-speed.js'), + 'constant-acceleration': require('../lib/dynamic/constant-acceleration.js') +}; +const registeredObservationModels = { + sensors: require('../lib/observation/sensor.js') +}; + +/** +*RegisterObservation enables to create a new observation model and stock it +* @param {String} name +* @callback fn the function corresponding to the desired model +*/ + +/** +*registerDynamic enables to create a new dynamic model and stocks it +* @param {String} name +* @callback fn the function corresponding to the desired model +*/ + +/** +*buildObservation enables to build a model given an observation configuration +* @param {ObservationConfig} observation +* @returns {ObservationConfig} the configuration with respect to the model +*/ + +/** +*buildDynamic enables to build a model given dynamic and observation configurations +* @param {DynamicConfig} dynamic +* @param {ObservationConfig} observation +* @returns {DynamicConfig} the dynamic configuration with respect to the model +*/ + +module.exports = { + registerObservation: (name, fn) => { + registeredObservationModels[name] = fn; + }, + registerDynamic: (name, fn) => { + registeredDynamicModels[name] = fn; + }, + buildObservation: observation => { + if (!registeredObservationModels[observation.name]) { + throw (new Error('The provided observation model name is not registered')); + } + + return registeredObservationModels[observation.name](observation); + }, + buildDynamic: (dynamic, observation) => { + if (!registeredDynamicModels[dynamic.name]) { + throw (new Error('The provided dynamic model name is not registered')); + } + + return registeredDynamicModels[dynamic.name](dynamic, observation); + } +}; + +},{"../lib/dynamic/constant-acceleration.js":10,"../lib/dynamic/constant-position.js":11,"../lib/dynamic/constant-speed.js":12,"../lib/observation/sensor.js":28}],28:[function(require,module,exports){ +const identity = require('../linalgebra/identity.js'); +const polymorphMatrix = require('../utils/polymorph-matrix.js'); + +/** +* @param {Number} sensorDimension +* @param {CovarianceParam} sensorCovariance +* @param {Number} nSensors +* @returns {ObservationConfig} +*/ + +module.exports = function (options) { + const {sensorDimension = 1, sensorCovariance = 1, nSensors = 1} = options; + const sensorsCovariance = polymorphMatrix(sensorCovariance, {dimension: sensorDimension}); + const oneSensorObservedProjection = identity(sensorDimension); + let concatenatedObservedProjection = []; + let concatenatedCovariance = []; + for (let i = 0; i < nSensors; i++) { + concatenatedObservedProjection = concatenatedObservedProjection.concat(oneSensorObservedProjection); + concatenatedCovariance = concatenatedCovariance.concat(sensorsCovariance); + } + + const formattedCovariance = polymorphMatrix(concatenatedCovariance, {dimension: nSensors * sensorDimension}); + return Object.assign({}, options, { + dimension: sensorDimension * nSensors, + observedProjection: concatenatedObservedProjection, + covariance: formattedCovariance + }); +}; + +},{"../linalgebra/identity.js":18,"../utils/polymorph-matrix.js":36}],29:[function(require,module,exports){ +const padWithZeros = require('../linalgebra/pad-with-zeros.js'); +const identity = require('../linalgebra/identity.js'); +/** +*Builds the stateProjection given an observedProjection +*@param {ObservationConfig} observation +*@param {DynamicConfig} dynamic +*@returns {ObservationConfig, DynamicConfig} the model containing the created stateProjection +*/ + +module.exports = function ({observation, dynamic}) { + const {observedProjection, stateProjection} = observation; + const observationDimension = observation.dimension; + const dynamicDimension = dynamic.dimension; + if (observedProjection && stateProjection) { + throw (new TypeError('You cannot use both observedProjection and stateProjection')); + } + + if (observedProjection) { + return { + observation: Object.assign({}, observation, { + stateProjection: padWithZeros(observedProjection, {dimension: dynamicDimension}) + }), + dynamic + }; + } + + if (observationDimension && dynamicDimension) { + const observationMatrix = identity(observationDimension); + return { + observation: Object.assign({}, observation, { + stateProjection: padWithZeros(observationMatrix, {dimension: dynamicDimension}) + }), + dynamic + }; + } + + return {observation, dynamic}; +}; + +},{"../linalgebra/identity.js":18,"../linalgebra/pad-with-zeros.js":21}],30:[function(require,module,exports){ +/** +*Verifies that dynamic.dimension and observation.dimension are set +*@param {ObservationConfig} observation +*@param {DynamicConfig} dynamic +*/ + +module.exports = function ({observation, dynamic}) { + const dynamicDimension = dynamic.dimension; + const observationDimension = observation.dimension; + if (!dynamicDimension || !observationDimension) { + throw (new TypeError('Dimension is not set')); + } + + return {observation, dynamic}; +}; + +},{}],31:[function(require,module,exports){ +const diag = require('../linalgebra/diag.js'); + +/** +*Initializes the dynamic.init when not given +*@param {ObservationConfig} observation +*@param {DynamicConfig} dynamic +*@returns {ObservationConfig, DynamicConfig} +*/ + +module.exports = function ({observation, dynamic}) { + if (!dynamic.init) { + const huge = 1e6; + const dynamicDimension = dynamic.dimension; + const meanArray = new Array(dynamicDimension).fill(0); + const covarianceArray = new Array(dynamicDimension).fill(huge); + const withInitOptions = { + observation, + dynamic: Object.assign({}, dynamic, { + init: { + mean: meanArray.map(element => [element]), + covariance: diag(covarianceArray) + } + }) + }; + return withInitOptions; + } + + return {observation, dynamic}; +}; + +},{"../linalgebra/diag.js":15}],32:[function(require,module,exports){ +/** +*Verifies that dimensions are matching and set dynamic.dimension and observation.dimension +* with respect of stateProjection and transition dimensions +*@param {ObservationConfig} observation +*@param {DynamicConfig} dynamic +*@returns {ObservationConfig, DynamicConfig} +*/ + +module.exports = function ({observation, dynamic}) { + const stateProjection = observation.stateProjection; + const transition = dynamic.transition; + const dynamicDimension = dynamic.dimension; + const observationDimension = observation.dimension; + + if (dynamicDimension && observationDimension && Array.isArray(stateProjection)) { + if (dynamicDimension !== stateProjection[0].length || observationDimension !== stateProjection.length) { + throw (new TypeError('stateProjection dimensions not matching with observation and dynamic dimensions')); + } + } + + if (dynamicDimension && Array.isArray(transition)) { + if (dynamicDimension !== transition.length) { + throw (new TypeError('transition dimension not matching with dynamic dimension')); + } + } + + if (Array.isArray(stateProjection)) { + return { + observation: Object.assign({}, observation, { + dimension: stateProjection.length + }), + dynamic: Object.assign({}, dynamic, { + dimension: stateProjection[0].length + }) + }; + } + + if (Array.isArray(transition)) { + return { + observation, + dynamic: Object.assign({}, dynamic, { + dimension: transition.length + }) + }; + } + + return {observation, dynamic}; +}; + +},{}],33:[function(require,module,exports){ +const checkMatrix = function (matrix, shape) { + if (matrix.reduce((a, b) => a.concat(b)).filter(a => Number.isNaN(a)).length > 0) { + throw (new Error('Matrix should not have a NaN')); + } + + if (shape) { + checkShape(matrix, shape); + } +}; + +const checkShape = function (matrix, shape) { + if (matrix.length !== shape[0]) { + throw (new Error('shape and length do not match')); + } + + if (shape.length > 1) { + return matrix.forEach(m => checkShape(m, shape.slice(1))); + } +}; + +/** + * @class + * Class representing a multi dimensionnal gaussian, with his mean and his covariance + * @property {Number} [index=0] the index of the State in the process, this is not mandatory for simple Kalman Filter, but is needed for most of the use case of extended kalman filter + * @property {Array.>} covariance square matrix of size dimension + * @property {Array.>} mean column matrix of size dimension x 1 + */ +class State { + constructor({mean, covariance, index}) { + this.mean = mean; + this.covariance = covariance; + this.index = index; + } + + /** + * Check the consistency of the State + */ + check() { + this.constructor.check(this); + } + + /** + * Check the consistency of the State's attributes + */ + + static check(state, {dimension = null} = {}) { + if (!(state instanceof State)) { + throw (new TypeError('The argument is not a state')); + } + + const {mean, covariance} = state; // Index + const meanDimension = mean.length; + if (typeof (dimension) === 'number' && meanDimension !== dimension) { + throw (new Error(`${meanDimension} and ${dimension} are not the same`)); + } + + checkMatrix(mean, [meanDimension, 1]); + checkMatrix(covariance, [meanDimension, meanDimension]); + + // If (typeof (index) !== 'number') { + // throw (new TypeError('t must be a number')); + // } + } +} + +module.exports = State; + +},{}],34:[function(require,module,exports){ +/** +*Returns the corresponding matrix in dim*1, given an dim matrix, and checks +* if corresponding with the observation dimension +*@param {Array. | Array.>} observation +*@param {Number} dimension +*@returns {Array.>} +*/ + +module.exports = function ({observation, dimension}) { + if (!Array.isArray(observation)) { + throw (new TypeError('The observation should be an array')); + } + + if (observation.length !== dimension) { + throw (new TypeError('Observation and dimension not matching')); + } + + if (typeof (observation[0]) === 'number') { + return observation.map(element => [element]); + } + + return observation; +}; + +},{}],35:[function(require,module,exports){ +const uniq = require('./uniq.js'); +const limit = 100; + +/** +*Equivalent to the Object.assign methode, takes several arguments and creates a new object corresponding to the assignment of the arguments +* @param {Object} args +* @param {Number} step +*/ +const deepAssign = function (args, step) { + if (step > limit) { + throw (new Error(`In deepAssign, number of recursive call (${step}) reached limit (${limit}), deepAssign is not working on self-referencing objects`)); + } + + const filterArguments = args.filter(arg => typeof (arg) !== 'undefined' && arg !== null); + const lastArgument = filterArguments[filterArguments.length - 1]; + if (filterArguments.length === 1) { + return filterArguments[0]; + } + + if (typeof (lastArgument) !== 'object' || Array.isArray(lastArgument)) { + return lastArgument; + } + + if (filterArguments.length === 0) { + return null; + } + + const objectsArguments = filterArguments.filter(arg => typeof (arg) === 'object'); + let keys = []; + objectsArguments.forEach(arg => { + keys = keys.concat(Object.keys(arg)); + }); + const uniqKeys = uniq(keys); + const result = {}; + uniqKeys.forEach(key => { + const values = objectsArguments.map(arg => arg[key]); + result[key] = deepAssign(values, step + 1); + }); + return result; +}; + +module.exports = ((...args) => deepAssign(args, 0)); + +},{"./uniq.js":38}],36:[function(require,module,exports){ +/** +* @typedef {Number | Array. | Array.>} CovarianceParam +*/ +const diag = require('../linalgebra/diag'); +/** +* If cov is a number, result will be Identity*cov +* If cov is an Array., result will be diag(cov) +* If cov is an Array.>, result will be cov +* @param {CovarianceParam} cov +* @param {Number} dimension +* @returns {Array.>} +*/ +module.exports = function (array, {dimension} = {}) { + if (typeof (array) === 'number' || Array.isArray(array)) { + if (typeof (array) === 'number' && typeof (dimension) === 'number') { + return diag(new Array(dimension).fill(array)); + } + + if ((Array.isArray(array)) && (Array.isArray(array[0]))) { + return array; + } + + if ((Array.isArray(array)) && (typeof (array[0]) === 'number')) { + return diag(array); + } + } + + return array; +}; + +},{"../linalgebra/diag":15}],37:[function(require,module,exports){ +// Const diag = require('../linalgebra/diag.js'); + +/** +* @callback MatrixCallback +* @returns > +*/ + +/** +* Tranforms: +** a 2d array into a function (() => array) +** a 1d array into a function (() => diag(array)) +*@param {Array. | Array.>} array +*@returns {MatrixCallback} +*/ + +module.exports = function (array) { + if (typeof (array) === 'function') { + return array; + } + + if (Array.isArray(array)) { + return function () { + return array; + }; + } + + throw (new Error('Only arrays and functions are authorized')); +}; + +},{}],38:[function(require,module,exports){ +module.exports = function (array) { + return array.filter((value, index) => + array.indexOf(value) === index + ); +}; + +},{}],39:[function(require,module,exports){ +var Sylvester = {} + +Sylvester.Matrix = function() {} + +Sylvester.Matrix.create = function(elements) { + var M = new Sylvester.Matrix() + return M.setElements(elements) +} + +Sylvester.Matrix.I = function(n) { + var els = [], + i = n, + j + while (i--) { + j = n + els[i] = [] + while (j--) { + els[i][j] = i === j ? 1 : 0 + } + } + return Sylvester.Matrix.create(els) +} + +Sylvester.Matrix.prototype = { + dup: function() { + return Sylvester.Matrix.create(this.elements) + }, + + isSquare: function() { + var cols = this.elements.length === 0 ? 0 : this.elements[0].length + return this.elements.length === cols + }, + + toRightTriangular: function() { + if (this.elements.length === 0) return Sylvester.Matrix.create([]) + var M = this.dup(), + els + var n = this.elements.length, + i, + j, + np = this.elements[0].length, + p + for (i = 0; i < n; i++) { + if (M.elements[i][i] === 0) { + for (j = i + 1; j < n; j++) { + if (M.elements[j][i] !== 0) { + els = [] + for (p = 0; p < np; p++) { + els.push(M.elements[i][p] + M.elements[j][p]) + } + M.elements[i] = els + break + } + } + } + if (M.elements[i][i] !== 0) { + for (j = i + 1; j < n; j++) { + var multiplier = M.elements[j][i] / M.elements[i][i] + els = [] + for (p = 0; p < np; p++) { + // Elements with column numbers up to an including the number of the + // row that we're subtracting can safely be set straight to zero, + // since that's the point of this routine and it avoids having to + // loop over and correct rounding errors later + els.push( + p <= i ? 0 : M.elements[j][p] - M.elements[i][p] * multiplier + ) + } + M.elements[j] = els + } + } + } + return M + }, + + determinant: function() { + if (this.elements.length === 0) { + return 1 + } + if (!this.isSquare()) { + return null + } + var M = this.toRightTriangular() + var det = M.elements[0][0], + n = M.elements.length + for (var i = 1; i < n; i++) { + det = det * M.elements[i][i] + } + return det + }, + + isSingular: function() { + return this.isSquare() && this.determinant() === 0 + }, + + augment: function(matrix) { + if (this.elements.length === 0) { + return this.dup() + } + var M = matrix.elements || matrix + if (typeof M[0][0] === 'undefined') { + M = Sylvester.Matrix.create(M).elements + } + var T = this.dup(), + cols = T.elements[0].length + var i = T.elements.length, + nj = M[0].length, + j + if (i !== M.length) { + return null + } + while (i--) { + j = nj + while (j--) { + T.elements[i][cols + j] = M[i][j] + } + } + return T + }, + + inverse: function() { + if (this.elements.length === 0) { + return null + } + if (!this.isSquare() || this.isSingular()) { + return null + } + var n = this.elements.length, + i = n, + j + var M = this.augment(Sylvester.Matrix.I(n)).toRightTriangular() + var np = M.elements[0].length, + p, + els, + divisor + var inverse_elements = [], + new_element + // Sylvester.Matrix is non-singular so there will be no zeros on the + // diagonal. Cycle through rows from last to first. + while (i--) { + // First, normalise diagonal elements to 1 + els = [] + inverse_elements[i] = [] + divisor = M.elements[i][i] + for (p = 0; p < np; p++) { + new_element = M.elements[i][p] / divisor + els.push(new_element) + // Shuffle off the current row of the right hand side into the results + // array as it will not be modified by later runs through this loop + if (p >= n) { + inverse_elements[i].push(new_element) + } + } + M.elements[i] = els + // Then, subtract this row from those above it to give the identity matrix + // on the left hand side + j = i + while (j--) { + els = [] + for (p = 0; p < np; p++) { + els.push(M.elements[j][p] - M.elements[i][p] * M.elements[j][i]) + } + M.elements[j] = els + } + } + return Sylvester.Matrix.create(inverse_elements) + }, + + setElements: function(els) { + var i, + j, + elements = els.elements || els + if (elements[0] && typeof elements[0][0] !== 'undefined') { + i = elements.length + this.elements = [] + while (i--) { + j = elements[i].length + this.elements[i] = [] + while (j--) { + this.elements[i][j] = elements[i][j] + } + } + return this + } + var n = elements.length + this.elements = [] + for (i = 0; i < n; i++) { + this.elements.push([elements[i]]) + } + return this + }, +} + +module.exports = function(elements) { + return Sylvester.Matrix.create(elements).inverse().elements +} + +},{}],"main":[function(require,module,exports){ +const KalmanFilter = require('../../lib/kalman-filter'); + +const noisyObservations = require('./observations.json').observations; +const kfOptions = require('./kf-options.js'); +const createElement = require('./views/create-element'); +const createGroupBoxes = require('./views/create-group-boxes'); + +const kf = new KalmanFilter(kfOptions); +let predicted = kf.predict(); + +const img = document.querySelector('#bikes');// eslint-disable-line no-undef + +// Create all the elements of the prediction or correction phase +const delay = 100; + +let promise = Promise.resolve(); +let previousCorrected = null; + +const delayPromise = delay => new Promise(resolve => setTimeout(resolve, delay)); + +module.exports = { + run(){ + noisyObservations.forEach((box, index) => { + promise = promise + .then(() => { + predicted = kf.predict({previousCorrected}); + const {mean, covariance} = predicted; + + createGroupBoxes({mean, covariance, parent: img, className: 'predicted', color: 'blue'}); + + return delayPromise(delay); + }) + .then((b => { + createElement({ + className: 'observation', + bbox: [ + b[0] + (b[2] / 2), + b[1] + (b[3] / 2), + b[2], + b[3] + ], + parent: img, + color: 'white', + lineStyle: 'solid' + }); + + return delayPromise(delay); + }).bind(null, box, index)) + .then((b => { + previousCorrected = kf.correct({predicted, observation: b}); + const {mean, covariance} = previousCorrected; + + createGroupBoxes({mean, covariance, parent: img, className: 'corrected', color: 'red'}); + + return delayPromise(delay); + }).bind(null, box, index)); + }) + } +} + + +},{"../../lib/kalman-filter":13,"./kf-options.js":1,"./observations.json":3,"./views/create-element":6,"./views/create-group-boxes":7}]},{},[]) +//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uLy4uLy5udm0vdmVyc2lvbnMvbm9kZS92MTIuMTguMC9saWIvbm9kZV9tb2R1bGVzL2Jyb3dzZXJpZnkvbm9kZV9tb2R1bGVzL2Jyb3dzZXItcGFjay9fcHJlbHVkZS5qcyIsImRlbW8vc3JjL2tmLW9wdGlvbnMuanMiLCJkZW1vL3NyYy9vYnNlcnZhdGlvbi1jb3ZhcmlhbmNlLmpzb24iLCJkZW1vL3NyYy9vYnNlcnZhdGlvbnMuanNvbiIsImRlbW8vc3JjL3ZpZXdzL2NyZWF0ZS1hcnJvdy5qcyIsImRlbW8vc3JjL3ZpZXdzL2NyZWF0ZS1jdXN0b20tZGFzaGVkLWxpbmUuanMiLCJkZW1vL3NyYy92aWV3cy9jcmVhdGUtZWxlbWVudC5qcyIsImRlbW8vc3JjL3ZpZXdzL2NyZWF0ZS1ncm91cC1ib3hlcy5qcyIsImRlbW8vc3JjL3ZpZXdzL2NyZWF0ZS1wb2ludC5qcyIsImxpYi9jb3JlLWthbG1hbi1maWx0ZXIuanMiLCJsaWIvZHluYW1pYy9jb25zdGFudC1hY2NlbGVyYXRpb24uanMiLCJsaWIvZHluYW1pYy9jb25zdGFudC1wb3NpdGlvbi5qcyIsImxpYi9keW5hbWljL2NvbnN0YW50LXNwZWVkLmpzIiwibGliL2thbG1hbi1maWx0ZXIuanMiLCJsaWIvbGluYWxnZWJyYS9hZGQuanMiLCJsaWIvbGluYWxnZWJyYS9kaWFnLmpzIiwibGliL2xpbmFsZ2VicmEvZGlzdGFuY2UtbWF0LmpzIiwibGliL2xpbmFsZ2VicmEvZWxlbS13aXNlLmpzIiwibGliL2xpbmFsZ2VicmEvaWRlbnRpdHkuanMiLCJsaWIvbGluYWxnZWJyYS9pbnZlcnQuanMiLCJsaWIvbGluYWxnZWJyYS9tYXQtbXVsLmpzIiwibGliL2xpbmFsZ2VicmEvcGFkLXdpdGgtemVyb3MuanMiLCJsaWIvbGluYWxnZWJyYS9zdWIuanMiLCJsaWIvbGluYWxnZWJyYS9zdW0uanMiLCJsaWIvbGluYWxnZWJyYS90cmFjZS5qcyIsImxpYi9saW5hbGdlYnJhL3RyYW5zcG9zZS5qcyIsImxpYi9saW5hbGdlYnJhL3plcm9zLmpzIiwibGliL21vZGVsLWNvbGxlY3Rpb24uanMiLCJsaWIvb2JzZXJ2YXRpb24vc2Vuc29yLmpzIiwibGliL3NldHVwL2J1aWxkLXN0YXRlLXByb2plY3Rpb24uanMiLCJsaWIvc2V0dXAvY2hlY2stZGltZW5zaW9ucy5qcyIsImxpYi9zZXR1cC9leHRlbmQtZHluYW1pYy1pbml0LmpzIiwibGliL3NldHVwL3NldC1kaW1lbnNpb25zLmpzIiwibGliL3N0YXRlLmpzIiwibGliL3V0aWxzL2FycmF5LXRvLW1hdHJpeC5qcyIsImxpYi91dGlscy9kZWVwLWFzc2lnbi5qcyIsImxpYi91dGlscy9wb2x5bW9ycGgtbWF0cml4LmpzIiwibGliL3V0aWxzL3RvLWZ1bmN0aW9uLmpzIiwibGliL3V0aWxzL3VuaXEuanMiLCJub2RlX21vZHVsZXMvbWF0cml4LWludmVyc2UvbWF0cml4LWludmVyc2UuanMiLCJkZW1vL3NyYy9tYWluLmpzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBO0FDQUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDNURBOztBQ0FBOztBQ0FBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDaEJBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ25EQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNsQkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3RGQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDZEE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzlNQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDekNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUM3QkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNyQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUN2SkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ1hBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNYQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDcEJBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzNCQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDakJBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNMQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDdkJBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3JCQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDTEE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ1hBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNSQTtBQUNBO0FBQ0E7QUFDQTs7QUNIQTtBQUNBO0FBQ0E7QUFDQTs7QUNIQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDeERBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDNUJBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUN0Q0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDZkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzdCQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNoREE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDbEVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUN2QkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDMUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUM3QkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUM1QkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ0xBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDcE1BO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBIiwiZmlsZSI6ImdlbmVyYXRlZC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzQ29udGVudCI6WyIoZnVuY3Rpb24oKXtmdW5jdGlvbiByKGUsbix0KXtmdW5jdGlvbiBvKGksZil7aWYoIW5baV0pe2lmKCFlW2ldKXt2YXIgYz1cImZ1bmN0aW9uXCI9PXR5cGVvZiByZXF1aXJlJiZyZXF1aXJlO2lmKCFmJiZjKXJldHVybiBjKGksITApO2lmKHUpcmV0dXJuIHUoaSwhMCk7dmFyIGE9bmV3IEVycm9yKFwiQ2Fubm90IGZpbmQgbW9kdWxlICdcIitpK1wiJ1wiKTt0aHJvdyBhLmNvZGU9XCJNT0RVTEVfTk9UX0ZPVU5EXCIsYX12YXIgcD1uW2ldPXtleHBvcnRzOnt9fTtlW2ldWzBdLmNhbGwocC5leHBvcnRzLGZ1bmN0aW9uKHIpe3ZhciBuPWVbaV1bMV1bcl07cmV0dXJuIG8obnx8cil9LHAscC5leHBvcnRzLHIsZSxuLHQpfXJldHVybiBuW2ldLmV4cG9ydHN9Zm9yKHZhciB1PVwiZnVuY3Rpb25cIj09dHlwZW9mIHJlcXVpcmUmJnJlcXVpcmUsaT0wO2k8dC5sZW5ndGg7aSsrKW8odFtpXSk7cmV0dXJuIG99cmV0dXJuIHJ9KSgpIiwiY29uc3Qgb2JzZXJ2YXRpb25Db3ZhcmlhbmNlID0gcmVxdWlyZSgnLi9vYnNlcnZhdGlvbi1jb3ZhcmlhbmNlLmpzb24nKTtcbmNvbnN0IHBvc1ZhciA9IDEwMDtcbmNvbnN0IHRpbWVTdGVwID0gMC4yO1xuY29uc3Qgc2l6ZVZhciA9IDE7XG5cbm1vZHVsZS5leHBvcnRzID0ge1xuXHRvYnNlcnZhdGlvbjoge1xuXHRcdGRpbWVuc2lvbjogNCxcblx0XHRzdGF0ZVByb2plY3Rpb246IFtcblx0XHRcdFsxLCAwLCAwLCAwLCAwLCAwLCAwLCAwLCAwLCAwLCAwLCAwXSxcblx0XHRcdFswLCAxLCAwLCAwLCAwLCAwLCAwLCAwLCAwLCAwLCAwLCAwXSxcblx0XHRcdFswLCAwLCAxLCAwLCAwLCAwLCAwLCAwLCAwLCAwLCAwLCAwXSxcblx0XHRcdFswLCAwLCAwLCAxLCAwLCAwLCAwLCAwLCAwLCAwLCAwLCAwXVxuXHRcdF0sXG5cdFx0Ly8gQ292YXJpYW5jZSBnZW5lcmF0ZWQgdGhhbmtzIHRvIGdldENvdmFyaWFuY2Vcblx0XHRjb3ZhcmlhbmNlOiBvYnNlcnZhdGlvbkNvdmFyaWFuY2Vcblx0XHQvLyBDb3ZhcmlhbmNlOiBbcG9zVmFyLCBwb3NWYXIsIHBvc1ZhciwgcG9zVmFyXSxcblxuXHR9LFxuXG5cdGR5bmFtaWM6IHtcblx0XHRuYW1lOiAnY29uc3RhbnQtYWNjZWxlcmF0aW9uJyxcblx0XHR0aW1lU3RlcDogMC4yLFxuXHRcdC8vIEluaXQ6IHtcblx0XHQvLyBcdG1lYW46IFtbOTQzXSwgWzM4NV0sIFs3NV0sIFs2NV0sIFstMjAwXSwgWy0yMDBdLCBbMF0sIFswXSwgWy0yMF0sIFstMjBdLCBbMF0sIFswXV0sXG5cdFx0Ly9cblx0XHQvLyBcdGNvdmFyaWFuY2U6IFtcblx0XHQvLyBcdFx0W2h1Z2UsIDAsIDAsIDAsIDAsIDAsIDAsIDAsIDAsIDAsIDAsIDBdLFxuXHRcdC8vIFx0XHRbMCwgaHVnZSwgMCwgMCwgMCwgMCwgMCwgMCwgMCwgMCwgMCwgMF0sXG5cdFx0Ly8gXHRcdFswLCAwLCBodWdlLCAwLCAwLCAwLCAwLCAwLCAwLCAwLCAwLCAwXSxcblx0XHQvLyBcdFx0WzAsIDAsIDAsIGh1Z2UsIDAsIDAsIDAsIDAsIDAsIDAsIDAsIDBdLFxuXHRcdC8vIFx0XHRbMCwgMCwgMCwgMCwgaHVnZSwgMCwgMCwgMCwgMCwgMCwgMCwgMF0sXG5cdFx0Ly8gXHRcdFswLCAwLCAwLCAwLCAwLCBodWdlLCAwLCAwLCAwLCAwLCAwLCAwXSxcblx0XHQvLyBcdFx0WzAsIDAsIDAsIDAsIDAsIDAsIGh1Z2UsIDAsIDAsIDAsIDAsIDBdLFxuXHRcdC8vIFx0XHRbMCwgMCwgMCwgMCwgMCwgMCwgMCwgaHVnZSwgMCwgMCwgMCwgMF0sXG5cdFx0Ly8gXHRcdFswLCAwLCAwLCAwLCAwLCAwLCAwLCAwLCBodWdlLCAwLCAwLCAwXSxcblx0XHQvLyBcdFx0WzAsIDAsIDAsIDAsIDAsIDAsIDAsIDAsIDAsIGh1Z2UsIDAsIDBdLFxuXHRcdC8vIFx0XHRbMCwgMCwgMCwgMCwgMCwgMCwgMCwgMCwgMCwgMCwgaHVnZSwgMF0sXG5cdFx0Ly8gXHRcdFswLCAwLCAwLCAwLCAwLCAwLCAwLCAwLCAwLCAwLCAwLCBodWdlXSxcblx0XHQvLyBcdF1cblx0XHQvLyB9LFxuXG5cdFx0ZGltZW5zaW9uOiAxMixcblxuXHRcdGNvdmFyaWFuY2U6IFtcblx0XHRcdHBvc1Zhcixcblx0XHRcdHBvc1Zhcixcblx0XHRcdHNpemVWYXIsXG5cdFx0XHRzaXplVmFyLFxuXHRcdFx0cG9zVmFyICogdGltZVN0ZXAgKiB0aW1lU3RlcCxcblx0XHRcdHBvc1ZhciAqIHRpbWVTdGVwICogdGltZVN0ZXAsXG5cdFx0XHRzaXplVmFyICogdGltZVN0ZXAgKiB0aW1lU3RlcCxcblx0XHRcdHNpemVWYXIgKiB0aW1lU3RlcCAqIHRpbWVTdGVwLFxuXHRcdFx0cG9zVmFyICogKHRpbWVTdGVwICoqIDQpLFxuXHRcdFx0cG9zVmFyICogKHRpbWVTdGVwICoqIDQpLFxuXHRcdFx0c2l6ZVZhciAqICh0aW1lU3RlcCAqKiA0KSxcblx0XHRcdHNpemVWYXIgKiAodGltZVN0ZXAgKiogNClcblx0XHRdXG5cdH1cbn07XG4iLCJtb2R1bGUuZXhwb3J0cz1bWzM0LjMxNDI4NTcxNDI4NTcyLC04LjExNDI4NTcxNDI4NTcxNCwtOS4xODU3MTQyODU3MTQyODUsMy4wNDI4NTcxNDI4NTcxNDI3XSxbLTguMTE0Mjg1NzE0Mjg1NzE0LDM5LjA4NTcxNDI4NTcxNDI5LDEuMTg1NzE0Mjg1NzE0Mjg1NywtNS41Mjg1NzE0Mjg1NzE0Mjg1XSxbLTkuMTg1NzE0Mjg1NzE0Mjg1LDEuMTg1NzE0Mjg1NzE0Mjg1NywzNC42Mjg1NzE0Mjg1NzE0MjYsMC43ODU3MTQyODU3MTQyODU3XSxbMy4wNDI4NTcxNDI4NTcxNDI3LC01LjUyODU3MTQyODU3MTQyODUsMC43ODU3MTQyODU3MTQyODU3LDM5Ljg1NzE0Mjg1NzE0Mjg1NF1dIiwibW9kdWxlLmV4cG9ydHM9e1wib2JzZXJ2YXRpb25zXCI6W1s4NDIsMjg2LDgyLDgxXSxbNzE0LDE4NCw5Miw4MF0sWzU2MCwxMDcsMTEyLDExNl0sWzQxOCw5NCw5NiwxMTBdLFsyNzcsMTQxLDg5LDg5XSxbMTQ2LDIwMCw4OCw3Ml0sWzIyLDMwNiw3Nyw4Ml1dfSIsIm1vZHVsZS5leHBvcnRzID0gZnVuY3Rpb24gKHtjbGFzc05hbWUsIHRhZyA9ICdkaXYnLCBiYm94LCBwYXJlbnQsIHJvdGF0aW9uQ29lZmZpY2llbnQsIHNjYWxlLCBjb2xvcn0pIHtcblx0Y29uc3QgZWxlbWVudCA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQodGFnKTsvLyBlc2xpbnQtZGlzYWJsZS1saW5lIG5vLXVuZGVmXG5cdGVsZW1lbnQuaWQgPSAnYXJyb3cnO1xuXHRlbGVtZW50LmNsYXNzTmFtZSA9IGNsYXNzTmFtZTtcblx0ZWxlbWVudC5zdHlsZS50b3AgPSBNYXRoLnJvdW5kKGJib3hbMV0pICsgJ3B4Jztcblx0ZWxlbWVudC5zdHlsZS5sZWZ0ID0gTWF0aC5yb3VuZChiYm94WzBdKSArICdweCc7XG5cdGlmIChyb3RhdGlvbkNvZWZmaWNpZW50KSB7XG5cdFx0ZWxlbWVudC5zdHlsZS50cmFuc2Zvcm0gPSBgcm90YXRlKCR7cm90YXRpb25Db2VmZmljaWVudH1kZWcpYDtcblx0XHRlbGVtZW50LnN0eWxlLnRyYW5zZm9ybU9yaWdpbiA9ICctNXB4IDEycHgnO1xuXHR9XG5cblx0ZWxlbWVudC5zdHlsZS5zY2FsZSA9IHNjYWxlO1xuXHRlbGVtZW50LnN0eWxlLmNvbG9yID0gY29sb3I7XG5cdHBhcmVudC5hcHBlbmQoZWxlbWVudCk7XG5cdHJldHVybiBlbGVtZW50O1xufTtcbiIsIm1vZHVsZS5leHBvcnRzID0gZnVuY3Rpb24gKHtcblx0Y2xhc3NOYW1lLFxuXHR0YWcgPSAnZGl2Jyxcblx0YmJveCxcblx0cGFyZW50LFxuXHRjb2xvcixcblx0cGVyY2VudGFnZSxcblx0cG9zaXRpb24gPSAndmVydGljYWwnXG59KSB7XG5cdC8vIEJib3ggY29udGFpbnMgMyBlbGVtZW50czogbGVmdCwgdG9wIGFuZCBib3R0b20gb2YgdGhlIGRhc2hlZCBsaW5lIG9yIHRvcCwgbGVmdCBhbmQgcmlnaHRcblx0Y29uc3QgZWxlbWVudCA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQodGFnKTsvLyBlc2xpbnQtZGlzYWJsZS1saW5lIG5vLXVuZGVmXG5cdC8vIElmIChjb2xvcikge1xuXHQvLyBcdGVsLnN0eWxlLmJhY2tncm91bmRDb2xvciA9IGNvbG9yXG5cdC8vIH1cblx0ZWxlbWVudC5jbGFzc05hbWUgPSBjbGFzc05hbWU7XG5cdGlmIChwb3NpdGlvbiA9PT0gJ3ZlcnRpY2FsJykge1xuXHRcdGVsZW1lbnQuc3R5bGUud2lkdGggPSAxICsgJ3B4Jztcblx0XHRlbGVtZW50LnN0eWxlLmhlaWdodCA9IE1hdGguYWJzKGJib3hbMV0gLSBiYm94WzJdKSArICdweCc7XG5cdFx0ZWxlbWVudC5zdHlsZS50b3AgPSBiYm94WzFdICsgJ3B4Jztcblx0XHRlbGVtZW50LnN0eWxlLmxlZnQgPSBiYm94WzBdICsgJ3B4Jztcblx0fVxuXG5cdGlmIChwb3NpdGlvbiA9PT0gJ2hvcml6b250YWwnKSB7XG5cdFx0ZWxlbWVudC5zdHlsZS5oZWlnaHQgPSAxICsgJ3B4Jztcblx0XHRlbGVtZW50LnN0eWxlLndpZHRoID0gTWF0aC5hYnMoYmJveFsxXSAtIGJib3hbMl0pICsgJ3B4Jztcblx0XHRlbGVtZW50LnN0eWxlLmxlZnQgPSBiYm94WzFdICsgJ3B4Jztcblx0XHRlbGVtZW50LnN0eWxlLnRvcCA9IGJib3hbMF0gKyAncHgnO1xuXHR9XG5cblx0Ly8gRWwuc3R5bGUub3BhY2l0eSA9IDEtcGVyY2VudGFnZVxuXHRjb25zdCB1cmxTdHJpbmcgPSAnZGF0YTppbWFnZS9zdmcreG1sLCUzY3N2ZyAnICtcblx0XHQnd2lkdGg9XFwnMTAwJTI1XFwnICcgK1xuXHRcdCdoZWlnaHQ9XFwnMTAwJTI1XFwnICcgK1xuXHRcdCd4bWxucz1cXCdodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2Z1xcJyUzZSUzY3JlY3QgJyArXG5cdFx0J3dpZHRoPVxcJzEwMCUyNVxcJyAnICtcblx0XHQnaGVpZ2h0PVxcJzEwMCUyNVxcJyAnICtcblx0XHQnZmlsbD1cXCdub25lXFwnICcgK1xuXHRcdGBzdHJva2U9JyR7Y29sb3J9JyBgICtcblx0XHQnc3Ryb2tlLXdpZHRoPVxcJzRcXCcgJyArXG5cdFx0YHN0cm9rZS1kYXNoYXJyYXk9JzEwJTJjJHtNYXRoLmZsb29yKHBlcmNlbnRhZ2UgKiAxMDApfScgYCArXG5cdFx0J3N0cm9rZS1kYXNob2Zmc2V0PVxcJzBcXCcgJyArXG5cdFx0J3N0cm9rZS1saW5lY2FwPVxcJ3JvdW5kXFwnLyUzZSUzYy9zdmclM2UnO1xuXG5cdGNvbnN0IGJhY2tncm91bmRJbWFnZTEgPSBgdXJsKFwiJHt1cmxTdHJpbmd9XCIpYDtcblxuXHQvLyBDb25zdCBiYWNrZ3JvdW5kSW1hZ2UyID0gXCJ1cmwoXFxcImRhdGE6aW1hZ2Uvc3ZnK3htbCwlM2Nzdmcgd2lkdGg9JzEwMCUyNScgaGVpZ2h0PScxMDAlMjUnIHhtbG5zPSdodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyclM2UlM2NyZWN0IHdpZHRoPScxMDAlMjUnIGhlaWdodD0nMTAwJTI1JyBmaWxsPSdub25lJyBzdHJva2U9JyUyMzMzMycgc3Ryb2tlLXdpZHRoPSc0JyBzdHJva2UtZGFzaGFycmF5PScxMCUyYzIwJyBzdHJva2UtZGFzaG9mZnNldD0nMCcgc3Ryb2tlLWxpbmVjYXA9J3NxdWFyZScvJTNlJTNjL3N2ZyUzZVxcXCIpXCJcblx0Ly8gY29uc29sZS5sb2coYmFja2dyb3VuZEltYWdlMSwgYmFja2dyb3VuZEltYWdlMiwgYmFja2dyb3VuZEltYWdlMT09PWJhY2tncm91bmRJbWFnZTIpXG5cdGVsZW1lbnQuc3R5bGUuYmFja2dyb3VuZEltYWdlID0gYmFja2dyb3VuZEltYWdlMTtcblx0cGFyZW50LmFwcGVuZChlbGVtZW50KTtcblx0cmV0dXJuIGVsZW1lbnQ7XG59O1xuIiwibW9kdWxlLmV4cG9ydHMgPSBmdW5jdGlvbiAoe2lkLCBjbGFzc05hbWUsIHRhZyA9ICdkaXYnLCBiYm94LCBwYXJlbnQsIHJvdGF0aW9uQ29lZmZpY2llbnR9KSB7XG5cdGNvbnN0IGVsZW1lbnQgPSBkb2N1bWVudC5jcmVhdGVFbGVtZW50KHRhZyk7Ly8gZXNsaW50LWRpc2FibGUtbGluZSBuby11bmRlZlxuXHRlbGVtZW50LmNsYXNzTmFtZSA9IGNsYXNzTmFtZTtcblx0ZWxlbWVudC5pZCA9IGlkO1xuXHQvLyBJZiAoY29sb3IgJiYgbGluZVN0eWxlKSB7XG5cdC8vIFx0ZWwuc3R5bGUuYm9yZGVyID0gYDFweCAke2xpbmVTdHlsZX0gJHtjb2xvcn1gXG5cdC8vIH1cblx0ZWxlbWVudC5zdHlsZS53aWR0aCA9IE1hdGgucm91bmQoYmJveFsyXSkgKyAncHgnO1xuXHRlbGVtZW50LnN0eWxlLmhlaWdodCA9IE1hdGgucm91bmQoYmJveFszXSkgKyAncHgnO1xuXHRlbGVtZW50LnN0eWxlLnRvcCA9IE1hdGgucm91bmQoYmJveFsxXSAtIChiYm94WzNdIC8gMikpICsgJ3B4Jztcblx0ZWxlbWVudC5zdHlsZS5sZWZ0ID0gTWF0aC5yb3VuZChiYm94WzBdIC0gKGJib3hbMl0gLyAyKSkgKyAncHgnO1xuXHRpZiAocm90YXRpb25Db2VmZmljaWVudCkge1xuXHRcdGVsZW1lbnQuc3R5bGUudHJhbnNmb3JtID0gYHJvdGF0ZSgke3JvdGF0aW9uQ29lZmZpY2llbnR9ZGVnKWA7XG5cdH1cblxuXHRwYXJlbnQuYXBwZW5kKGVsZW1lbnQpO1xuXHRyZXR1cm4gZWxlbWVudDtcbn07XG4iLCJjb25zdCBjcmVhdGVFbGVtZW50ID0gcmVxdWlyZSgnLi9jcmVhdGUtZWxlbWVudCcpO1xuY29uc3QgY3JlYXRlUG9pbnQgPSByZXF1aXJlKCcuL2NyZWF0ZS1wb2ludCcpO1xuY29uc3QgY3JlYXRlQXJyb3cgPSByZXF1aXJlKCcuL2NyZWF0ZS1hcnJvdycpO1xuY29uc3QgY3JlYXRlQ3VzdG9tRGFzaGVkTGluZSA9IHJlcXVpcmUoJy4vY3JlYXRlLWN1c3RvbS1kYXNoZWQtbGluZScpO1xuXG5tb2R1bGUuZXhwb3J0cyA9IGZ1bmN0aW9uICh7bWVhbiwgY292YXJpYW5jZSwgY29sb3IsIHBhcmVudCwgY2xhc3NOYW1lLCB0YWcgPSAnZGl2J30pIHtcblx0Y29uc3QgY29udGFpbmVyID0gZG9jdW1lbnQuY3JlYXRlRWxlbWVudCh0YWcpOyAvLyBlc2xpbnQtZGlzYWJsZS1saW5lIG5vLXVuZGVmXG5cblx0Y29udGFpbmVyLmNsYXNzTmFtZSA9IGNsYXNzTmFtZTtcblx0Y29uc3QgY2VudGVyID0gW21lYW5bMF1bMF0gKyAobWVhblsyXVswXSAvIDIpLCBtZWFuWzFdWzBdICsgKG1lYW5bM11bMF0gLyAyKV07XG5cdGNyZWF0ZUVsZW1lbnQoe1xuXHRcdGNsYXNzTmFtZTogJ2JveCcsXG5cdFx0YmJveDogW2NlbnRlclswXSwgY2VudGVyWzFdLCBtZWFuWzJdWzBdLCBtZWFuWzNdWzBdXSxcblx0XHRwYXJlbnQ6IGNvbnRhaW5lcixcblx0XHRjb2xvcixcblx0XHRsaW5lU3R5bGU6ICdzb2xpZCdcblx0fSk7XG5cdGNyZWF0ZUVsZW1lbnQoe1xuXHRcdGNsYXNzTmFtZTogJ2JveCBzdGREZXYnLFxuXHRcdGJib3g6IFtcblx0XHRcdGNlbnRlclswXSxcblx0XHRcdGNlbnRlclsxXSxcblx0XHRcdG1lYW5bMl1bMF0gKyAoMiAqIDMgKiBNYXRoLnNxcnQoY292YXJpYW5jZVsyXVsyXSkpLFxuXHRcdFx0bWVhblszXVswXSArICgyICogMyAqIE1hdGguc3FydChjb3ZhcmlhbmNlWzNdWzNdKSlcblx0XHRdLFxuXHRcdHBhcmVudDogY29udGFpbmVyLFxuXHRcdGNvbG9yXG5cdH0pO1xuXHRjcmVhdGVQb2ludCh7XG5cdFx0YmJveDogW2NlbnRlclswXSwgY2VudGVyWzFdLCAyLCAyXSxcblx0XHRwYXJlbnQ6IGNvbnRhaW5lcixcblx0XHRjb2xvclxuXHR9KTtcblx0Y29uc3QgY29ycmVsYXRpb25YWSA9IGNvdmFyaWFuY2VbMF1bMV0gLyAoTWF0aC5zcXJ0KGNvdmFyaWFuY2VbMF1bMF0pICogTWF0aC5zcXJ0KGNvdmFyaWFuY2VbMV1bMV0pKTtcblx0Y3JlYXRlRWxlbWVudCh7XG5cdFx0Y2xhc3NOYW1lOiAnZWxsaXBzZSBzdGREZXYnLFxuXHRcdGJib3g6IFtcblx0XHRcdGNlbnRlclswXSxcblx0XHRcdGNlbnRlclsxXSxcblx0XHRcdDIgKiAzICogTWF0aC5zcXJ0KGNvdmFyaWFuY2VbMF1bMF0pLFxuXHRcdFx0MiAqIDMgKiBNYXRoLnNxcnQoY292YXJpYW5jZVsxXVsxXSlcblx0XHRdLFxuXHRcdHBhcmVudDogY29udGFpbmVyLFxuXHRcdHJvdGF0aW9uQ29lZmZpY2llbnQ6IGNvcnJlbGF0aW9uWFksXG5cdFx0Y29sb3Jcblx0fSk7XG5cdGNvbnN0IGNvcnJlbGF0aW9uWFcgPSBjb3ZhcmlhbmNlWzBdWzJdIC8gKE1hdGguc3FydChjb3ZhcmlhbmNlWzBdWzBdKSAqIE1hdGguc3FydChjb3ZhcmlhbmNlWzJdWzJdKSk7XG5cdGNyZWF0ZUN1c3RvbURhc2hlZExpbmUoe1xuXHRcdGNsYXNzTmFtZTogJ2Rhc2hlZExpbmUnLFxuXHRcdGJib3g6IFtcblx0XHRcdGNlbnRlclswXSxcblx0XHRcdGNlbnRlclsxXSArICgzICogTWF0aC5zcXJ0KGNvdmFyaWFuY2VbMV1bMV0pKSxcblx0XHRcdGNlbnRlclsxXSArIChtZWFuWzNdWzBdIC8gMikgKyAoMyAqIE1hdGguc3FydChjb3ZhcmlhbmNlWzNdWzNdKSlcblx0XHRdLFxuXHRcdHBhcmVudDogY29udGFpbmVyLFxuXHRcdHBlcmNlbnRhZ2U6IE1hdGguYWJzKGNvcnJlbGF0aW9uWFcpLFxuXHRcdGNvbG9yXG5cdH0pO1xuXHRjb25zdCBjb3JyZWxhdGlvbllIID0gY292YXJpYW5jZVsxXVszXSAvIChNYXRoLnNxcnQoY292YXJpYW5jZVsxXVsxXSkgKiBNYXRoLnNxcnQoY292YXJpYW5jZVszXVszXSkpO1xuXHRjcmVhdGVDdXN0b21EYXNoZWRMaW5lKHtcblx0XHRjbGFzc05hbWU6ICdkYXNoZWRMaW5lJyxcblx0XHRiYm94OiBbXG5cdFx0XHRjZW50ZXJbMV0sXG5cdFx0XHRjZW50ZXJbMF0gKyAoMyAqIE1hdGguc3FydChjb3ZhcmlhbmNlWzBdWzBdKSksXG5cdFx0XHRjZW50ZXJbMF0gKyAobWVhblsyXVswXSAvIDIpICsgKDMgKiBNYXRoLnNxcnQoY292YXJpYW5jZVsyXVsyXSkpXG5cdFx0XSxcblx0XHRwYXJlbnQ6IGNvbnRhaW5lcixcblx0XHRwZXJjZW50YWdlOiBNYXRoLmFicyhjb3JyZWxhdGlvbllIKSxcblx0XHRwb3NpdGlvbjogJ2hvcml6b250YWwnLFxuXHRcdGNvbG9yXG5cdH0pO1xuXHRjb25zdCBhcnJvd1JvdGF0aW9uID0gKC0xICogTWF0aC5hdGFuKG1lYW5bNF1bMF0gLyBtZWFuWzVdWzBdKSAqIDE4MCAvIE1hdGguUEkpIC0gNDU7XG5cdGNvbnN0IGFycm93U2NhbGUgPSBNYXRoLnNxcnQoKG1lYW5bNF1bMF0gKiogMikgKyAobWVhbls1XVswXSAqKiAyKSk7XG5cdGNyZWF0ZUFycm93KHtcblx0XHRjbGFzc05hbWU6ICdhcnJvdycsXG5cdFx0YmJveDogW1xuXHRcdFx0Y2VudGVyWzBdICsgNixcblx0XHRcdGNlbnRlclsxXSAtIDlcblx0XHRdLFxuXHRcdHBhcmVudDogY29udGFpbmVyLFxuXHRcdHJvdGF0aW9uQ29lZmZpY2llbnQ6IGFycm93Um90YXRpb24sXG5cdFx0c2NhbGU6IGFycm93U2NhbGUsXG5cdFx0Y29sb3Jcblx0fSk7XG5cdHBhcmVudC5hcHBlbmQoY29udGFpbmVyKTtcbn07XG4iLCJtb2R1bGUuZXhwb3J0cyA9IGZ1bmN0aW9uICh7Y2xhc3NOYW1lID0gJ3BvaW50JywgdGFnID0gJ2RpdicsIGJib3gsIHBhcmVudH0pIHtcblx0Y29uc3QgZWxlbWVudCA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQodGFnKTsvLyBlc2xpbnQtZGlzYWJsZS1saW5lIG5vLXVuZGVmXG5cdGVsZW1lbnQuY2xhc3NOYW1lID0gY2xhc3NOYW1lO1xuXHQvLyBJZiAoY29sb3IpIHtcblx0Ly8gXHRlbC5zdHlsZS5ib3JkZXIgPSBgMnB4IHNvbGlkICR7Y29sb3J9YCxcblx0Ly8gXHRlbC5zdHlsZS5iYWNrZ3JvdW5kQ29sb3IgPSBgJHtjb2xvcn1gXG5cdC8vIH1cblx0ZWxlbWVudC5zdHlsZS53aWR0aCA9IE1hdGgucm91bmQoYmJveFsyXSkgKyAncHgnO1xuXHRlbGVtZW50LnN0eWxlLmhlaWdodCA9IE1hdGgucm91bmQoYmJveFszXSkgKyAncHgnO1xuXHRlbGVtZW50LnN0eWxlLnRvcCA9IE1hdGgucm91bmQoYmJveFsxXSAtIChiYm94WzNdIC8gMikpICsgJ3B4Jztcblx0ZWxlbWVudC5zdHlsZS5sZWZ0ID0gTWF0aC5yb3VuZChiYm94WzBdIC0gKGJib3hbMl0gLyAyKSkgKyAncHgnO1xuXHRwYXJlbnQuYXBwZW5kKGVsZW1lbnQpO1xuXHRyZXR1cm4gZWxlbWVudDtcbn07XG4iLCJjb25zdCBtYXRNdWwgPSByZXF1aXJlKCcuLi9saWIvbGluYWxnZWJyYS9tYXQtbXVsLmpzJyk7XG5jb25zdCB0cmFuc3Bvc2UgPSByZXF1aXJlKCcuLi9saWIvbGluYWxnZWJyYS90cmFuc3Bvc2UuanMnKTtcbmNvbnN0IGFkZCA9IHJlcXVpcmUoJy4uL2xpYi9saW5hbGdlYnJhL2FkZC5qcycpO1xuY29uc3QgaW52ZXJ0ID0gcmVxdWlyZSgnLi4vbGliL2xpbmFsZ2VicmEvaW52ZXJ0LmpzJyk7XG5jb25zdCBzdWIgPSByZXF1aXJlKCcuLi9saWIvbGluYWxnZWJyYS9zdWIuanMnKTtcbmNvbnN0IGdldElkZW50aXR5ID0gcmVxdWlyZSgnLi4vbGliL2xpbmFsZ2VicmEvaWRlbnRpdHkuanMnKTtcbmNvbnN0IFN0YXRlID0gcmVxdWlyZSgnLi9zdGF0ZS5qcycpO1xuXG4vKipcbiogQGNhbGxiYWNrIE9ic2VydmF0aW9uQ2FsbGJhY2tcbiogQHBhcmFtIHtPYmplY3R9IG9wdHNcbiogQHBhcmFtIHtOdW1iZXJ9IG9wdHMuaW5kZXhcbiogQHBhcmFtIHtOdW1iZXJ9IG9wdHMucHJldmlvdXNDb3JyZWN0ZWRcbiovXG5cbi8qKlxuKiBAdHlwZWRlZiB7T2JqZWN0fSBPYnNlcnZhdGlvbkNvbmZpZ1xuKiBAcHJvcGVydHkge051bWJlcn0gZGltZW5zaW9uXG4qIEBwcm9wZXJ0eSB7QXJyYXkuQXJyYXkuPE51bWJlcj4+IHwgT2JzZXJ2YXRpb25DYWxsYmFja30gc3RhdGVQcm9qZWN0aW9uLFxuKiBAcHJvcGVydHkge0FycmF5LkFycmF5LjxOdW1iZXI+PiB8IE9ic2VydmF0aW9uQ2FsbGJhY2t9IGNvdmFyaWFuY2VcbiovXG5cbi8qKlxuKiBAY2FsbGJhY2sgRHluYW1pY0NhbGxiYWNrXG4qIEBwYXJhbSB7T2JqZWN0fSBvcHRzXG4qIEBwYXJhbSB7TnVtYmVyfSBvcHRzLmluZGV4XG4qIEBwYXJhbSB7U3RhdGV9IG9wdHMucHJlZGljdGVkXG4qIEBwYXJhbSB7T2JzZXJ2YXRpb259IG9wdHMub2JzZXJ2YXRpb25cbiovXG5cbi8qKlxuKiBAdHlwZWRlZiB7T2JqZWN0fSBEeW5hbWljQ29uZmlnXG4qIEBwcm9wZXJ0eSB7TnVtYmVyfSBkaW1lbnNpb25cbiogQHByb3BlcnR5IHtBcnJheS5BcnJheS48TnVtYmVyPj4gfCBEeW5hbWljQ2FsbGJhY2t9IHRyYW5zaXRpb24sXG4qIEBwcm9wZXJ0eSB7QXJyYXkuQXJyYXkuPE51bWJlcj4+IHwgRHluYW1pY0NhbGxiYWNrfSBjb3ZhcmlhbmNlXG4qL1xuXG5jb25zdCBkZWZhdWx0TG9nZ2VyID0ge1xuXHRpbmZvOiAoLi4uYXJncykgPT4gY29uc29sZS5sb2coLi4uYXJncyksXG5cdGRlYnVnOiAoKSA9PiB7fSxcblx0d2FybjogKC4uLmFyZ3MpID0+IGNvbnNvbGUubG9nKC4uLmFyZ3MpLFxuXHRlcnJvcjogKC4uLmFyZ3MpID0+IGNvbnNvbGUubG9nKC4uLmFyZ3MpXG59O1xuXG4vKipcbiogQGNsYXNzXG4qIEBwcm9wZXJ0eSB7RHluYW1pY0NvbmZpZ30gZHluYW1pYyB0aGUgc3lzdGVtJ3MgZHluYW1pYyBtb2RlbFxuKiBAcHJvcGVydHkge09ic2VydmF0aW9uQ29uZmlnfSBvYnNlcnZhdGlvbiB0aGUgc3lzdGVtJ3Mgb2JzZXJ2YXRpb24gbW9kZWxcbipAcHJvcGVydHkgbG9nZ2VyIGEgV2luc3Rvbi1saWtlIGxvZ2dlclxuKi9cbmNsYXNzIENvcmVLYWxtYW5GaWx0ZXIge1xuXHQvKipcblx0KiBAcGFyYW0ge0R5bmFtaWNDb25maWd9IGR5bmFtaWNcblx0KiBAcGFyYW0ge09ic2VydmF0aW9uQ29uZmlnfSBvYnNlcnZhdGlvbiB0aGUgc3lzdGVtJ3Mgb2JzZXJ2YXRpb24gbW9kZWxcblx0Ki9cblxuXHRjb25zdHJ1Y3Rvcih7ZHluYW1pYywgb2JzZXJ2YXRpb24sIGxvZ2dlciA9IGRlZmF1bHRMb2dnZXJ9KSB7XG5cdFx0dGhpcy5keW5hbWljID0gZHluYW1pYztcblx0XHR0aGlzLm9ic2VydmF0aW9uID0gb2JzZXJ2YXRpb247XG5cdFx0dGhpcy5sb2dnZXIgPSBsb2dnZXI7XG5cdH1cblxuXHRnZXRWYWx1ZShmbiwgb3B0aW9ucykge1xuXHRcdHJldHVybiAodHlwZW9mIChmbikgPT09ICdmdW5jdGlvbicgPyBmbihvcHRpb25zKSA6IGZuKTtcblx0fVxuXG5cdGdldEluaXRTdGF0ZSgpIHtcblx0XHRjb25zdCB7bWVhbjogbWVhbkluaXQsIGNvdmFyaWFuY2U6IGNvdmFyaWFuY2VJbml0LCBpbmRleDogaW5kZXhJbml0fSA9IHRoaXMuZHluYW1pYy5pbml0O1xuXHRcdGNvbnN0IGluaXRTdGF0ZSA9IG5ldyBTdGF0ZSh7XG5cdFx0XHRtZWFuOiBtZWFuSW5pdCxcblx0XHRcdGNvdmFyaWFuY2U6IGNvdmFyaWFuY2VJbml0LFxuXHRcdFx0aW5kZXg6IGluZGV4SW5pdH0pO1xuXHRcdHJldHVybiBpbml0U3RhdGU7XG5cdH1cblxuXHQvKipcblx0VGhpcyB3aWxsIHJldHVybiB0aGUgcHJlZGljdGVkIGNvdmFyaWFuY2Ugb2YgYSBnaXZlbiBwcmV2aW91c0NvcnJlY3RlZCBTdGF0ZSwgdGhpcyB3aWxsIGhlbHAgdXMgdG8gYnVpbGQgdGhlIGFzeW1wdG90aWNTdGF0ZS5cblx0KiBAcGFyYW0ge1N0YXRlfSBwcmV2aW91c0NvcnJlY3RlZFxuXHQqIEByZXR1cm5ze0FycmF5LjxBcnJheS48TnVtYmVyPj59XG5cdCovXG5cblx0Z2V0UHJlZGljdGVkQ292YXJpYW5jZSh7cHJldmlvdXNDb3JyZWN0ZWR9ID0ge30pIHtcblx0XHRwcmV2aW91c0NvcnJlY3RlZCA9IHByZXZpb3VzQ29ycmVjdGVkIHx8IHRoaXMuZ2V0SW5pdFN0YXRlKCk7XG5cblx0XHRjb25zdCBnZXRWYWx1ZU9wdGlvbnMgPSB7cHJldmlvdXNDb3JyZWN0ZWQsIGluZGV4OiBwcmV2aW91c0NvcnJlY3RlZC5pbmRleH07XG5cdFx0Y29uc3QgZCA9IHRoaXMuZ2V0VmFsdWUodGhpcy5keW5hbWljLnRyYW5zaXRpb24sIGdldFZhbHVlT3B0aW9ucyk7XG5cdFx0Y29uc3QgZFRyYW5zcG9zZWQgPSB0cmFuc3Bvc2UoZCk7XG5cdFx0Y29uc3QgY292YXJpYW5jZUludGVyID0gbWF0TXVsKGQsIHByZXZpb3VzQ29ycmVjdGVkLmNvdmFyaWFuY2UpO1xuXHRcdGNvbnN0IGNvdmFyaWFuY2VQcmV2aW91cyA9IG1hdE11bChjb3ZhcmlhbmNlSW50ZXIsIGRUcmFuc3Bvc2VkKTtcblx0XHRjb25zdCBkeW5Db3YgPSB0aGlzLmdldFZhbHVlKHRoaXMuZHluYW1pYy5jb3ZhcmlhbmNlLCBnZXRWYWx1ZU9wdGlvbnMpO1xuXG5cdFx0Y29uc3QgY292YXJpYW5jZSA9IGFkZChcblx0XHRcdGR5bkNvdixcblx0XHRcdGNvdmFyaWFuY2VQcmV2aW91c1xuXHRcdCk7XG5cdFx0cmV0dXJuIGNvdmFyaWFuY2U7XG5cdH1cblxuXHQvKipcblx0VGhpcyB3aWxsIHJldHVybiB0aGUgbmV3IHByZWRpY3Rpb24sIHJlbGF0aXZlbHkgdG8gdGhlIGR5bmFtaWMgbW9kZWwgY2hvc2VuXG5cdCogQHBhcmFtIHtTdGF0ZX0gcHJldmlvdXNDb3JyZWN0ZWQgU3RhdGUgcmVsYXRpdmUgdG8gb3VyIGR5bmFtaWMgbW9kZWxcblx0KiBAcmV0dXJuc3tTdGF0ZX0gcHJlZGljdGVkIFN0YXRlXG5cdCovXG5cblx0cHJlZGljdCh7cHJldmlvdXNDb3JyZWN0ZWR9ID0ge30pIHtcblx0XHRwcmV2aW91c0NvcnJlY3RlZCA9IHByZXZpb3VzQ29ycmVjdGVkIHx8IHRoaXMuZ2V0SW5pdFN0YXRlKCk7XG5cblx0XHRTdGF0ZS5jaGVjayhwcmV2aW91c0NvcnJlY3RlZCwge2RpbWVuc2lvbjogdGhpcy5keW5hbWljLmRpbWVuc2lvbn0pO1xuXG5cdFx0Y29uc3QgZ2V0VmFsdWVPcHRpb25zID0ge3ByZXZpb3VzQ29ycmVjdGVkLCBpbmRleDogcHJldmlvdXNDb3JyZWN0ZWQuaW5kZXh9O1xuXHRcdGNvbnN0IGQgPSB0aGlzLmdldFZhbHVlKHRoaXMuZHluYW1pYy50cmFuc2l0aW9uLCBnZXRWYWx1ZU9wdGlvbnMpO1xuXG5cdFx0Y29uc3QgbWVhbiA9IG1hdE11bChkLCBwcmV2aW91c0NvcnJlY3RlZC5tZWFuKTtcblxuXHRcdGNvbnN0IGNvdmFyaWFuY2UgPSB0aGlzLmdldFByZWRpY3RlZENvdmFyaWFuY2Uoe3ByZXZpb3VzQ29ycmVjdGVkfSk7XG5cdFx0bGV0IGluZGV4O1xuXHRcdGlmICh0eXBlb2YgKHByZXZpb3VzQ29ycmVjdGVkLmluZGV4KSA9PT0gJ251bWJlcicpIHtcblx0XHRcdGluZGV4ID0gcHJldmlvdXNDb3JyZWN0ZWQuaW5kZXggKyAxO1xuXHRcdH1cblx0XHRlbHNlIHtcblx0XHRcdGluZGV4ID0gbnVsbDtcblx0XHR9XG5cblx0XHRjb25zdCBwcmVkaWN0ZWQgPSBuZXcgU3RhdGUoe21lYW4sIGNvdmFyaWFuY2UsIGluZGV4fSk7XG5cdFx0dGhpcy5sb2dnZXIuZGVidWcoJ1ByZWRpY3Rpb24gZG9uZScsIHByZWRpY3RlZCk7XG5cdFx0cmV0dXJuIHByZWRpY3RlZDtcblx0fVxuXHQvKipcblx0VGhpcyB3aWxsIHJldHVybiB0aGUgbmV3IGNvcnJlY3Rpb24sIHRha2luZyBpbnRvIGFjY291bnQgdGhlIHByZWRpY3Rpb24gbWFkZVxuXHRhbmQgdGhlIG9ic2VydmF0aW9uIG9mIHRoZSBzZW5zb3Jcblx0KiBAcGFyYW0ge1N0YXRlfSBwcmVkaWN0ZWQgdGhlIHByZXZpb3VzIFN0YXRlXG5cdCogQHJldHVybnN7QXJyYXk8QXJyYXk+fSBrYWxtYW5HYWluXG5cdCovXG5cblx0Z2V0R2Fpbih7cHJlZGljdGVkLCBzdGF0ZVByb2plY3Rpb259KSB7XG5cdFx0Y29uc3QgZ2V0VmFsdWVPcHRpb25zID0ge3ByZWRpY3RlZCwgaW5kZXg6IHByZWRpY3RlZC5pbmRleH07XG5cdFx0c3RhdGVQcm9qZWN0aW9uID0gc3RhdGVQcm9qZWN0aW9uIHx8IHRoaXMuZ2V0VmFsdWUodGhpcy5vYnNlcnZhdGlvbi5zdGF0ZVByb2plY3Rpb24sIGdldFZhbHVlT3B0aW9ucyk7XG5cdFx0Y29uc3Qgb2JzQ292YXJpYW5jZSA9IHRoaXMuZ2V0VmFsdWUodGhpcy5vYnNlcnZhdGlvbi5jb3ZhcmlhbmNlLCBnZXRWYWx1ZU9wdGlvbnMpO1xuXHRcdGNvbnN0IHN0YXRlUHJvalRyYW5zcG9zZWQgPSB0cmFuc3Bvc2Uoc3RhdGVQcm9qZWN0aW9uKTtcblx0XHRjb25zdCBub2lzZWxlc3NJbm5vdmF0aW9uID0gbWF0TXVsKFxuXHRcdFx0bWF0TXVsKHN0YXRlUHJvamVjdGlvbiwgcHJlZGljdGVkLmNvdmFyaWFuY2UpLFxuXHRcdFx0c3RhdGVQcm9qVHJhbnNwb3NlZFxuXHRcdCk7XG5cdFx0Y29uc3QgaW5ub3ZhdGlvbkNvdmFyaWFuY2UgPSBhZGQobm9pc2VsZXNzSW5ub3ZhdGlvbiwgb2JzQ292YXJpYW5jZSk7XG5cdFx0Y29uc3Qgb3B0aW1hbEthbG1hbkdhaW4gPSBtYXRNdWwoXG5cdFx0XHRtYXRNdWwocHJlZGljdGVkLmNvdmFyaWFuY2UsIHN0YXRlUHJvalRyYW5zcG9zZWQpLFxuXHRcdFx0aW52ZXJ0KGlubm92YXRpb25Db3ZhcmlhbmNlKVxuXHRcdCk7XG5cdFx0cmV0dXJuIG9wdGltYWxLYWxtYW5HYWluO1xuXHR9XG5cblx0LyoqXG5cdFRoaXMgd2lsbCByZXR1cm4gdGhlIGNvcnJlY3RlZCBjb3ZhcmlhbmNlIG9mIGEgZ2l2ZW4gcHJlZGljdGVkIFN0YXRlLCB0aGlzIHdpbGwgaGVscCB1cyB0byBidWlsZCB0aGUgYXN5bXB0b3RpY1N0YXRlLlxuXHQqIEBwYXJhbSB7U3RhdGV9IHByZWRpY3RlZCB0aGUgcHJldmlvdXMgU3RhdGVcblx0KiBAcmV0dXJuc3tBcnJheS48QXJyYXkuPE51bWJlcj4+fVxuXHQqL1xuXG5cdGdldENvcnJlY3RlZENvdmFyaWFuY2Uoe3ByZWRpY3RlZH0pIHtcblx0XHRjb25zdCBnZXRWYWx1ZU9wdGlvbnMgPSB7cHJlZGljdGVkLCBpbmRleDogcHJlZGljdGVkLmluZGV4fTtcblx0XHRjb25zdCBpZGVudGl0eSA9IGdldElkZW50aXR5KHByZWRpY3RlZC5jb3ZhcmlhbmNlLmxlbmd0aCk7XG5cdFx0Y29uc3Qgc3RhdGVQcm9qID0gdGhpcy5nZXRWYWx1ZSh0aGlzLm9ic2VydmF0aW9uLnN0YXRlUHJvamVjdGlvbiwgZ2V0VmFsdWVPcHRpb25zKTtcblx0XHRjb25zdCBvcHRpbWFsS2FsbWFuR2FpbiA9IHRoaXMuZ2V0R2Fpbih7cHJlZGljdGVkLCBzdGF0ZVByb2plY3Rpb246IHN0YXRlUHJvan0pO1xuXHRcdHJldHVybiBtYXRNdWwoXG5cdFx0XHRzdWIoaWRlbnRpdHksIG1hdE11bChvcHRpbWFsS2FsbWFuR2Fpbiwgc3RhdGVQcm9qKSksXG5cdFx0XHRwcmVkaWN0ZWQuY292YXJpYW5jZVxuXHRcdCk7XG5cdH1cblxuXHQvKipcblx0VGhpcyB3aWxsIHJldHVybiB0aGUgbmV3IGNvcnJlY3Rpb24sIHRha2luZyBpbnRvIGFjY291bnQgdGhlIHByZWRpY3Rpb24gbWFkZVxuXHRhbmQgdGhlIG9ic2VydmF0aW9uIG9mIHRoZSBzZW5zb3Jcblx0KiBAcGFyYW0ge1N0YXRlfSBwcmVkaWN0ZWQgdGhlIHByZXZpb3VzIFN0YXRlXG5cdCogQHBhcmFtIHtBcnJheX0gb2JzZXJ2YXRpb24gdGhlIG9ic2VydmF0aW9uIG9mIHRoZSBzZW5zb3Jcblx0KiBAcmV0dXJuc3tTdGF0ZX0gY29ycmVjdGVkIFN0YXRlIG9mIHRoZSBLYWxtYW4gRmlsdGVyXG5cdCovXG5cblx0Y29ycmVjdCh7cHJlZGljdGVkLCBvYnNlcnZhdGlvbn0pIHtcblx0XHRTdGF0ZS5jaGVjayhwcmVkaWN0ZWQsIHtkaW1lbnNpb246IHRoaXMuZHluYW1pYy5kaW1lbnNpb259KTtcblx0XHRpZiAoIW9ic2VydmF0aW9uKSB7XG5cdFx0XHR0aHJvdyAobmV3IEVycm9yKCdubyBtZWFzdXJlIGF2YWlsYWJsZScpKTtcblx0XHR9XG5cblx0XHRjb25zdCBnZXRWYWx1ZU9wdGlvbnMgPSB7cHJlZGljdGVkLCBpbmRleDogcHJlZGljdGVkLmluZGV4fTtcblx0XHRjb25zdCBzdGF0ZVByb2ogPSB0aGlzLmdldFZhbHVlKHRoaXMub2JzZXJ2YXRpb24uc3RhdGVQcm9qZWN0aW9uLCBnZXRWYWx1ZU9wdGlvbnMpO1xuXG5cdFx0Y29uc3Qgb3B0aW1hbEthbG1hbkdhaW4gPSB0aGlzLmdldEdhaW4oe3ByZWRpY3RlZCwgc3RhdGVQcm9qZWN0aW9uOiBzdGF0ZVByb2p9KTtcblx0XHRjb25zdCBpbm5vdmF0aW9uID0gc3ViKFxuXHRcdFx0b2JzZXJ2YXRpb24sXG5cdFx0XHRtYXRNdWwoc3RhdGVQcm9qLCBwcmVkaWN0ZWQubWVhbilcblx0XHQpO1xuXHRcdGNvbnN0IG1lYW4gPSBhZGQoXG5cdFx0XHRwcmVkaWN0ZWQubWVhbixcblx0XHRcdG1hdE11bChvcHRpbWFsS2FsbWFuR2FpbiwgaW5ub3ZhdGlvbilcblx0XHQpO1xuXHRcdGlmKGlzTmFOKG1lYW5bMF1bMF0pKXtcblx0XHRcdHRocm93KG5ldyBFcnJvcignTWVhbiBpcyBOYU4gYWZ0ZXIgY29ycmVjdGlvbicpKVxuXHRcdH1cblxuXHRcdGNvbnN0IGNvdmFyaWFuY2UgPSB0aGlzLmdldENvcnJlY3RlZENvdmFyaWFuY2Uoe3ByZWRpY3RlZH0pO1xuXHRcdGNvbnN0IGNvcnJlY3RlZCA9IG5ldyBTdGF0ZSh7bWVhbiwgY292YXJpYW5jZSwgaW5kZXg6IHByZWRpY3RlZC5pbmRleH0pO1xuXHRcdHRoaXMubG9nZ2VyLmRlYnVnKCdDb3JyZWN0aW9uIGRvbmUnLCBjb3JyZWN0ZWQpO1xuXHRcdHJldHVybiBjb3JyZWN0ZWQ7XG5cdH1cbn1cblxubW9kdWxlLmV4cG9ydHMgPSBDb3JlS2FsbWFuRmlsdGVyO1xuIiwiY29uc3QgaWRlbnRpdHkgPSByZXF1aXJlKCcuLi9saW5hbGdlYnJhL2lkZW50aXR5LmpzJyk7XG5cbi8qKlxuKkNyZWF0ZXMgYSBkeW5hbWljIG1vZGVsLCBmb2xsb3dpbmcgY29uc3RhbnQgYWNjZWxlcmF0aW9uIG1vZGVsIHdpdGggcmVzcGVjdCB3aXRoIHRoZSBkaW1lbnNpb25zIHByb3ZpZGVkIGluIHRoZSBvYnNlcnZhdGlvbiBwYXJhbWV0ZXJzXG4qIEBwYXJhbSB7RHluYW1pY0NvbmZpZ30gZHluYW1pY1xuKiBAcGFyYW0ge09ic2VydmF0aW9uQ29uZmlnfSBvYnNlcnZhdGlvblxuKiBAcmV0dXJucyB7RHluYW1pY0NvbmZpZ31cbiovXG5cbm1vZHVsZS5leHBvcnRzID0gZnVuY3Rpb24gKGR5bmFtaWMsIG9ic2VydmF0aW9uKSB7XG5cdGNvbnN0IHRpbWVTdGVwID0gZHluYW1pYy50aW1lU3RlcCB8fCAxO1xuXHRjb25zdCBvYnNlcnZlZFByb2plY3Rpb24gPSBvYnNlcnZhdGlvbi5vYnNlcnZlZFByb2plY3Rpb247XG5cdGNvbnN0IHN0YXRlUHJvamVjdGlvbiA9IG9ic2VydmF0aW9uLnN0YXRlUHJvamVjdGlvbjtcblx0Y29uc3Qgb2JzZXJ2YXRpb25EaW1lbnNpb24gPSBvYnNlcnZhdGlvbi5kaW1lbnNpb247XG5cdGxldCBkaW1lbnNpb247XG5cblx0aWYgKHN0YXRlUHJvamVjdGlvbiAmJiBOdW1iZXIuaXNJbnRlZ2VyKHN0YXRlUHJvamVjdGlvblswXS5sZW5ndGggLyAzKSkge1xuXHRcdGRpbWVuc2lvbiA9IG9ic2VydmF0aW9uLnN0YXRlUHJvamVjdGlvblswXS5sZW5ndGg7XG5cdH0gZWxzZSBpZiAob2JzZXJ2ZWRQcm9qZWN0aW9uKSB7XG5cdFx0ZGltZW5zaW9uID0gb2JzZXJ2ZWRQcm9qZWN0aW9uWzBdLmxlbmd0aCAqIDM7XG5cdH0gZWxzZSBpZiAob2JzZXJ2YXRpb25EaW1lbnNpb24pIHtcblx0XHRkaW1lbnNpb24gPSBvYnNlcnZhdGlvbkRpbWVuc2lvbiAqIDM7XG5cdH0gZWxzZSB7XG5cdFx0dGhyb3cgKG5ldyBFcnJvcignb2JzZXJ2ZWRQcm9qZWN0aW9uIG9yIHN0YXRlUHJvamVjdGlvbiBzaG91bGQgYmUgZGVmaW5lZCBpbiBvYnNlcnZhdGlvbiBpbiBvcmRlciB0byB1c2UgY29uc3RhbnQtc3BlZWQgZmlsdGVyJykpO1xuXHR9XG5cblx0Y29uc3QgYmFzZURpbWVuc2lvbiA9IGRpbWVuc2lvbiAvIDM7XG5cdC8vIFdlIGNvbnN0cnVjdCB0aGUgdHJhbnNpdGlvbiBhbmQgY292YXJpYW5jZSBtYXRyaWNlc1xuXHRjb25zdCB0cmFuc2l0aW9uID0gaWRlbnRpdHkoZGltZW5zaW9uKTtcblx0Zm9yIChsZXQgaSA9IDA7IGkgPCBiYXNlRGltZW5zaW9uOyBpKyspIHtcblx0XHR0cmFuc2l0aW9uW2ldW2kgKyBiYXNlRGltZW5zaW9uXSA9IHRpbWVTdGVwO1xuXHRcdHRyYW5zaXRpb25baV1baSArICgyICogYmFzZURpbWVuc2lvbildID0gMC41ICogKHRpbWVTdGVwICoqIDIpO1xuXHRcdHRyYW5zaXRpb25baSArIGJhc2VEaW1lbnNpb25dW2kgKyAoMiAqIGJhc2VEaW1lbnNpb24pXSA9IHRpbWVTdGVwO1xuXHR9XG5cblx0Y29uc3QgYXJyYXlDb3ZhcmlhbmNlID0gbmV3IEFycmF5KGJhc2VEaW1lbnNpb24pLmZpbGwoMSlcblx0XHQuY29uY2F0KG5ldyBBcnJheShiYXNlRGltZW5zaW9uKS5maWxsKHRpbWVTdGVwICogdGltZVN0ZXApKVxuXHRcdC5jb25jYXQobmV3IEFycmF5KGJhc2VEaW1lbnNpb24pLmZpbGwodGltZVN0ZXAgKiogNCkpO1xuXHRjb25zdCBjb3ZhcmlhbmNlID0gZHluYW1pYy5jb3ZhcmlhbmNlIHx8IGFycmF5Q292YXJpYW5jZTtcblx0cmV0dXJuIE9iamVjdC5hc3NpZ24oe30sIGR5bmFtaWMsIHtkaW1lbnNpb24sIHRyYW5zaXRpb24sIGNvdmFyaWFuY2V9KTtcbn07XG4iLCJjb25zdCBpZGVudGl0eSA9IHJlcXVpcmUoJy4uL2xpbmFsZ2VicmEvaWRlbnRpdHkuanMnKTtcbi8qKlxuKkNyZWF0ZXMgYSBkeW5hbWljIG1vZGVsLCBmb2xsb3dpbmcgY29uc3RhbnQgcG9zaXRpb24gbW9kZWwgd2l0aCByZXNwZWN0IHdpdGggdGhlIGRpbWVuc2lvbnMgcHJvdmlkZWQgaW4gdGhlIG9ic2VydmF0aW9uIHBhcmFtZXRlcnNcbiogQHBhcmFtIHtEeW5hbWljQ29uZmlnfSBkeW5hbWljXG4qIEBwYXJhbSB7T2JzZXJ2YXRpb25Db25maWd9IG9ic2VydmF0aW9uXG4qIEByZXR1cm5zIHtEeW5hbWljQ29uZmlnfVxuKi9cblxubW9kdWxlLmV4cG9ydHMgPSBmdW5jdGlvbiAoZHluYW1pYywgb2JzZXJ2YXRpb24pIHtcblx0bGV0IGRpbWVuc2lvbiA9IGR5bmFtaWMuZGltZW5zaW9uO1xuXHRjb25zdCBvYnNlcnZhdGlvbkRpbWVuc2lvbiA9IG9ic2VydmF0aW9uLmRpbWVuc2lvbjtcblx0Y29uc3Qgb2JzZXJ2ZWRQcm9qZWN0aW9uID0gb2JzZXJ2YXRpb24ub2JzZXJ2ZWRQcm9qZWN0aW9uO1xuXHRjb25zdCBzdGF0ZVByb2plY3Rpb24gPSBvYnNlcnZhdGlvbi5zdGF0ZVByb2plY3Rpb247XG5cdGxldCBjb3ZhcmlhbmNlID0gZHluYW1pYy5jb3ZhcmlhbmNlO1xuXG5cdGlmICghZHluYW1pYy5kaW1lbnNpb24pIHtcblx0XHRpZiAob2JzZXJ2YXRpb25EaW1lbnNpb24pIHtcblx0XHRcdGRpbWVuc2lvbiA9IG9ic2VydmF0aW9uRGltZW5zaW9uO1xuXHRcdH0gZWxzZSBpZiAob2JzZXJ2ZWRQcm9qZWN0aW9uKSB7XG5cdFx0XHRkaW1lbnNpb24gPSBvYnNlcnZlZFByb2plY3Rpb25bMF0ubGVuZ3RoO1xuXHRcdH0gZWxzZSBpZiAoc3RhdGVQcm9qZWN0aW9uKSB7XG5cdFx0XHRkaW1lbnNpb24gPSBzdGF0ZVByb2plY3Rpb25bMF0ubGVuZ3RoO1xuXHRcdH1cblx0fVxuXG5cdGNvbnN0IHRyYW5zaXRpb24gPSBpZGVudGl0eShkaW1lbnNpb24pO1xuXHRjb3ZhcmlhbmNlID0gY292YXJpYW5jZSB8fCBpZGVudGl0eShkaW1lbnNpb24pO1xuXHRyZXR1cm4gT2JqZWN0LmFzc2lnbih7fSwgZHluYW1pYywge2RpbWVuc2lvbiwgdHJhbnNpdGlvbiwgY292YXJpYW5jZX0pO1xufTtcbiIsImNvbnN0IGlkZW50aXR5ID0gcmVxdWlyZSgnLi4vbGluYWxnZWJyYS9pZGVudGl0eS5qcycpO1xuXG4vKipcbipDcmVhdGVzIGEgZHluYW1pYyBtb2RlbCwgZm9sbG93aW5nIGNvbnN0YW50IHBvc2l0aW9uIG1vZGVsIHdpdGggcmVzcGVjdCB3aXRoIHRoZSBkaW1lbnNpb25zIHByb3ZpZGVkIGluIHRoZSBvYnNlcnZhdGlvbiBwYXJhbWV0ZXJzXG4qIEBwYXJhbSB7RHluYW1pY0NvbmZpZ30gZHluYW1pY1xuKiBAcGFyYW0ge09ic2VydmF0aW9uQ29uZmlnfSBvYnNlcnZhdGlvblxuKiBAcmV0dXJucyB7RHluYW1pY0NvbmZpZ31cbiovXG5cbm1vZHVsZS5leHBvcnRzID0gZnVuY3Rpb24gKGR5bmFtaWMsIG9ic2VydmF0aW9uKSB7XG5cdGNvbnN0IHRpbWVTdGVwID0gZHluYW1pYy50aW1lU3RlcCB8fCAxO1xuXHRjb25zdCBvYnNlcnZlZFByb2plY3Rpb24gPSBvYnNlcnZhdGlvbi5vYnNlcnZlZFByb2plY3Rpb247XG5cdGNvbnN0IHN0YXRlUHJvamVjdGlvbiA9IG9ic2VydmF0aW9uLnN0YXRlUHJvamVjdGlvbjtcblx0Y29uc3Qgb2JzZXJ2YXRpb25EaW1lbnNpb24gPSBvYnNlcnZhdGlvbi5kaW1lbnNpb247XG5cdGxldCBkaW1lbnNpb247XG5cblx0aWYgKHN0YXRlUHJvamVjdGlvbiAmJiBOdW1iZXIuaXNJbnRlZ2VyKHN0YXRlUHJvamVjdGlvblswXS5sZW5ndGggLyAyKSkge1xuXHRcdGRpbWVuc2lvbiA9IG9ic2VydmF0aW9uLnN0YXRlUHJvamVjdGlvblswXS5sZW5ndGg7XG5cdH0gZWxzZSBpZiAob2JzZXJ2ZWRQcm9qZWN0aW9uKSB7XG5cdFx0ZGltZW5zaW9uID0gb2JzZXJ2ZWRQcm9qZWN0aW9uWzBdLmxlbmd0aCAqIDI7XG5cdH0gZWxzZSBpZiAob2JzZXJ2YXRpb25EaW1lbnNpb24pIHtcblx0XHRkaW1lbnNpb24gPSBvYnNlcnZhdGlvbkRpbWVuc2lvbiAqIDI7XG5cdH0gZWxzZSB7XG5cdFx0dGhyb3cgKG5ldyBFcnJvcignb2JzZXJ2ZWRQcm9qZWN0aW9uIG9yIHN0YXRlUHJvamVjdGlvbiBzaG91bGQgYmUgZGVmaW5lZCBpbiBvYnNlcnZhdGlvbiBpbiBvcmRlciB0byB1c2UgY29uc3RhbnQtc3BlZWQgZmlsdGVyJykpO1xuXHR9XG5cblx0Y29uc3QgYmFzZURpbWVuc2lvbiA9IGRpbWVuc2lvbiAvIDI7XG5cdC8vIFdlIGNvbnN0cnVjdCB0aGUgdHJhbnNpdGlvbiBhbmQgY292YXJpYW5jZSBtYXRyaWNlc1xuXHRjb25zdCB0cmFuc2l0aW9uID0gaWRlbnRpdHkoZGltZW5zaW9uKTtcblx0Zm9yIChsZXQgaSA9IDA7IGkgPCBiYXNlRGltZW5zaW9uOyBpKyspIHtcblx0XHR0cmFuc2l0aW9uW2ldW2kgKyBiYXNlRGltZW5zaW9uXSA9IHRpbWVTdGVwO1xuXHR9XG5cblx0Y29uc3QgYXJyYXlDb3ZhcmlhbmNlID0gbmV3IEFycmF5KGJhc2VEaW1lbnNpb24pLmZpbGwoMSkuY29uY2F0KG5ldyBBcnJheShiYXNlRGltZW5zaW9uKS5maWxsKHRpbWVTdGVwICogdGltZVN0ZXApKTtcblx0Y29uc3QgY292YXJpYW5jZSA9IGR5bmFtaWMuY292YXJpYW5jZSB8fCBhcnJheUNvdmFyaWFuY2U7XG5cdHJldHVybiBPYmplY3QuYXNzaWduKHt9LCBkeW5hbWljLCB7ZGltZW5zaW9uLCB0cmFuc2l0aW9uLCBjb3ZhcmlhbmNlfSk7XG59O1xuIiwiY29uc3QgQ29yZUthbG1hbkZpbHRlciA9IHJlcXVpcmUoJy4vY29yZS1rYWxtYW4tZmlsdGVyLmpzJyk7XG5cbmNvbnN0IGFycmF5VG9NYXRyaXggPSByZXF1aXJlKCcuLi9saWIvdXRpbHMvYXJyYXktdG8tbWF0cml4LmpzJyk7XG5jb25zdCBzZXREaW1lbnNpb25zID0gcmVxdWlyZSgnLi4vbGliL3NldHVwL3NldC1kaW1lbnNpb25zLmpzJyk7XG5jb25zdCBjaGVja0RpbWVuc2lvbnMgPSByZXF1aXJlKCcuLi9saWIvc2V0dXAvY2hlY2stZGltZW5zaW9ucy5qcycpO1xuY29uc3QgYnVpbGRTdGF0ZVByb2plY3Rpb24gPSByZXF1aXJlKCcuLi9saWIvc2V0dXAvYnVpbGQtc3RhdGUtcHJvamVjdGlvbi5qcycpO1xuY29uc3QgZXh0ZW5kRHluYW1pY0luaXQgPSByZXF1aXJlKCcuLi9saWIvc2V0dXAvZXh0ZW5kLWR5bmFtaWMtaW5pdC5qcycpO1xuY29uc3QgbW9kZWxDb2xsZWN0aW9uID0gcmVxdWlyZSgnLi9tb2RlbC1jb2xsZWN0aW9uLmpzJyk7XG5jb25zdCB0b0Z1bmN0aW9uID0gcmVxdWlyZSgnLi4vbGliL3V0aWxzL3RvLWZ1bmN0aW9uLmpzJyk7XG5jb25zdCBkZWVwQXNzaWduID0gcmVxdWlyZSgnLi4vbGliL3V0aWxzL2RlZXAtYXNzaWduLmpzJyk7XG5jb25zdCBwb2x5bW9ycGhNYXRyaXggPSByZXF1aXJlKCcuLi9saWIvdXRpbHMvcG9seW1vcnBoLW1hdHJpeC5qcycpO1xuY29uc3QgU3RhdGUgPSByZXF1aXJlKCcuL3N0YXRlLmpzJyk7XG5jb25zdCBkaXN0YW5jZU1hdCA9IHJlcXVpcmUoJy4uL2xpYi9saW5hbGdlYnJhL2Rpc3RhbmNlLW1hdC5qcycpO1xuXG4vKipcbipUaGlzIGZ1bmN0aW9uIGZpbGxzIHRoZSBnaXZlbiBvcHRpb25zIGJ5IHN1Y2Nlc3NpdmVseSBjaGVja2luZyBpZiBpdCB1c2VzIGEgcmVnaXN0ZXJlZCBtb2RlbCxcbiogaXQgYnVpbGRzIGFuZCBjaGVja3MgdGhlIGR5bmFtaWMgYW5kIG9ic2VydmF0aW9uIGRpbWVuc2lvbnMsIGJ1aWxkIHRoZSBzdGF0ZVByb2plY3Rpb24gaWYgb25seSBvYnNlcnZlZFByb2plY3Rpb25cbippcyBnaXZlbiwgYW5kIGluaXRpYWxpemUgZHluYW1pYy5pbml0XG4qQHBhcmFtIHtEeW5hbWljQ29uZmlnfSBvcHRpb25zLmR5bmFtaWNcbipAcGFyYW0ge09ic2VydmF0aW9uQ29uZmlnfSBvcHRpb25zLm9ic2VydmF0aW9uXG4qL1xuXG5jb25zdCBzZXR1cE1vZGVsc1BhcmFtZXRlcnMgPSBmdW5jdGlvbiAoe29ic2VydmF0aW9uLCBkeW5hbWljfSkge1xuXHRpZiAodHlwZW9mIChvYnNlcnZhdGlvbi5uYW1lKSA9PT0gJ3N0cmluZycpIHtcblx0XHRvYnNlcnZhdGlvbiA9IG1vZGVsQ29sbGVjdGlvbi5idWlsZE9ic2VydmF0aW9uKG9ic2VydmF0aW9uKTtcblx0fVxuXG5cdGlmICh0eXBlb2YgKGR5bmFtaWMubmFtZSkgPT09ICdzdHJpbmcnKSB7XG5cdFx0ZHluYW1pYyA9IG1vZGVsQ29sbGVjdGlvbi5idWlsZER5bmFtaWMoZHluYW1pYywgb2JzZXJ2YXRpb24pO1xuXHR9XG5cblx0Y29uc3Qgd2l0aERpbWVuc2lvbk9wdGlvbnMgPSBzZXREaW1lbnNpb25zKHtvYnNlcnZhdGlvbiwgZHluYW1pY30pO1xuXHRjb25zdCBjaGVja2VkRGltZW5zaW9uT3B0aW9ucyA9IGNoZWNrRGltZW5zaW9ucyh3aXRoRGltZW5zaW9uT3B0aW9ucyk7XG5cdGNvbnN0IGJ1aWxkU3RhdGVQcm9qZWN0aW9uT3B0aW9ucyA9IGJ1aWxkU3RhdGVQcm9qZWN0aW9uKGNoZWNrZWREaW1lbnNpb25PcHRpb25zKTtcblx0cmV0dXJuIGV4dGVuZER5bmFtaWNJbml0KGJ1aWxkU3RhdGVQcm9qZWN0aW9uT3B0aW9ucyk7XG59O1xuXG4vKipcbipSZXR1cm5zIHRoZSBjb3JyZXNwb25kaW5nIG1vZGVsIHdpdGhvdXQgYXJyYXlzIGFzIHZhbHVlcyBidXQgb25seSBmdW5jdGlvbnNcbipAcGFyYW0ge09ic2VydmF0aW9uQ29uZmlnfSBvYnNlcnZhdGlvblxuKkBwYXJhbSB7RHluYW1pY0NvbmZpZ30gZHluYW1pY1xuKkByZXR1cm5zIHtPYnNlcnZhdGlvbkNvbmZpZywgRHluYW1pY0NvbmZpZ30gbW9kZWwgd2l0aCByZXNwZWN0IG9mIHRoZSBDb3JlIEthbG1hbiBGaWx0ZXIgcHJvcGVydGllc1xuKi9cbmNvbnN0IG1vZGVsc1BhcmFtZXRlcnNUb0NvcmVPcHRpb25zID0gZnVuY3Rpb24gKG1vZGVsVG9CZUNoYW5nZWQpIHtcblx0Y29uc3Qge29ic2VydmF0aW9uLCBkeW5hbWljfSA9IG1vZGVsVG9CZUNoYW5nZWQ7XG5cdHJldHVybiBkZWVwQXNzaWduKG1vZGVsVG9CZUNoYW5nZWQsIHtcblx0XHRvYnNlcnZhdGlvbjoge1xuXHRcdFx0c3RhdGVQcm9qZWN0aW9uOiB0b0Z1bmN0aW9uKHBvbHltb3JwaE1hdHJpeChvYnNlcnZhdGlvbi5zdGF0ZVByb2plY3Rpb24pKSxcblx0XHRcdGNvdmFyaWFuY2U6IHRvRnVuY3Rpb24ocG9seW1vcnBoTWF0cml4KG9ic2VydmF0aW9uLmNvdmFyaWFuY2UsIHtkaW1lbnNpb246IG9ic2VydmF0aW9uLmRpbWVuc2lvbn0pKVxuXHRcdH0sXG5cdFx0ZHluYW1pYzoge1xuXHRcdFx0dHJhbnNpdGlvbjogdG9GdW5jdGlvbihwb2x5bW9ycGhNYXRyaXgoZHluYW1pYy50cmFuc2l0aW9uKSksXG5cdFx0XHRjb3ZhcmlhbmNlOiB0b0Z1bmN0aW9uKHBvbHltb3JwaE1hdHJpeChkeW5hbWljLmNvdmFyaWFuY2UsIHtkaW1lbnNpb246IGR5bmFtaWMuZGltZW5zaW9ufSkpXG5cdFx0fVxuXHR9KTtcbn07XG5cbmNsYXNzIEthbG1hbkZpbHRlciBleHRlbmRzIENvcmVLYWxtYW5GaWx0ZXIge1xuXHQvKipcblx0KiBAcGFyYW0ge0R5bmFtaWNDb25maWd9IG9wdGlvbnMuZHluYW1pY1xuXHQqIEBwYXJhbSB7T2JzZXJ2YXRpb25Db25maWd9IG9wdGlvbnMub2JzZXJ2YXRpb24gdGhlIHN5c3RlbSdzIG9ic2VydmF0aW9uIG1vZGVsXG5cdCovXG5cdGNvbnN0cnVjdG9yKG9wdGlvbnMpIHtcblx0XHRjb25zdCBtb2RlbHNQYXJhbWV0ZXJzID0gc2V0dXBNb2RlbHNQYXJhbWV0ZXJzKG9wdGlvbnMpO1xuXHRcdGNvbnN0IGNvcmVPcHRpb25zID0gbW9kZWxzUGFyYW1ldGVyc1RvQ29yZU9wdGlvbnMobW9kZWxzUGFyYW1ldGVycyk7XG5cblx0XHRzdXBlcihPYmplY3QuYXNzaWduKHt9LCBvcHRpb25zLCBjb3JlT3B0aW9ucykpO1xuXHR9XG5cblx0Y29ycmVjdCh7cHJlZGljdGVkLCBvYnNlcnZhdGlvbn0pIHtcblx0XHRjb25zdCBjb3JlT2JzZXJ2YXRpb24gPSBhcnJheVRvTWF0cml4KHtvYnNlcnZhdGlvbiwgZGltZW5zaW9uOiB0aGlzLm9ic2VydmF0aW9uLmRpbWVuc2lvbn0pO1xuXHRcdHJldHVybiBzdXBlci5jb3JyZWN0KHtwcmVkaWN0ZWQsIG9ic2VydmF0aW9uOiBjb3JlT2JzZXJ2YXRpb259KTtcblx0fVxuXG5cdC8qKlxuXHQqUGVyZm9ybXMgdGhlIHByZWRpY3Rpb24gYW5kIHRoZSBjb3JyZWN0aW9uIHN0ZXBzXG5cdCpAcGFyYW0ge1N0YXRlfSBwcmV2aW91c0NvcnJlY3RlZFxuXHQqQHBhcmFtIHs8QXJyYXkuPE51bWJlcj4+fSBvYnNlcnZhdGlvblxuXHQqQHJldHVybnMge0FycmF5LjxOdW1iZXI+fSB0aGUgbWVhbiBvZiB0aGUgY29ycmVjdGlvbnNcblx0Ki9cblxuXHRmaWx0ZXIoe3ByZXZpb3VzQ29ycmVjdGVkLCBvYnNlcnZhdGlvbn0pIHtcblx0XHRjb25zdCBwcmVkaWN0ZWQgPSBzdXBlci5wcmVkaWN0KHtwcmV2aW91c0NvcnJlY3RlZH0pO1xuXHRcdHJldHVybiB0aGlzLmNvcnJlY3Qoe3ByZWRpY3RlZCwgb2JzZXJ2YXRpb259KTtcblx0fVxuXG5cdC8qKlxuKkZpbHRlcnMgYWxsIHRoZSBvYnNlcnZhdGlvbnNcbipAcGFyYW0ge0FycmF5LjxBcnJheS48TnVtYmVyPj59IG9ic2VydmF0aW9uc1xuKkByZXR1cm5zIHtBcnJheS48TnVtYmVyPn0gdGhlIG1lYW4gb2YgdGhlIGNvcnJlY3Rpb25zXG4qL1xuXHRmaWx0ZXJBbGwob2JzZXJ2YXRpb25zKSB7XG5cdFx0Y29uc3Qge21lYW46IG1lYW5Jbml0LCBjb3ZhcmlhbmNlOiBjb3ZhcmlhbmNlSW5pdCwgaW5kZXg6IGluZGV4SW5pdH0gPSB0aGlzLmR5bmFtaWMuaW5pdDtcblx0XHRsZXQgcHJldmlvdXNDb3JyZWN0ZWQgPSBuZXcgU3RhdGUoe1xuXHRcdFx0bWVhbjogbWVhbkluaXQsXG5cdFx0XHRjb3ZhcmlhbmNlOiBjb3ZhcmlhbmNlSW5pdCxcblx0XHRcdGluZGV4OiBpbmRleEluaXR9KTtcblx0XHRjb25zdCByZXN1bHRzID0gW107XG5cdFx0Zm9yIChjb25zdCBvYnNlcnZhdGlvbiBvZiBvYnNlcnZhdGlvbnMpIHtcblx0XHRcdGNvbnN0IHByZWRpY3RlZCA9IHRoaXMucHJlZGljdCh7cHJldmlvdXNDb3JyZWN0ZWR9KTtcblx0XHRcdHByZXZpb3VzQ29ycmVjdGVkID0gdGhpcy5jb3JyZWN0KHtcblx0XHRcdFx0cHJlZGljdGVkLFxuXHRcdFx0XHRvYnNlcnZhdGlvblxuXHRcdFx0fSk7XG5cdFx0XHRyZXN1bHRzLnB1c2gocHJldmlvdXNDb3JyZWN0ZWQubWVhbik7XG5cdFx0fVxuXG5cdFx0cmV0dXJuIHJlc3VsdHM7XG5cdH1cblxuXHQvKipcblx0KiBSZXR1cm5zIGFuIGVzdGltYXRpb24gb2YgdGhlIGFzeW1wdG90aWMgc3RhdGUgY292YXJpYW5jZSBhcyBleHBsYWluZWQgaW4gaHR0cHM6Ly9lbi53aWtpcGVkaWEub3JnL3dpa2kvS2FsbWFuX2ZpbHRlciNBc3ltcHRvdGljX2Zvcm1cblx0KiBpbiBwcmFjdGljZSB0aGlzIGNhbiBiZSB1c2VkIGFzIGEgaW5pdC5jb3ZhcmlhbmNlIHZhbHVlIGJ1dCBpcyB2ZXJ5IGNvc3RmdWwgY2FsY3VsYXRpb24gKHRoYXQncyB3aHkgdGhpcyBpcyBub3QgbWFkZSBieSBkZWZhdWx0KVxuXHQqIEBwYXJhbSB7TnVtYmVyfSBbdG9sZXJhbmNlPTFlLTZdIHJldHVybnMgd2hlbiB0aGUgbGFzdCB2YWx1ZXMgZGlmZmVyZW5jZXMgYXJlIGxlc3MgdGhhbiB0b2xlcmFuY2Vcblx0KiBAcmV0dXJuIHs8QXJyYXkuPEFycmF5LjxOdW1iZXI+Pj59IGNvdmFyaWFuY2Vcblx0Ki9cblx0YXN5bXB0b3RpY1N0YXRlQ292YXJpYW5jZShsaW1pdEl0ZXJhdGlvbnMgPSAxZTIsIHRvbGVyYW5jZSA9IDFlLTYpIHtcblx0XHRsZXQgcHJldmlvdXNDb3JyZWN0ZWQgPSBzdXBlci5nZXRJbml0U3RhdGUoKTtcblx0XHRsZXQgcHJlZGljdGVkO1xuXHRcdGNvbnN0IHJlc3VsdHMgPSBbXTtcblx0XHRmb3IgKGxldCBpID0gMDsgaSA8IGxpbWl0SXRlcmF0aW9uczsgaSsrKSB7XG5cdFx0XHRsZXQgY291bnQgPSAwO1xuXHRcdFx0cHJlZGljdGVkID0gbmV3IFN0YXRlKHtjb3ZhcmlhbmNlOiBzdXBlci5nZXRQcmVkaWN0ZWRDb3ZhcmlhbmNlKHtwcmV2aW91c0NvcnJlY3RlZH0pfSk7XG5cdFx0XHRwcmV2aW91c0NvcnJlY3RlZCA9IG5ldyBTdGF0ZSh7Y292YXJpYW5jZTogc3VwZXIuZ2V0Q29ycmVjdGVkQ292YXJpYW5jZSh7cHJlZGljdGVkfSl9KTtcblx0XHRcdHJlc3VsdHMucHVzaChwcmV2aW91c0NvcnJlY3RlZC5jb3ZhcmlhbmNlKTtcblx0XHRcdGZvciAobGV0IGogPSAxOyBqIDwgNDsgaisrKSB7XG5cdFx0XHRcdGlmIChkaXN0YW5jZU1hdChwcmV2aW91c0NvcnJlY3RlZC5jb3ZhcmlhbmNlLCByZXN1bHRzW2kgLSBqXSkgPCB0b2xlcmFuY2UpIHtcblx0XHRcdFx0XHRjb3VudCArPSAxO1xuXHRcdFx0XHR9XG5cdFx0XHR9XG5cblx0XHRcdGlmIChjb3VudCA9PT0gMykge1xuXHRcdFx0XHRyZXR1cm4gcmVzdWx0c1tpXTtcblx0XHRcdH1cblx0XHR9XG5cblx0XHR0aHJvdyAobmV3IEVycm9yKCdUaGUgc3RhdGUgY292YXJpYW5jZSBkb2VzIG5vdCBjb252ZXJnZSBhc3ltcHRvdGljYWxseScpKTtcblx0fVxuXG5cdC8qKlxuXHQqIFJldHVybnMgYW4gZXN0aW1hdGlvbiBvZiB0aGUgYXN5bXB0b3RpYyBnYWluLCBhcyBleHBsYWluZWQgaW4gaHR0cHM6Ly9lbi53aWtpcGVkaWEub3JnL3dpa2kvS2FsbWFuX2ZpbHRlciNBc3ltcHRvdGljX2Zvcm1cblx0KiBAcGFyYW0ge051bWJlcn0gW3RvbGVyYW5jZT0xZS02XSByZXR1cm5zIHdoZW4gdGhlIGxhc3QgdmFsdWVzIGRpZmZlcmVuY2VzIGFyZSBsZXNzIHRoYW4gdG9sZXJhbmNlXG5cdCogQHJldHVybiB7PEFycmF5LjxBcnJheS48TnVtYmVyPj4+fSBnYWluXG5cdCovXG5cdGFzeW1wdG90aWNHYWluKHRvbGVyYW5jZSA9IDFlLTYpIHtcblx0XHRjb25zdCBhc3ltcHRvdGljU3RhdGUgPSBuZXcgU3RhdGUoe2NvdmFyaWFuY2U6IHRoaXMuYXN5bXB0b3RpY1N0YXRlQ292YXJpYW5jZSh0b2xlcmFuY2UpfSk7XG5cdFx0cmV0dXJuIHN1cGVyLmdldEdhaW4oe3ByZXZpb3VzQ29ycmVjdGVkOiBhc3ltcHRvdGljU3RhdGV9KTtcblx0fVxufVxuXG5tb2R1bGUuZXhwb3J0cyA9IEthbG1hbkZpbHRlcjtcbiIsImNvbnN0IGVsZW1XaXNlID0gcmVxdWlyZSgnLi9lbGVtLXdpc2UnKTtcbi8qKlxuKiBBZGQgbWF0cml4ZXMgdG9nZXRoZXJcbiogQHBhcmFtIHsuLi48QXJyYXkuPEFycmF5LjxOdW1iZXI+Pn0gYXJncyBsaXN0IG9mIG1hdHJpeFxuKiBAcmV0dXJucyB7QXJyYXkuPEFycmF5LjxOdW1iZXI+Pn0gc3VtXG4qL1xubW9kdWxlLmV4cG9ydHMgPSBmdW5jdGlvbiAoLi4uYXJncykge1xuXHRyZXR1cm4gZWxlbVdpc2UoYXJncywgYXJnczIgPT4ge1xuXHRcdHJldHVybiBhcmdzMi5yZWR1Y2UoKGEsIGIpID0+IGEgKyBiLCAwKTtcblx0fSk7XG59O1xuIiwiY29uc3QgemVyb3MgPSByZXF1aXJlKCcuL3plcm9zJyk7XG5cbm1vZHVsZS5leHBvcnRzID0gZnVuY3Rpb24gKG1hdCkge1xuXHRjb25zdCByZXN1bHQgPSB6ZXJvcyhtYXQubGVuZ3RoLCBtYXQubGVuZ3RoKTtcblxuXHRmb3IgKGNvbnN0IFtpLCBlbGVtZW50XSBvZiBtYXQuZW50cmllcygpKSB7XG5cdFx0cmVzdWx0W2ldW2ldID0gZWxlbWVudDtcblx0fVxuXG5cdHJldHVybiByZXN1bHQ7XG59O1xuIiwiY29uc3QgdHJhY2UgPSByZXF1aXJlKCcuL3RyYWNlLmpzJyk7XG5jb25zdCB0cmFuc3Bvc2UgPSByZXF1aXJlKCcuL3RyYW5zcG9zZS5qcycpO1xuY29uc3QgbWF0U3ViID0gcmVxdWlyZSgnLi9zdWIuanMnKTtcbmNvbnN0IG1hdE11bCA9IHJlcXVpcmUoJy4vbWF0LW11bC5qcycpO1xuY29uc3Qgc3VtID0gcmVxdWlyZSgnLi9zdW0uanMnKTtcblxuLy8gW0Zyb2Jlbml1cyBub3JtXShodHRwczovL2VuLndpa2lwZWRpYS5vcmcvd2lraS9NYXRyaXhfbm9ybSNGcm9iZW5pdXNfbm9ybSApXG5tb2R1bGUuZXhwb3J0cyA9IGZ1bmN0aW9uIChhcnJheTEsIGFycmF5Mikge1xuXHRpZiAodHlwZW9mIChhcnJheTEpID09PSAndW5kZWZpbmVkJykge1xuXHRcdHJldHVybiBzdW0oYXJyYXkyKTtcblx0fVxuXG5cdGlmICh0eXBlb2YgKGFycmF5MikgPT09ICd1bmRlZmluZWQnKSB7XG5cdFx0cmV0dXJuIHN1bShhcnJheTEpO1xuXHR9XG5cblx0Y29uc3QgbSA9IG1hdFN1YihhcnJheTEsIGFycmF5Mik7XG5cdGNvbnN0IHAgPSBtYXRNdWwodHJhbnNwb3NlKG0pLCBtKTtcblx0cmV0dXJuIE1hdGguc3FydCh0cmFjZShwKSk7XG59O1xuIiwiLyoqXG4qIEBjYWxsYmFjayBlbGVtV2lzZUNiXG4qIEBwYXJhbSB7QXJyYXkuPE51bWJlcj59IGFyclxuKiBAcGFyYW0ge051bWJlcn0gcm93SWRcbiogQHBhcmFtIHtOdW1iZXJ9IGNvbElkXG4qL1xuLyoqXG4qIHJ1biBhIGZ1bmN0aW9uIG9uIGNlbGwgcGVyIGNlbGwgZm9yIGVhY2ggTWF0cml4ZXNcbiogQHBhcmFtIHs8QXJyYXkuPEFycmF5LjxBcnJheS48TnVtYmVyPj4+fSBhcnJNYXRyaXhlcyBsaXN0IG9mIG1hdHJpeGVzXG4qIEBwYXJhbSB7ZWxlbVdpc2VDYn0gZm5cbiogQHJldHVybnMge0FycmF5LjxBcnJheS48TnVtYmVyPj59IHJlc3VsdGluZyBtYXRyaXhcbiogQGV4YW1wbGVcbi8vIHRoaXMgd2lsbCBkbyBtMSArIG0yICsgbTMgKyBtNCBvbiBtYXRyaXhlc1xuZWxlbVdpc2UoW20xLCBtMiwgbTMsIG00XSwgYXJnczIgPT4ge1xuXHRyZXR1cm4gYXJnczIucmVkdWNlKChhLCBiKSA9PiBhICsgYiwgMCk7XG59KTtcbiovXG5cbm1vZHVsZS5leHBvcnRzID0gZnVuY3Rpb24gKGFycmF5TWF0cml4ZXMsIGZuKSB7XG5cdHJldHVybiBhcnJheU1hdHJpeGVzWzBdLm1hcCgocm93LCByb3dJZCkgPT4ge1xuXHRcdHJldHVybiByb3cubWFwKChjZWxsLCBjb2xJZCkgPT4ge1xuXHRcdFx0Y29uc3QgYXJyYXkgPSBhcnJheU1hdHJpeGVzLm1hcChtID0+IG1bcm93SWRdW2NvbElkXSk7XG5cdFx0XHRyZXR1cm4gZm4oYXJyYXksIHJvd0lkLCBjb2xJZCk7XG5cdFx0fSk7XG5cdH0pO1xufTtcblxuIiwibW9kdWxlLmV4cG9ydHMgPSBmdW5jdGlvbiAoc3RhdGVTaXplKSB7XG5cdGNvbnN0IGlkZW50aXR5QXJyYXkgPSBbXTtcblx0Zm9yIChsZXQgaSA9IDA7IGkgPCBzdGF0ZVNpemU7IGkrKykge1xuXHRcdGNvbnN0IHJvd0lkZW50aXR5ID0gW107XG5cdFx0Zm9yIChsZXQgaiA9IDA7IGogPCBzdGF0ZVNpemU7IGorKykge1xuXHRcdFx0aWYgKGkgPT09IGopIHtcblx0XHRcdFx0cm93SWRlbnRpdHkucHVzaCgxKTtcblx0XHRcdH0gZWxzZSB7XG5cdFx0XHRcdHJvd0lkZW50aXR5LnB1c2goMCk7XG5cdFx0XHR9XG5cdFx0fVxuXG5cdFx0aWRlbnRpdHlBcnJheS5wdXNoKHJvd0lkZW50aXR5KTtcblx0fVxuXG5cdHJldHVybiBpZGVudGl0eUFycmF5O1xufTtcbiIsImNvbnN0IG1hdHJpeEludmVyc2UgPSByZXF1aXJlKCdtYXRyaXgtaW52ZXJzZScpO1xuXG5tb2R1bGUuZXhwb3J0cyA9IGZ1bmN0aW9uIChtKSB7XG5cdHJldHVybiBtYXRyaXhJbnZlcnNlKG0pO1xufTtcbiIsIi8qKlxuKiBNdWx0aXBseSAyIG1hdHJpeGVzIHRvZ2V0aGVyXG4qIEBwYXJhbSB7PEFycmF5LjxBcnJheS48TnVtYmVyPj59IG0xXG4qIEBwYXJhbSB7PEFycmF5LjxBcnJheS48TnVtYmVyPj59IG0yXG4qIEByZXR1cm5zIHtBcnJheS48QXJyYXkuPE51bWJlcj4+fVxuKi9cbm1vZHVsZS5leHBvcnRzID0gZnVuY3Rpb24gKG0xLCBtMikge1xuXHQvLyBDb25zb2xlLmxvZyh7bTEsIG0yfSk7XG5cdGNvbnN0IHJlc3VsdCA9IFtdO1xuXHRmb3IgKGxldCBpID0gMDsgaSA8IG0xLmxlbmd0aDsgaSsrKSB7XG5cdFx0cmVzdWx0W2ldID0gW107XG5cdFx0Zm9yIChsZXQgaiA9IDA7IGogPCBtMlswXS5sZW5ndGg7IGorKykge1xuXHRcdFx0bGV0IHN1bSA9IDA7XG5cdFx0XHRmb3IgKGxldCBrID0gMDsgayA8IG0xWzBdLmxlbmd0aDsgaysrKSB7XG5cdFx0XHRcdHN1bSArPSBtMVtpXVtrXSAqIG0yW2tdW2pdO1xuXHRcdFx0fVxuXG5cdFx0XHRyZXN1bHRbaV1bal0gPSBzdW07XG5cdFx0fVxuXHR9XG5cblx0cmV0dXJuIHJlc3VsdDtcbn07XG4iLCIvKipcbipUaGlzIGZ1bmN0aW9uIHJldHVybnMgdGhlIHN0YXRlUHJvamVjdGlvbiBwYWRlZCB3aXRoIHplcm9zIHdpdGggcmVzcGVjdCB0byBhIGdpdmVuXG4qb2JzZXJ2ZWRQcm9qZWN0aW9uXG4qQHBhcmFtIHtBcnJheS48TnVtYmVyPiB8IEFycmF5LjxBcnJheS48TnVtYmVyPj59IGFycmF5IHRoZSBhcnJheSB3ZSBuZWVkIHRvIHBhZFxuKkBwYXJhbSB7TnVtYmVyfSBkaW1lbnNpb24gaW4gb3VyIGNhc2UsIHRoZSBkeW5hbWljIGRpbWVuc2lvblxuKkByZXR1cm5zIHtBcnJheS48TnVtYmVyPiB8IEFycmF5LjxBcnJheS48TnVtYmVyPj59IHBhZGVkIGFycmF5XG4qL1xubW9kdWxlLmV4cG9ydHMgPSBmdW5jdGlvbiAoYXJyYXksIHtkaW1lbnNpb259KSB7XG5cdGNvbnN0IGwgPSBhcnJheVswXS5sZW5ndGg7XG5cdGlmIChkaW1lbnNpb24gPCBsKSB7XG5cdFx0dGhyb3cgKG5ldyBUeXBlRXJyb3IoJ0R5bmFtaWMgZGltZW5zaW9uIGRvZXMgbm90IG1hdGNoIHdpdGggb2JzZXJ2ZWRQcm9qZWN0aW9uJykpO1xuXHR9XG5cblx0Zm9yIChsZXQgaSA9IDA7IGkgPCBsOyBpKyspIHtcblx0XHRmb3IgKGxldCBqID0gMDsgaiA8IGRpbWVuc2lvbiAtIGw7IGorKykge1xuXHRcdFx0YXJyYXlbaV0ucHVzaCgwKTtcblx0XHR9XG5cdH1cblxuXHRyZXR1cm4gYXJyYXk7XG59O1xuIiwiY29uc3QgZWxlbVdpc2UgPSByZXF1aXJlKCcuL2VsZW0td2lzZScpO1xuXG5tb2R1bGUuZXhwb3J0cyA9IGZ1bmN0aW9uICguLi5hcmdzKSB7XG5cdHJldHVybiBlbGVtV2lzZShhcmdzLCAoW2EsIGJdKSA9PiBhIC0gYik7XG59O1xuIiwiLy8gU3VtIGFsbCB0aGUgdGVybXMgb2YgYSBnaXZlbiBtYXRyaXhcbm1vZHVsZS5leHBvcnRzID0gZnVuY3Rpb24gKGFycmF5KSB7XG5cdGxldCBzID0gMDtcblx0Zm9yIChsZXQgaSA9IDA7IGkgPCBhcnJheS5sZW5ndGg7IGkrKykge1xuXHRcdGZvciAobGV0IGogPSAwOyBqIDwgYXJyYXkubGVuZ3RoOyBqKyspIHtcblx0XHRcdHMgKz0gYXJyYXlbaV1bal07XG5cdFx0fVxuXHR9XG5cblx0cmV0dXJuIHM7XG59O1xuIiwibW9kdWxlLmV4cG9ydHMgPSBmdW5jdGlvbiAoYXJyYXkpIHtcblx0bGV0IGRpYWcgPSAwO1xuXHRmb3IgKGNvbnN0IFtyb3csIGVsZW1lbnRdIG9mIGFycmF5LmVudHJpZXMoKSkge1xuXHRcdGRpYWcgKz0gZWxlbWVudFtyb3ddO1xuXHR9XG5cblx0cmV0dXJuIGRpYWc7XG59O1xuIiwibW9kdWxlLmV4cG9ydHMgPSBmdW5jdGlvbiAoYXJyYXkpIHtcblx0cmV0dXJuIGFycmF5WzBdLm1hcCgoY29sLCBpKSA9PiBhcnJheS5tYXAocm93ID0+IHJvd1tpXSkpO1xufTtcbiIsIm1vZHVsZS5leHBvcnRzID0gZnVuY3Rpb24gKHJvd3MsIGNvbHMpIHtcblx0cmV0dXJuIG5ldyBBcnJheShyb3dzKS5maWxsKDEpLm1hcCgoKSA9PiBuZXcgQXJyYXkoY29scykuZmlsbCgwKSk7XG59O1xuIiwiY29uc3QgcmVnaXN0ZXJlZER5bmFtaWNNb2RlbHMgPSB7XG5cdCdjb25zdGFudC1wb3NpdGlvbic6IHJlcXVpcmUoJy4uL2xpYi9keW5hbWljL2NvbnN0YW50LXBvc2l0aW9uLmpzJyksXG5cdCdjb25zdGFudC1zcGVlZCc6IHJlcXVpcmUoJy4uL2xpYi9keW5hbWljL2NvbnN0YW50LXNwZWVkLmpzJyksXG5cdCdjb25zdGFudC1hY2NlbGVyYXRpb24nOiByZXF1aXJlKCcuLi9saWIvZHluYW1pYy9jb25zdGFudC1hY2NlbGVyYXRpb24uanMnKVxufTtcbmNvbnN0IHJlZ2lzdGVyZWRPYnNlcnZhdGlvbk1vZGVscyA9IHtcblx0c2Vuc29yczogcmVxdWlyZSgnLi4vbGliL29ic2VydmF0aW9uL3NlbnNvci5qcycpXG59O1xuXG4vKipcbipSZWdpc3Rlck9ic2VydmF0aW9uIGVuYWJsZXMgdG8gY3JlYXRlIGEgbmV3IG9ic2VydmF0aW9uIG1vZGVsIGFuZCBzdG9jayBpdFxuKiBAcGFyYW0ge1N0cmluZ30gbmFtZVxuKiBAY2FsbGJhY2sgZm4gdGhlIGZ1bmN0aW9uIGNvcnJlc3BvbmRpbmcgdG8gdGhlIGRlc2lyZWQgbW9kZWxcbiovXG5cbi8qKlxuKnJlZ2lzdGVyRHluYW1pYyBlbmFibGVzIHRvIGNyZWF0ZSBhIG5ldyBkeW5hbWljIG1vZGVsIGFuZCBzdG9ja3MgaXRcbiogQHBhcmFtIHtTdHJpbmd9IG5hbWVcbiogQGNhbGxiYWNrIGZuIHRoZSBmdW5jdGlvbiBjb3JyZXNwb25kaW5nIHRvIHRoZSBkZXNpcmVkIG1vZGVsXG4qL1xuXG4vKipcbipidWlsZE9ic2VydmF0aW9uIGVuYWJsZXMgdG8gYnVpbGQgYSBtb2RlbCBnaXZlbiBhbiBvYnNlcnZhdGlvbiBjb25maWd1cmF0aW9uXG4qIEBwYXJhbSB7T2JzZXJ2YXRpb25Db25maWd9IG9ic2VydmF0aW9uXG4qIEByZXR1cm5zIHtPYnNlcnZhdGlvbkNvbmZpZ30gdGhlIGNvbmZpZ3VyYXRpb24gd2l0aCByZXNwZWN0IHRvIHRoZSBtb2RlbFxuKi9cblxuLyoqXG4qYnVpbGREeW5hbWljIGVuYWJsZXMgdG8gYnVpbGQgYSBtb2RlbCBnaXZlbiBkeW5hbWljIGFuZCBvYnNlcnZhdGlvbiBjb25maWd1cmF0aW9uc1xuKiBAcGFyYW0ge0R5bmFtaWNDb25maWd9IGR5bmFtaWNcbiogQHBhcmFtIHtPYnNlcnZhdGlvbkNvbmZpZ30gb2JzZXJ2YXRpb25cbiogQHJldHVybnMge0R5bmFtaWNDb25maWd9IHRoZSBkeW5hbWljIGNvbmZpZ3VyYXRpb24gd2l0aCByZXNwZWN0IHRvIHRoZSBtb2RlbFxuKi9cblxubW9kdWxlLmV4cG9ydHMgPSB7XG5cdHJlZ2lzdGVyT2JzZXJ2YXRpb246IChuYW1lLCBmbikgPT4ge1xuXHRcdHJlZ2lzdGVyZWRPYnNlcnZhdGlvbk1vZGVsc1tuYW1lXSA9IGZuO1xuXHR9LFxuXHRyZWdpc3RlckR5bmFtaWM6IChuYW1lLCBmbikgPT4ge1xuXHRcdHJlZ2lzdGVyZWREeW5hbWljTW9kZWxzW25hbWVdID0gZm47XG5cdH0sXG5cdGJ1aWxkT2JzZXJ2YXRpb246IG9ic2VydmF0aW9uID0+IHtcblx0XHRpZiAoIXJlZ2lzdGVyZWRPYnNlcnZhdGlvbk1vZGVsc1tvYnNlcnZhdGlvbi5uYW1lXSkge1xuXHRcdFx0dGhyb3cgKG5ldyBFcnJvcignVGhlIHByb3ZpZGVkIG9ic2VydmF0aW9uIG1vZGVsIG5hbWUgaXMgbm90IHJlZ2lzdGVyZWQnKSk7XG5cdFx0fVxuXG5cdFx0cmV0dXJuIHJlZ2lzdGVyZWRPYnNlcnZhdGlvbk1vZGVsc1tvYnNlcnZhdGlvbi5uYW1lXShvYnNlcnZhdGlvbik7XG5cdH0sXG5cdGJ1aWxkRHluYW1pYzogKGR5bmFtaWMsIG9ic2VydmF0aW9uKSA9PiB7XG5cdFx0aWYgKCFyZWdpc3RlcmVkRHluYW1pY01vZGVsc1tkeW5hbWljLm5hbWVdKSB7XG5cdFx0XHR0aHJvdyAobmV3IEVycm9yKCdUaGUgcHJvdmlkZWQgZHluYW1pYyBtb2RlbCBuYW1lIGlzIG5vdCByZWdpc3RlcmVkJykpO1xuXHRcdH1cblxuXHRcdHJldHVybiByZWdpc3RlcmVkRHluYW1pY01vZGVsc1tkeW5hbWljLm5hbWVdKGR5bmFtaWMsIG9ic2VydmF0aW9uKTtcblx0fVxufTtcbiIsImNvbnN0IGlkZW50aXR5ID0gcmVxdWlyZSgnLi4vbGluYWxnZWJyYS9pZGVudGl0eS5qcycpO1xuY29uc3QgcG9seW1vcnBoTWF0cml4ID0gcmVxdWlyZSgnLi4vdXRpbHMvcG9seW1vcnBoLW1hdHJpeC5qcycpO1xuXG4vKipcbiogQHBhcmFtIHtOdW1iZXJ9IHNlbnNvckRpbWVuc2lvblxuKiBAcGFyYW0ge0NvdmFyaWFuY2VQYXJhbX0gc2Vuc29yQ292YXJpYW5jZVxuKiBAcGFyYW0ge051bWJlcn0gblNlbnNvcnNcbiogQHJldHVybnMge09ic2VydmF0aW9uQ29uZmlnfVxuKi9cblxubW9kdWxlLmV4cG9ydHMgPSBmdW5jdGlvbiAob3B0aW9ucykge1xuXHRjb25zdCB7c2Vuc29yRGltZW5zaW9uID0gMSwgc2Vuc29yQ292YXJpYW5jZSA9IDEsIG5TZW5zb3JzID0gMX0gPSBvcHRpb25zO1xuXHRjb25zdCBzZW5zb3JzQ292YXJpYW5jZSA9IHBvbHltb3JwaE1hdHJpeChzZW5zb3JDb3ZhcmlhbmNlLCB7ZGltZW5zaW9uOiBzZW5zb3JEaW1lbnNpb259KTtcblx0Y29uc3Qgb25lU2Vuc29yT2JzZXJ2ZWRQcm9qZWN0aW9uID0gaWRlbnRpdHkoc2Vuc29yRGltZW5zaW9uKTtcblx0bGV0IGNvbmNhdGVuYXRlZE9ic2VydmVkUHJvamVjdGlvbiA9IFtdO1xuXHRsZXQgY29uY2F0ZW5hdGVkQ292YXJpYW5jZSA9IFtdO1xuXHRmb3IgKGxldCBpID0gMDsgaSA8IG5TZW5zb3JzOyBpKyspIHtcblx0XHRjb25jYXRlbmF0ZWRPYnNlcnZlZFByb2plY3Rpb24gPSBjb25jYXRlbmF0ZWRPYnNlcnZlZFByb2plY3Rpb24uY29uY2F0KG9uZVNlbnNvck9ic2VydmVkUHJvamVjdGlvbik7XG5cdFx0Y29uY2F0ZW5hdGVkQ292YXJpYW5jZSA9IGNvbmNhdGVuYXRlZENvdmFyaWFuY2UuY29uY2F0KHNlbnNvcnNDb3ZhcmlhbmNlKTtcblx0fVxuXG5cdGNvbnN0IGZvcm1hdHRlZENvdmFyaWFuY2UgPSBwb2x5bW9ycGhNYXRyaXgoY29uY2F0ZW5hdGVkQ292YXJpYW5jZSwge2RpbWVuc2lvbjogblNlbnNvcnMgKiBzZW5zb3JEaW1lbnNpb259KTtcblx0cmV0dXJuIE9iamVjdC5hc3NpZ24oe30sIG9wdGlvbnMsIHtcblx0XHRkaW1lbnNpb246IHNlbnNvckRpbWVuc2lvbiAqIG5TZW5zb3JzLFxuXHRcdG9ic2VydmVkUHJvamVjdGlvbjogY29uY2F0ZW5hdGVkT2JzZXJ2ZWRQcm9qZWN0aW9uLFxuXHRcdGNvdmFyaWFuY2U6IGZvcm1hdHRlZENvdmFyaWFuY2Vcblx0fSk7XG59O1xuIiwiY29uc3QgcGFkV2l0aFplcm9zID0gcmVxdWlyZSgnLi4vbGluYWxnZWJyYS9wYWQtd2l0aC16ZXJvcy5qcycpO1xuY29uc3QgaWRlbnRpdHkgPSByZXF1aXJlKCcuLi9saW5hbGdlYnJhL2lkZW50aXR5LmpzJyk7XG4vKipcbipCdWlsZHMgdGhlIHN0YXRlUHJvamVjdGlvbiBnaXZlbiBhbiBvYnNlcnZlZFByb2plY3Rpb25cbipAcGFyYW0ge09ic2VydmF0aW9uQ29uZmlnfSBvYnNlcnZhdGlvblxuKkBwYXJhbSB7RHluYW1pY0NvbmZpZ30gZHluYW1pY1xuKkByZXR1cm5zIHtPYnNlcnZhdGlvbkNvbmZpZywgRHluYW1pY0NvbmZpZ30gdGhlIG1vZGVsIGNvbnRhaW5pbmcgdGhlIGNyZWF0ZWQgc3RhdGVQcm9qZWN0aW9uXG4qL1xuXG5tb2R1bGUuZXhwb3J0cyA9IGZ1bmN0aW9uICh7b2JzZXJ2YXRpb24sIGR5bmFtaWN9KSB7XG5cdGNvbnN0IHtvYnNlcnZlZFByb2plY3Rpb24sIHN0YXRlUHJvamVjdGlvbn0gPSBvYnNlcnZhdGlvbjtcblx0Y29uc3Qgb2JzZXJ2YXRpb25EaW1lbnNpb24gPSBvYnNlcnZhdGlvbi5kaW1lbnNpb247XG5cdGNvbnN0IGR5bmFtaWNEaW1lbnNpb24gPSBkeW5hbWljLmRpbWVuc2lvbjtcblx0aWYgKG9ic2VydmVkUHJvamVjdGlvbiAmJiBzdGF0ZVByb2plY3Rpb24pIHtcblx0XHR0aHJvdyAobmV3IFR5cGVFcnJvcignWW91IGNhbm5vdCB1c2UgYm90aCBvYnNlcnZlZFByb2plY3Rpb24gYW5kIHN0YXRlUHJvamVjdGlvbicpKTtcblx0fVxuXG5cdGlmIChvYnNlcnZlZFByb2plY3Rpb24pIHtcblx0XHRyZXR1cm4ge1xuXHRcdFx0b2JzZXJ2YXRpb246IE9iamVjdC5hc3NpZ24oe30sIG9ic2VydmF0aW9uLCB7XG5cdFx0XHRcdHN0YXRlUHJvamVjdGlvbjogcGFkV2l0aFplcm9zKG9ic2VydmVkUHJvamVjdGlvbiwge2RpbWVuc2lvbjogZHluYW1pY0RpbWVuc2lvbn0pXG5cdFx0XHR9KSxcblx0XHRcdGR5bmFtaWNcblx0XHR9O1xuXHR9XG5cblx0aWYgKG9ic2VydmF0aW9uRGltZW5zaW9uICYmIGR5bmFtaWNEaW1lbnNpb24pIHtcblx0XHRjb25zdCBvYnNlcnZhdGlvbk1hdHJpeCA9IGlkZW50aXR5KG9ic2VydmF0aW9uRGltZW5zaW9uKTtcblx0XHRyZXR1cm4ge1xuXHRcdFx0b2JzZXJ2YXRpb246IE9iamVjdC5hc3NpZ24oe30sIG9ic2VydmF0aW9uLCB7XG5cdFx0XHRcdHN0YXRlUHJvamVjdGlvbjogcGFkV2l0aFplcm9zKG9ic2VydmF0aW9uTWF0cml4LCB7ZGltZW5zaW9uOiBkeW5hbWljRGltZW5zaW9ufSlcblx0XHRcdH0pLFxuXHRcdFx0ZHluYW1pY1xuXHRcdH07XG5cdH1cblxuXHRyZXR1cm4ge29ic2VydmF0aW9uLCBkeW5hbWljfTtcbn07XG4iLCIvKipcbipWZXJpZmllcyB0aGF0IGR5bmFtaWMuZGltZW5zaW9uIGFuZCBvYnNlcnZhdGlvbi5kaW1lbnNpb24gYXJlIHNldFxuKkBwYXJhbSB7T2JzZXJ2YXRpb25Db25maWd9IG9ic2VydmF0aW9uXG4qQHBhcmFtIHtEeW5hbWljQ29uZmlnfSBkeW5hbWljXG4qL1xuXG5tb2R1bGUuZXhwb3J0cyA9IGZ1bmN0aW9uICh7b2JzZXJ2YXRpb24sIGR5bmFtaWN9KSB7XG5cdGNvbnN0IGR5bmFtaWNEaW1lbnNpb24gPSBkeW5hbWljLmRpbWVuc2lvbjtcblx0Y29uc3Qgb2JzZXJ2YXRpb25EaW1lbnNpb24gPSBvYnNlcnZhdGlvbi5kaW1lbnNpb247XG5cdGlmICghZHluYW1pY0RpbWVuc2lvbiB8fCAhb2JzZXJ2YXRpb25EaW1lbnNpb24pIHtcblx0XHR0aHJvdyAobmV3IFR5cGVFcnJvcignRGltZW5zaW9uIGlzIG5vdCBzZXQnKSk7XG5cdH1cblxuXHRyZXR1cm4ge29ic2VydmF0aW9uLCBkeW5hbWljfTtcbn07XG4iLCJjb25zdCBkaWFnID0gcmVxdWlyZSgnLi4vbGluYWxnZWJyYS9kaWFnLmpzJyk7XG5cbi8qKlxuKkluaXRpYWxpemVzIHRoZSBkeW5hbWljLmluaXQgd2hlbiBub3QgZ2l2ZW5cbipAcGFyYW0ge09ic2VydmF0aW9uQ29uZmlnfSBvYnNlcnZhdGlvblxuKkBwYXJhbSB7RHluYW1pY0NvbmZpZ30gZHluYW1pY1xuKkByZXR1cm5zIHtPYnNlcnZhdGlvbkNvbmZpZywgRHluYW1pY0NvbmZpZ31cbiovXG5cbm1vZHVsZS5leHBvcnRzID0gZnVuY3Rpb24gKHtvYnNlcnZhdGlvbiwgZHluYW1pY30pIHtcblx0aWYgKCFkeW5hbWljLmluaXQpIHtcblx0XHRjb25zdCBodWdlID0gMWU2O1xuXHRcdGNvbnN0IGR5bmFtaWNEaW1lbnNpb24gPSBkeW5hbWljLmRpbWVuc2lvbjtcblx0XHRjb25zdCBtZWFuQXJyYXkgPSBuZXcgQXJyYXkoZHluYW1pY0RpbWVuc2lvbikuZmlsbCgwKTtcblx0XHRjb25zdCBjb3ZhcmlhbmNlQXJyYXkgPSBuZXcgQXJyYXkoZHluYW1pY0RpbWVuc2lvbikuZmlsbChodWdlKTtcblx0XHRjb25zdCB3aXRoSW5pdE9wdGlvbnMgPSB7XG5cdFx0XHRvYnNlcnZhdGlvbixcblx0XHRcdGR5bmFtaWM6IE9iamVjdC5hc3NpZ24oe30sIGR5bmFtaWMsIHtcblx0XHRcdFx0aW5pdDoge1xuXHRcdFx0XHRcdG1lYW46IG1lYW5BcnJheS5tYXAoZWxlbWVudCA9PiBbZWxlbWVudF0pLFxuXHRcdFx0XHRcdGNvdmFyaWFuY2U6IGRpYWcoY292YXJpYW5jZUFycmF5KVxuXHRcdFx0XHR9XG5cdFx0XHR9KVxuXHRcdH07XG5cdFx0cmV0dXJuIHdpdGhJbml0T3B0aW9ucztcblx0fVxuXG5cdHJldHVybiB7b2JzZXJ2YXRpb24sIGR5bmFtaWN9O1xufTtcbiIsIi8qKlxuKlZlcmlmaWVzIHRoYXQgZGltZW5zaW9ucyBhcmUgbWF0Y2hpbmcgYW5kIHNldCBkeW5hbWljLmRpbWVuc2lvbiBhbmQgb2JzZXJ2YXRpb24uZGltZW5zaW9uXG4qIHdpdGggcmVzcGVjdCBvZiBzdGF0ZVByb2plY3Rpb24gYW5kIHRyYW5zaXRpb24gZGltZW5zaW9uc1xuKkBwYXJhbSB7T2JzZXJ2YXRpb25Db25maWd9IG9ic2VydmF0aW9uXG4qQHBhcmFtIHtEeW5hbWljQ29uZmlnfSBkeW5hbWljXG4qQHJldHVybnMge09ic2VydmF0aW9uQ29uZmlnLCBEeW5hbWljQ29uZmlnfVxuKi9cblxubW9kdWxlLmV4cG9ydHMgPSBmdW5jdGlvbiAoe29ic2VydmF0aW9uLCBkeW5hbWljfSkge1xuXHRjb25zdCBzdGF0ZVByb2plY3Rpb24gPSBvYnNlcnZhdGlvbi5zdGF0ZVByb2plY3Rpb247XG5cdGNvbnN0IHRyYW5zaXRpb24gPSBkeW5hbWljLnRyYW5zaXRpb247XG5cdGNvbnN0IGR5bmFtaWNEaW1lbnNpb24gPSBkeW5hbWljLmRpbWVuc2lvbjtcblx0Y29uc3Qgb2JzZXJ2YXRpb25EaW1lbnNpb24gPSBvYnNlcnZhdGlvbi5kaW1lbnNpb247XG5cblx0aWYgKGR5bmFtaWNEaW1lbnNpb24gJiYgb2JzZXJ2YXRpb25EaW1lbnNpb24gJiYgQXJyYXkuaXNBcnJheShzdGF0ZVByb2plY3Rpb24pKSB7XG5cdFx0aWYgKGR5bmFtaWNEaW1lbnNpb24gIT09IHN0YXRlUHJvamVjdGlvblswXS5sZW5ndGggfHwgb2JzZXJ2YXRpb25EaW1lbnNpb24gIT09IHN0YXRlUHJvamVjdGlvbi5sZW5ndGgpIHtcblx0XHRcdHRocm93IChuZXcgVHlwZUVycm9yKCdzdGF0ZVByb2plY3Rpb24gZGltZW5zaW9ucyBub3QgbWF0Y2hpbmcgd2l0aCBvYnNlcnZhdGlvbiBhbmQgZHluYW1pYyBkaW1lbnNpb25zJykpO1xuXHRcdH1cblx0fVxuXG5cdGlmIChkeW5hbWljRGltZW5zaW9uICYmIEFycmF5LmlzQXJyYXkodHJhbnNpdGlvbikpIHtcblx0XHRpZiAoZHluYW1pY0RpbWVuc2lvbiAhPT0gdHJhbnNpdGlvbi5sZW5ndGgpIHtcblx0XHRcdHRocm93IChuZXcgVHlwZUVycm9yKCd0cmFuc2l0aW9uIGRpbWVuc2lvbiBub3QgbWF0Y2hpbmcgd2l0aCBkeW5hbWljIGRpbWVuc2lvbicpKTtcblx0XHR9XG5cdH1cblxuXHRpZiAoQXJyYXkuaXNBcnJheShzdGF0ZVByb2plY3Rpb24pKSB7XG5cdFx0cmV0dXJuIHtcblx0XHRcdG9ic2VydmF0aW9uOiBPYmplY3QuYXNzaWduKHt9LCBvYnNlcnZhdGlvbiwge1xuXHRcdFx0XHRkaW1lbnNpb246IHN0YXRlUHJvamVjdGlvbi5sZW5ndGhcblx0XHRcdH0pLFxuXHRcdFx0ZHluYW1pYzogT2JqZWN0LmFzc2lnbih7fSwgZHluYW1pYywge1xuXHRcdFx0XHRkaW1lbnNpb246IHN0YXRlUHJvamVjdGlvblswXS5sZW5ndGhcblx0XHRcdH0pXG5cdFx0fTtcblx0fVxuXG5cdGlmIChBcnJheS5pc0FycmF5KHRyYW5zaXRpb24pKSB7XG5cdFx0cmV0dXJuIHtcblx0XHRcdG9ic2VydmF0aW9uLFxuXHRcdFx0ZHluYW1pYzogT2JqZWN0LmFzc2lnbih7fSwgZHluYW1pYywge1xuXHRcdFx0XHRkaW1lbnNpb246IHRyYW5zaXRpb24ubGVuZ3RoXG5cdFx0XHR9KVxuXHRcdH07XG5cdH1cblxuXHRyZXR1cm4ge29ic2VydmF0aW9uLCBkeW5hbWljfTtcbn07XG4iLCJjb25zdCBjaGVja01hdHJpeCA9IGZ1bmN0aW9uIChtYXRyaXgsIHNoYXBlKSB7XG5cdGlmIChtYXRyaXgucmVkdWNlKChhLCBiKSA9PiBhLmNvbmNhdChiKSkuZmlsdGVyKGEgPT4gTnVtYmVyLmlzTmFOKGEpKS5sZW5ndGggPiAwKSB7XG5cdFx0dGhyb3cgKG5ldyBFcnJvcignTWF0cml4IHNob3VsZCBub3QgaGF2ZSBhIE5hTicpKTtcblx0fVxuXG5cdGlmIChzaGFwZSkge1xuXHRcdGNoZWNrU2hhcGUobWF0cml4LCBzaGFwZSk7XG5cdH1cbn07XG5cbmNvbnN0IGNoZWNrU2hhcGUgPSBmdW5jdGlvbiAobWF0cml4LCBzaGFwZSkge1xuXHRpZiAobWF0cml4Lmxlbmd0aCAhPT0gc2hhcGVbMF0pIHtcblx0XHR0aHJvdyAobmV3IEVycm9yKCdzaGFwZSBhbmQgbGVuZ3RoIGRvIG5vdCBtYXRjaCcpKTtcblx0fVxuXG5cdGlmIChzaGFwZS5sZW5ndGggPiAxKSB7XG5cdFx0cmV0dXJuIG1hdHJpeC5mb3JFYWNoKG0gPT4gY2hlY2tTaGFwZShtLCBzaGFwZS5zbGljZSgxKSkpO1xuXHR9XG59O1xuXG4vKipcbiAqIEBjbGFzc1xuICogQ2xhc3MgcmVwcmVzZW50aW5nIGEgbXVsdGkgZGltZW5zaW9ubmFsIGdhdXNzaWFuLCB3aXRoIGhpcyBtZWFuIGFuZCBoaXMgY292YXJpYW5jZVxuICogQHByb3BlcnR5IHtOdW1iZXJ9IFtpbmRleD0wXSB0aGUgaW5kZXggb2YgdGhlIFN0YXRlIGluIHRoZSBwcm9jZXNzLCB0aGlzIGlzIG5vdCBtYW5kYXRvcnkgZm9yIHNpbXBsZSBLYWxtYW4gRmlsdGVyLCBidXQgaXMgbmVlZGVkIGZvciBtb3N0IG9mIHRoZSB1c2UgY2FzZSBvZiBleHRlbmRlZCBrYWxtYW4gZmlsdGVyXG4gKiBAcHJvcGVydHkge0FycmF5LjxBcnJheS48TnVtYmVyPj59IGNvdmFyaWFuY2Ugc3F1YXJlIG1hdHJpeCBvZiBzaXplIGRpbWVuc2lvblxuICogQHByb3BlcnR5IHtBcnJheS48QXJyYXk8TnVtYmVyPj59IG1lYW4gY29sdW1uIG1hdHJpeCBvZiBzaXplIGRpbWVuc2lvbiB4IDFcbiAqL1xuY2xhc3MgU3RhdGUge1xuXHRjb25zdHJ1Y3Rvcih7bWVhbiwgY292YXJpYW5jZSwgaW5kZXh9KSB7XG5cdFx0dGhpcy5tZWFuID0gbWVhbjtcblx0XHR0aGlzLmNvdmFyaWFuY2UgPSBjb3ZhcmlhbmNlO1xuXHRcdHRoaXMuaW5kZXggPSBpbmRleDtcblx0fVxuXG5cdC8qKlxuXHQqIENoZWNrIHRoZSBjb25zaXN0ZW5jeSBvZiB0aGUgU3RhdGVcblx0Ki9cblx0Y2hlY2soKSB7XG5cdFx0dGhpcy5jb25zdHJ1Y3Rvci5jaGVjayh0aGlzKTtcblx0fVxuXG5cdC8qKlxuXHQqIENoZWNrIHRoZSBjb25zaXN0ZW5jeSBvZiB0aGUgU3RhdGUncyBhdHRyaWJ1dGVzXG5cdCovXG5cblx0c3RhdGljIGNoZWNrKHN0YXRlLCB7ZGltZW5zaW9uID0gbnVsbH0gPSB7fSkge1xuXHRcdGlmICghKHN0YXRlIGluc3RhbmNlb2YgU3RhdGUpKSB7XG5cdFx0XHR0aHJvdyAobmV3IFR5cGVFcnJvcignVGhlIGFyZ3VtZW50IGlzIG5vdCBhIHN0YXRlJykpO1xuXHRcdH1cblxuXHRcdGNvbnN0IHttZWFuLCBjb3ZhcmlhbmNlfSA9IHN0YXRlOyAvLyBJbmRleFxuXHRcdGNvbnN0IG1lYW5EaW1lbnNpb24gPSBtZWFuLmxlbmd0aDtcblx0XHRpZiAodHlwZW9mIChkaW1lbnNpb24pID09PSAnbnVtYmVyJyAmJiBtZWFuRGltZW5zaW9uICE9PSBkaW1lbnNpb24pIHtcblx0XHRcdHRocm93IChuZXcgRXJyb3IoYCR7bWVhbkRpbWVuc2lvbn0gYW5kICR7ZGltZW5zaW9ufSBhcmUgbm90IHRoZSBzYW1lYCkpO1xuXHRcdH1cblxuXHRcdGNoZWNrTWF0cml4KG1lYW4sIFttZWFuRGltZW5zaW9uLCAxXSk7XG5cdFx0Y2hlY2tNYXRyaXgoY292YXJpYW5jZSwgW21lYW5EaW1lbnNpb24sIG1lYW5EaW1lbnNpb25dKTtcblxuXHRcdC8vIElmICh0eXBlb2YgKGluZGV4KSAhPT0gJ251bWJlcicpIHtcblx0XHQvLyBcdHRocm93IChuZXcgVHlwZUVycm9yKCd0IG11c3QgYmUgYSBudW1iZXInKSk7XG5cdFx0Ly8gfVxuXHR9XG59XG5cbm1vZHVsZS5leHBvcnRzID0gU3RhdGU7XG4iLCIvKipcbipSZXR1cm5zIHRoZSBjb3JyZXNwb25kaW5nIG1hdHJpeCBpbiBkaW0qMSwgZ2l2ZW4gYW4gZGltIG1hdHJpeCwgYW5kIGNoZWNrc1xuKiBpZiBjb3JyZXNwb25kaW5nIHdpdGggdGhlIG9ic2VydmF0aW9uIGRpbWVuc2lvblxuKkBwYXJhbSB7QXJyYXkuPE51bWJlcj4gfCBBcnJheS48QXJyYXkuPE51bWJlcj4+fSBvYnNlcnZhdGlvblxuKkBwYXJhbSB7TnVtYmVyfSBkaW1lbnNpb25cbipAcmV0dXJucyB7QXJyYXkuPEFycmF5LjxOdW1iZXI+Pn1cbiovXG5cbm1vZHVsZS5leHBvcnRzID0gZnVuY3Rpb24gKHtvYnNlcnZhdGlvbiwgZGltZW5zaW9ufSkge1xuXHRpZiAoIUFycmF5LmlzQXJyYXkob2JzZXJ2YXRpb24pKSB7XG5cdFx0dGhyb3cgKG5ldyBUeXBlRXJyb3IoJ1RoZSBvYnNlcnZhdGlvbiBzaG91bGQgYmUgYW4gYXJyYXknKSk7XG5cdH1cblxuXHRpZiAob2JzZXJ2YXRpb24ubGVuZ3RoICE9PSBkaW1lbnNpb24pIHtcblx0XHR0aHJvdyAobmV3IFR5cGVFcnJvcignT2JzZXJ2YXRpb24gYW5kIGRpbWVuc2lvbiBub3QgbWF0Y2hpbmcnKSk7XG5cdH1cblxuXHRpZiAodHlwZW9mIChvYnNlcnZhdGlvblswXSkgPT09ICdudW1iZXInKSB7XG5cdFx0cmV0dXJuIG9ic2VydmF0aW9uLm1hcChlbGVtZW50ID0+IFtlbGVtZW50XSk7XG5cdH1cblxuXHRyZXR1cm4gb2JzZXJ2YXRpb247XG59O1xuIiwiY29uc3QgdW5pcSA9IHJlcXVpcmUoJy4vdW5pcS5qcycpO1xuY29uc3QgbGltaXQgPSAxMDA7XG5cbi8qKlxuKkVxdWl2YWxlbnQgdG8gdGhlIE9iamVjdC5hc3NpZ24gbWV0aG9kZSwgdGFrZXMgc2V2ZXJhbCBhcmd1bWVudHMgYW5kIGNyZWF0ZXMgYSBuZXcgb2JqZWN0IGNvcnJlc3BvbmRpbmcgdG8gdGhlIGFzc2lnbm1lbnQgb2YgdGhlIGFyZ3VtZW50c1xuKiBAcGFyYW0ge09iamVjdH0gYXJnc1xuKiBAcGFyYW0ge051bWJlcn0gc3RlcFxuKi9cbmNvbnN0IGRlZXBBc3NpZ24gPSBmdW5jdGlvbiAoYXJncywgc3RlcCkge1xuXHRpZiAoc3RlcCA+IGxpbWl0KSB7XG5cdFx0dGhyb3cgKG5ldyBFcnJvcihgSW4gZGVlcEFzc2lnbiwgbnVtYmVyIG9mIHJlY3Vyc2l2ZSBjYWxsICgke3N0ZXB9KSByZWFjaGVkIGxpbWl0ICgke2xpbWl0fSksIGRlZXBBc3NpZ24gaXMgbm90IHdvcmtpbmcgb24gIHNlbGYtcmVmZXJlbmNpbmcgb2JqZWN0c2ApKTtcblx0fVxuXG5cdGNvbnN0IGZpbHRlckFyZ3VtZW50cyA9IGFyZ3MuZmlsdGVyKGFyZyA9PiB0eXBlb2YgKGFyZykgIT09ICd1bmRlZmluZWQnICYmIGFyZyAhPT0gbnVsbCk7XG5cdGNvbnN0IGxhc3RBcmd1bWVudCA9IGZpbHRlckFyZ3VtZW50c1tmaWx0ZXJBcmd1bWVudHMubGVuZ3RoIC0gMV07XG5cdGlmIChmaWx0ZXJBcmd1bWVudHMubGVuZ3RoID09PSAxKSB7XG5cdFx0cmV0dXJuIGZpbHRlckFyZ3VtZW50c1swXTtcblx0fVxuXG5cdGlmICh0eXBlb2YgKGxhc3RBcmd1bWVudCkgIT09ICdvYmplY3QnIHx8IEFycmF5LmlzQXJyYXkobGFzdEFyZ3VtZW50KSkge1xuXHRcdHJldHVybiBsYXN0QXJndW1lbnQ7XG5cdH1cblxuXHRpZiAoZmlsdGVyQXJndW1lbnRzLmxlbmd0aCA9PT0gMCkge1xuXHRcdHJldHVybiBudWxsO1xuXHR9XG5cblx0Y29uc3Qgb2JqZWN0c0FyZ3VtZW50cyA9IGZpbHRlckFyZ3VtZW50cy5maWx0ZXIoYXJnID0+IHR5cGVvZiAoYXJnKSA9PT0gJ29iamVjdCcpO1xuXHRsZXQga2V5cyA9IFtdO1xuXHRvYmplY3RzQXJndW1lbnRzLmZvckVhY2goYXJnID0+IHtcblx0XHRrZXlzID0ga2V5cy5jb25jYXQoT2JqZWN0LmtleXMoYXJnKSk7XG5cdH0pO1xuXHRjb25zdCB1bmlxS2V5cyA9IHVuaXEoa2V5cyk7XG5cdGNvbnN0IHJlc3VsdCA9IHt9O1xuXHR1bmlxS2V5cy5mb3JFYWNoKGtleSA9PiB7XG5cdFx0Y29uc3QgdmFsdWVzID0gb2JqZWN0c0FyZ3VtZW50cy5tYXAoYXJnID0+IGFyZ1trZXldKTtcblx0XHRyZXN1bHRba2V5XSA9IGRlZXBBc3NpZ24odmFsdWVzLCBzdGVwICsgMSk7XG5cdH0pO1xuXHRyZXR1cm4gcmVzdWx0O1xufTtcblxubW9kdWxlLmV4cG9ydHMgPSAoKC4uLmFyZ3MpID0+IGRlZXBBc3NpZ24oYXJncywgMCkpO1xuIiwiLyoqXG4qIEB0eXBlZGVmIHtOdW1iZXIgfCBBcnJheS48TnVtYmVyPiB8IEFycmF5LjxBcnJheS48TnVtYmVyPj59IENvdmFyaWFuY2VQYXJhbVxuKi9cbmNvbnN0IGRpYWcgPSByZXF1aXJlKCcuLi9saW5hbGdlYnJhL2RpYWcnKTtcbi8qKlxuKiBJZiBjb3YgaXMgYSBudW1iZXIsIHJlc3VsdCB3aWxsIGJlIElkZW50aXR5KmNvdlxuKiBJZiBjb3YgaXMgYW4gQXJyYXkuPE51bWJlcj4sIHJlc3VsdCB3aWxsIGJlIGRpYWcoY292KVxuKiBJZiBjb3YgaXMgYW4gQXJyYXkuPEFycmF5LjxOdW1iZXI+PiwgcmVzdWx0IHdpbGwgYmUgY292XG4qIEBwYXJhbSB7Q292YXJpYW5jZVBhcmFtfSBjb3ZcbiogQHBhcmFtIHtOdW1iZXJ9IGRpbWVuc2lvblxuKiBAcmV0dXJucyB7QXJyYXkuPEFycmF5LjxOdW1iZXI+Pn1cbiovXG5tb2R1bGUuZXhwb3J0cyA9IGZ1bmN0aW9uIChhcnJheSwge2RpbWVuc2lvbn0gPSB7fSkge1xuXHRpZiAodHlwZW9mIChhcnJheSkgPT09ICdudW1iZXInIHx8IEFycmF5LmlzQXJyYXkoYXJyYXkpKSB7XG5cdFx0aWYgKHR5cGVvZiAoYXJyYXkpID09PSAnbnVtYmVyJyAmJiB0eXBlb2YgKGRpbWVuc2lvbikgPT09ICdudW1iZXInKSB7XG5cdFx0XHRyZXR1cm4gZGlhZyhuZXcgQXJyYXkoZGltZW5zaW9uKS5maWxsKGFycmF5KSk7XG5cdFx0fVxuXG5cdFx0aWYgKChBcnJheS5pc0FycmF5KGFycmF5KSkgJiYgKEFycmF5LmlzQXJyYXkoYXJyYXlbMF0pKSkge1xuXHRcdFx0cmV0dXJuIGFycmF5O1xuXHRcdH1cblxuXHRcdGlmICgoQXJyYXkuaXNBcnJheShhcnJheSkpICYmICh0eXBlb2YgKGFycmF5WzBdKSA9PT0gJ251bWJlcicpKSB7XG5cdFx0XHRyZXR1cm4gZGlhZyhhcnJheSk7XG5cdFx0fVxuXHR9XG5cblx0cmV0dXJuIGFycmF5O1xufTtcbiIsIi8vIENvbnN0IGRpYWcgPSByZXF1aXJlKCcuLi9saW5hbGdlYnJhL2RpYWcuanMnKTtcblxuLyoqXG4qIEBjYWxsYmFjayBNYXRyaXhDYWxsYmFja1xuKiBAcmV0dXJucyA8QXJyYXkuPEFycmF5LjxOdW1iZXI+PlxuKi9cblxuLyoqXG4qIFRyYW5mb3JtczpcbioqIGEgMmQgYXJyYXkgaW50byBhIGZ1bmN0aW9uICgoKSA9PiBhcnJheSlcbioqIGEgMWQgYXJyYXkgaW50byBhIGZ1bmN0aW9uICgoKSA9PiBkaWFnKGFycmF5KSlcbipAcGFyYW0ge0FycmF5LjxOdW1iZXI+IHwgQXJyYXkuPEFycmF5LjxOdW1iZXI+Pn0gYXJyYXlcbipAcmV0dXJucyB7TWF0cml4Q2FsbGJhY2t9XG4qL1xuXG5tb2R1bGUuZXhwb3J0cyA9IGZ1bmN0aW9uIChhcnJheSkge1xuXHRpZiAodHlwZW9mIChhcnJheSkgPT09ICdmdW5jdGlvbicpIHtcblx0XHRyZXR1cm4gYXJyYXk7XG5cdH1cblxuXHRpZiAoQXJyYXkuaXNBcnJheShhcnJheSkpIHtcblx0XHRyZXR1cm4gZnVuY3Rpb24gKCkge1xuXHRcdFx0cmV0dXJuIGFycmF5O1xuXHRcdH07XG5cdH1cblxuXHR0aHJvdyAobmV3IEVycm9yKCdPbmx5IGFycmF5cyBhbmQgZnVuY3Rpb25zIGFyZSBhdXRob3JpemVkJykpO1xufTtcbiIsIm1vZHVsZS5leHBvcnRzID0gZnVuY3Rpb24gKGFycmF5KSB7XG5cdHJldHVybiBhcnJheS5maWx0ZXIoKHZhbHVlLCBpbmRleCkgPT5cblx0XHRhcnJheS5pbmRleE9mKHZhbHVlKSA9PT0gaW5kZXhcblx0KTtcbn07XG4iLCJ2YXIgU3lsdmVzdGVyID0ge31cblxuU3lsdmVzdGVyLk1hdHJpeCA9IGZ1bmN0aW9uKCkge31cblxuU3lsdmVzdGVyLk1hdHJpeC5jcmVhdGUgPSBmdW5jdGlvbihlbGVtZW50cykge1xuICB2YXIgTSA9IG5ldyBTeWx2ZXN0ZXIuTWF0cml4KClcbiAgcmV0dXJuIE0uc2V0RWxlbWVudHMoZWxlbWVudHMpXG59XG5cblN5bHZlc3Rlci5NYXRyaXguSSA9IGZ1bmN0aW9uKG4pIHtcbiAgdmFyIGVscyA9IFtdLFxuICAgIGkgPSBuLFxuICAgIGpcbiAgd2hpbGUgKGktLSkge1xuICAgIGogPSBuXG4gICAgZWxzW2ldID0gW11cbiAgICB3aGlsZSAoai0tKSB7XG4gICAgICBlbHNbaV1bal0gPSBpID09PSBqID8gMSA6IDBcbiAgICB9XG4gIH1cbiAgcmV0dXJuIFN5bHZlc3Rlci5NYXRyaXguY3JlYXRlKGVscylcbn1cblxuU3lsdmVzdGVyLk1hdHJpeC5wcm90b3R5cGUgPSB7XG4gIGR1cDogZnVuY3Rpb24oKSB7XG4gICAgcmV0dXJuIFN5bHZlc3Rlci5NYXRyaXguY3JlYXRlKHRoaXMuZWxlbWVudHMpXG4gIH0sXG5cbiAgaXNTcXVhcmU6IGZ1bmN0aW9uKCkge1xuICAgIHZhciBjb2xzID0gdGhpcy5lbGVtZW50cy5sZW5ndGggPT09IDAgPyAwIDogdGhpcy5lbGVtZW50c1swXS5sZW5ndGhcbiAgICByZXR1cm4gdGhpcy5lbGVtZW50cy5sZW5ndGggPT09IGNvbHNcbiAgfSxcblxuICB0b1JpZ2h0VHJpYW5ndWxhcjogZnVuY3Rpb24oKSB7XG4gICAgaWYgKHRoaXMuZWxlbWVudHMubGVuZ3RoID09PSAwKSByZXR1cm4gU3lsdmVzdGVyLk1hdHJpeC5jcmVhdGUoW10pXG4gICAgdmFyIE0gPSB0aGlzLmR1cCgpLFxuICAgICAgZWxzXG4gICAgdmFyIG4gPSB0aGlzLmVsZW1lbnRzLmxlbmd0aCxcbiAgICAgIGksXG4gICAgICBqLFxuICAgICAgbnAgPSB0aGlzLmVsZW1lbnRzWzBdLmxlbmd0aCxcbiAgICAgIHBcbiAgICBmb3IgKGkgPSAwOyBpIDwgbjsgaSsrKSB7XG4gICAgICBpZiAoTS5lbGVtZW50c1tpXVtpXSA9PT0gMCkge1xuICAgICAgICBmb3IgKGogPSBpICsgMTsgaiA8IG47IGorKykge1xuICAgICAgICAgIGlmIChNLmVsZW1lbnRzW2pdW2ldICE9PSAwKSB7XG4gICAgICAgICAgICBlbHMgPSBbXVxuICAgICAgICAgICAgZm9yIChwID0gMDsgcCA8IG5wOyBwKyspIHtcbiAgICAgICAgICAgICAgZWxzLnB1c2goTS5lbGVtZW50c1tpXVtwXSArIE0uZWxlbWVudHNbal1bcF0pXG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBNLmVsZW1lbnRzW2ldID0gZWxzXG4gICAgICAgICAgICBicmVha1xuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgfVxuICAgICAgaWYgKE0uZWxlbWVudHNbaV1baV0gIT09IDApIHtcbiAgICAgICAgZm9yIChqID0gaSArIDE7IGogPCBuOyBqKyspIHtcbiAgICAgICAgICB2YXIgbXVsdGlwbGllciA9IE0uZWxlbWVudHNbal1baV0gLyBNLmVsZW1lbnRzW2ldW2ldXG4gICAgICAgICAgZWxzID0gW11cbiAgICAgICAgICBmb3IgKHAgPSAwOyBwIDwgbnA7IHArKykge1xuICAgICAgICAgICAgLy8gRWxlbWVudHMgd2l0aCBjb2x1bW4gbnVtYmVycyB1cCB0byBhbiBpbmNsdWRpbmcgdGhlIG51bWJlciBvZiB0aGVcbiAgICAgICAgICAgIC8vIHJvdyB0aGF0IHdlJ3JlIHN1YnRyYWN0aW5nIGNhbiBzYWZlbHkgYmUgc2V0IHN0cmFpZ2h0IHRvIHplcm8sXG4gICAgICAgICAgICAvLyBzaW5jZSB0aGF0J3MgdGhlIHBvaW50IG9mIHRoaXMgcm91dGluZSBhbmQgaXQgYXZvaWRzIGhhdmluZyB0b1xuICAgICAgICAgICAgLy8gbG9vcCBvdmVyIGFuZCBjb3JyZWN0IHJvdW5kaW5nIGVycm9ycyBsYXRlclxuICAgICAgICAgICAgZWxzLnB1c2goXG4gICAgICAgICAgICAgIHAgPD0gaSA/IDAgOiBNLmVsZW1lbnRzW2pdW3BdIC0gTS5lbGVtZW50c1tpXVtwXSAqIG11bHRpcGxpZXJcbiAgICAgICAgICAgIClcbiAgICAgICAgICB9XG4gICAgICAgICAgTS5lbGVtZW50c1tqXSA9IGVsc1xuICAgICAgICB9XG4gICAgICB9XG4gICAgfVxuICAgIHJldHVybiBNXG4gIH0sXG5cbiAgZGV0ZXJtaW5hbnQ6IGZ1bmN0aW9uKCkge1xuICAgIGlmICh0aGlzLmVsZW1lbnRzLmxlbmd0aCA9PT0gMCkge1xuICAgICAgcmV0dXJuIDFcbiAgICB9XG4gICAgaWYgKCF0aGlzLmlzU3F1YXJlKCkpIHtcbiAgICAgIHJldHVybiBudWxsXG4gICAgfVxuICAgIHZhciBNID0gdGhpcy50b1JpZ2h0VHJpYW5ndWxhcigpXG4gICAgdmFyIGRldCA9IE0uZWxlbWVudHNbMF1bMF0sXG4gICAgICBuID0gTS5lbGVtZW50cy5sZW5ndGhcbiAgICBmb3IgKHZhciBpID0gMTsgaSA8IG47IGkrKykge1xuICAgICAgZGV0ID0gZGV0ICogTS5lbGVtZW50c1tpXVtpXVxuICAgIH1cbiAgICByZXR1cm4gZGV0XG4gIH0sXG5cbiAgaXNTaW5ndWxhcjogZnVuY3Rpb24oKSB7XG4gICAgcmV0dXJuIHRoaXMuaXNTcXVhcmUoKSAmJiB0aGlzLmRldGVybWluYW50KCkgPT09IDBcbiAgfSxcblxuICBhdWdtZW50OiBmdW5jdGlvbihtYXRyaXgpIHtcbiAgICBpZiAodGhpcy5lbGVtZW50cy5sZW5ndGggPT09IDApIHtcbiAgICAgIHJldHVybiB0aGlzLmR1cCgpXG4gICAgfVxuICAgIHZhciBNID0gbWF0cml4LmVsZW1lbnRzIHx8IG1hdHJpeFxuICAgIGlmICh0eXBlb2YgTVswXVswXSA9PT0gJ3VuZGVmaW5lZCcpIHtcbiAgICAgIE0gPSBTeWx2ZXN0ZXIuTWF0cml4LmNyZWF0ZShNKS5lbGVtZW50c1xuICAgIH1cbiAgICB2YXIgVCA9IHRoaXMuZHVwKCksXG4gICAgICBjb2xzID0gVC5lbGVtZW50c1swXS5sZW5ndGhcbiAgICB2YXIgaSA9IFQuZWxlbWVudHMubGVuZ3RoLFxuICAgICAgbmogPSBNWzBdLmxlbmd0aCxcbiAgICAgIGpcbiAgICBpZiAoaSAhPT0gTS5sZW5ndGgpIHtcbiAgICAgIHJldHVybiBudWxsXG4gICAgfVxuICAgIHdoaWxlIChpLS0pIHtcbiAgICAgIGogPSBualxuICAgICAgd2hpbGUgKGotLSkge1xuICAgICAgICBULmVsZW1lbnRzW2ldW2NvbHMgKyBqXSA9IE1baV1bal1cbiAgICAgIH1cbiAgICB9XG4gICAgcmV0dXJuIFRcbiAgfSxcblxuICBpbnZlcnNlOiBmdW5jdGlvbigpIHtcbiAgICBpZiAodGhpcy5lbGVtZW50cy5sZW5ndGggPT09IDApIHtcbiAgICAgIHJldHVybiBudWxsXG4gICAgfVxuICAgIGlmICghdGhpcy5pc1NxdWFyZSgpIHx8IHRoaXMuaXNTaW5ndWxhcigpKSB7XG4gICAgICByZXR1cm4gbnVsbFxuICAgIH1cbiAgICB2YXIgbiA9IHRoaXMuZWxlbWVudHMubGVuZ3RoLFxuICAgICAgaSA9IG4sXG4gICAgICBqXG4gICAgdmFyIE0gPSB0aGlzLmF1Z21lbnQoU3lsdmVzdGVyLk1hdHJpeC5JKG4pKS50b1JpZ2h0VHJpYW5ndWxhcigpXG4gICAgdmFyIG5wID0gTS5lbGVtZW50c1swXS5sZW5ndGgsXG4gICAgICBwLFxuICAgICAgZWxzLFxuICAgICAgZGl2aXNvclxuICAgIHZhciBpbnZlcnNlX2VsZW1lbnRzID0gW10sXG4gICAgICBuZXdfZWxlbWVudFxuICAgIC8vIFN5bHZlc3Rlci5NYXRyaXggaXMgbm9uLXNpbmd1bGFyIHNvIHRoZXJlIHdpbGwgYmUgbm8gemVyb3Mgb24gdGhlXG4gICAgLy8gZGlhZ29uYWwuIEN5Y2xlIHRocm91Z2ggcm93cyBmcm9tIGxhc3QgdG8gZmlyc3QuXG4gICAgd2hpbGUgKGktLSkge1xuICAgICAgLy8gRmlyc3QsIG5vcm1hbGlzZSBkaWFnb25hbCBlbGVtZW50cyB0byAxXG4gICAgICBlbHMgPSBbXVxuICAgICAgaW52ZXJzZV9lbGVtZW50c1tpXSA9IFtdXG4gICAgICBkaXZpc29yID0gTS5lbGVtZW50c1tpXVtpXVxuICAgICAgZm9yIChwID0gMDsgcCA8IG5wOyBwKyspIHtcbiAgICAgICAgbmV3X2VsZW1lbnQgPSBNLmVsZW1lbnRzW2ldW3BdIC8gZGl2aXNvclxuICAgICAgICBlbHMucHVzaChuZXdfZWxlbWVudClcbiAgICAgICAgLy8gU2h1ZmZsZSBvZmYgdGhlIGN1cnJlbnQgcm93IG9mIHRoZSByaWdodCBoYW5kIHNpZGUgaW50byB0aGUgcmVzdWx0c1xuICAgICAgICAvLyBhcnJheSBhcyBpdCB3aWxsIG5vdCBiZSBtb2RpZmllZCBieSBsYXRlciBydW5zIHRocm91Z2ggdGhpcyBsb29wXG4gICAgICAgIGlmIChwID49IG4pIHtcbiAgICAgICAgICBpbnZlcnNlX2VsZW1lbnRzW2ldLnB1c2gobmV3X2VsZW1lbnQpXG4gICAgICAgIH1cbiAgICAgIH1cbiAgICAgIE0uZWxlbWVudHNbaV0gPSBlbHNcbiAgICAgIC8vIFRoZW4sIHN1YnRyYWN0IHRoaXMgcm93IGZyb20gdGhvc2UgYWJvdmUgaXQgdG8gZ2l2ZSB0aGUgaWRlbnRpdHkgbWF0cml4XG4gICAgICAvLyBvbiB0aGUgbGVmdCBoYW5kIHNpZGVcbiAgICAgIGogPSBpXG4gICAgICB3aGlsZSAoai0tKSB7XG4gICAgICAgIGVscyA9IFtdXG4gICAgICAgIGZvciAocCA9IDA7IHAgPCBucDsgcCsrKSB7XG4gICAgICAgICAgZWxzLnB1c2goTS5lbGVtZW50c1tqXVtwXSAtIE0uZWxlbWVudHNbaV1bcF0gKiBNLmVsZW1lbnRzW2pdW2ldKVxuICAgICAgICB9XG4gICAgICAgIE0uZWxlbWVudHNbal0gPSBlbHNcbiAgICAgIH1cbiAgICB9XG4gICAgcmV0dXJuIFN5bHZlc3Rlci5NYXRyaXguY3JlYXRlKGludmVyc2VfZWxlbWVudHMpXG4gIH0sXG5cbiAgc2V0RWxlbWVudHM6IGZ1bmN0aW9uKGVscykge1xuICAgIHZhciBpLFxuICAgICAgaixcbiAgICAgIGVsZW1lbnRzID0gZWxzLmVsZW1lbnRzIHx8IGVsc1xuICAgIGlmIChlbGVtZW50c1swXSAmJiB0eXBlb2YgZWxlbWVudHNbMF1bMF0gIT09ICd1bmRlZmluZWQnKSB7XG4gICAgICBpID0gZWxlbWVudHMubGVuZ3RoXG4gICAgICB0aGlzLmVsZW1lbnRzID0gW11cbiAgICAgIHdoaWxlIChpLS0pIHtcbiAgICAgICAgaiA9IGVsZW1lbnRzW2ldLmxlbmd0aFxuICAgICAgICB0aGlzLmVsZW1lbnRzW2ldID0gW11cbiAgICAgICAgd2hpbGUgKGotLSkge1xuICAgICAgICAgIHRoaXMuZWxlbWVudHNbaV1bal0gPSBlbGVtZW50c1tpXVtqXVxuICAgICAgICB9XG4gICAgICB9XG4gICAgICByZXR1cm4gdGhpc1xuICAgIH1cbiAgICB2YXIgbiA9IGVsZW1lbnRzLmxlbmd0aFxuICAgIHRoaXMuZWxlbWVudHMgPSBbXVxuICAgIGZvciAoaSA9IDA7IGkgPCBuOyBpKyspIHtcbiAgICAgIHRoaXMuZWxlbWVudHMucHVzaChbZWxlbWVudHNbaV1dKVxuICAgIH1cbiAgICByZXR1cm4gdGhpc1xuICB9LFxufVxuXG5tb2R1bGUuZXhwb3J0cyA9IGZ1bmN0aW9uKGVsZW1lbnRzKSB7XG4gIHJldHVybiBTeWx2ZXN0ZXIuTWF0cml4LmNyZWF0ZShlbGVtZW50cykuaW52ZXJzZSgpLmVsZW1lbnRzXG59XG4iLCJjb25zdCBLYWxtYW5GaWx0ZXIgPSByZXF1aXJlKCcuLi8uLi9saWIva2FsbWFuLWZpbHRlcicpO1xuXG5jb25zdCBub2lzeU9ic2VydmF0aW9ucyA9IHJlcXVpcmUoJy4vb2JzZXJ2YXRpb25zLmpzb24nKS5vYnNlcnZhdGlvbnM7XG5jb25zdCBrZk9wdGlvbnMgPSByZXF1aXJlKCcuL2tmLW9wdGlvbnMuanMnKTtcbmNvbnN0IGNyZWF0ZUVsZW1lbnQgPSByZXF1aXJlKCcuL3ZpZXdzL2NyZWF0ZS1lbGVtZW50Jyk7XG5jb25zdCBjcmVhdGVHcm91cEJveGVzID0gcmVxdWlyZSgnLi92aWV3cy9jcmVhdGUtZ3JvdXAtYm94ZXMnKTtcblxuY29uc3Qga2YgPSBuZXcgS2FsbWFuRmlsdGVyKGtmT3B0aW9ucyk7XG5sZXQgcHJlZGljdGVkID0ga2YucHJlZGljdCgpO1xuXG5jb25zdCBpbWcgPSBkb2N1bWVudC5xdWVyeVNlbGVjdG9yKCcjYmlrZXMnKTsvLyBlc2xpbnQtZGlzYWJsZS1saW5lIG5vLXVuZGVmXG5cbi8vIENyZWF0ZSBhbGwgdGhlIGVsZW1lbnRzIG9mIHRoZSBwcmVkaWN0aW9uIG9yIGNvcnJlY3Rpb24gcGhhc2VcbmNvbnN0IGRlbGF5ID0gMTAwO1xuXG5sZXQgcHJvbWlzZSA9IFByb21pc2UucmVzb2x2ZSgpO1xubGV0IHByZXZpb3VzQ29ycmVjdGVkID0gbnVsbDtcblxuY29uc3QgZGVsYXlQcm9taXNlID0gZGVsYXkgPT4gbmV3IFByb21pc2UocmVzb2x2ZSA9PiBzZXRUaW1lb3V0KHJlc29sdmUsIGRlbGF5KSk7XG5cbm1vZHVsZS5leHBvcnRzID0ge1xuXHRydW4oKXtcblx0XHRub2lzeU9ic2VydmF0aW9ucy5mb3JFYWNoKChib3gsIGluZGV4KSA9PiB7XG5cdFx0XHRwcm9taXNlID0gcHJvbWlzZVxuXHRcdFx0XHQudGhlbigoKSA9PiB7XG5cdFx0XHRcdFx0cHJlZGljdGVkID0ga2YucHJlZGljdCh7cHJldmlvdXNDb3JyZWN0ZWR9KTtcblx0XHRcdFx0XHRjb25zdCB7bWVhbiwgY292YXJpYW5jZX0gPSBwcmVkaWN0ZWQ7XG5cblx0XHRcdFx0XHRjcmVhdGVHcm91cEJveGVzKHttZWFuLCBjb3ZhcmlhbmNlLCBwYXJlbnQ6IGltZywgY2xhc3NOYW1lOiAncHJlZGljdGVkJywgY29sb3I6ICdibHVlJ30pO1xuXG5cdFx0XHRcdFx0cmV0dXJuIGRlbGF5UHJvbWlzZShkZWxheSk7XG5cdFx0XHRcdH0pXG5cdFx0XHRcdC50aGVuKChiID0+IHtcblx0XHRcdFx0XHRjcmVhdGVFbGVtZW50KHtcblx0XHRcdFx0XHRcdGNsYXNzTmFtZTogJ29ic2VydmF0aW9uJyxcblx0XHRcdFx0XHRcdGJib3g6IFtcblx0XHRcdFx0XHRcdFx0YlswXSArIChiWzJdIC8gMiksXG5cdFx0XHRcdFx0XHRcdGJbMV0gKyAoYlszXSAvIDIpLFxuXHRcdFx0XHRcdFx0XHRiWzJdLFxuXHRcdFx0XHRcdFx0XHRiWzNdXG5cdFx0XHRcdFx0XHRdLFxuXHRcdFx0XHRcdFx0cGFyZW50OiBpbWcsXG5cdFx0XHRcdFx0XHRjb2xvcjogJ3doaXRlJyxcblx0XHRcdFx0XHRcdGxpbmVTdHlsZTogJ3NvbGlkJ1xuXHRcdFx0XHRcdH0pO1xuXG5cdFx0XHRcdFx0cmV0dXJuIGRlbGF5UHJvbWlzZShkZWxheSk7XG5cdFx0XHRcdH0pLmJpbmQobnVsbCwgYm94LCBpbmRleCkpXG5cdFx0XHRcdC50aGVuKChiID0+IHtcblx0XHRcdFx0XHRwcmV2aW91c0NvcnJlY3RlZCA9IGtmLmNvcnJlY3Qoe3ByZWRpY3RlZCwgb2JzZXJ2YXRpb246IGJ9KTtcblx0XHRcdFx0XHRjb25zdCB7bWVhbiwgY292YXJpYW5jZX0gPSBwcmV2aW91c0NvcnJlY3RlZDtcblxuXHRcdFx0XHRcdGNyZWF0ZUdyb3VwQm94ZXMoe21lYW4sIGNvdmFyaWFuY2UsIHBhcmVudDogaW1nLCBjbGFzc05hbWU6ICdjb3JyZWN0ZWQnLCBjb2xvcjogJ3JlZCd9KTtcblxuXHRcdFx0XHRcdHJldHVybiBkZWxheVByb21pc2UoZGVsYXkpO1xuXHRcdFx0XHR9KS5iaW5kKG51bGwsIGJveCwgaW5kZXgpKTtcblx0XHR9KVxuXHR9XG59XG5cbiJdfQ== diff --git a/demo/kalman-filter.js b/demo/kalman-filter.js deleted file mode 100644 index c2ec29a..0000000 --- a/demo/kalman-filter.js +++ /dev/null @@ -1,9567 +0,0 @@ -require=(function(){function r(e,n,t){function o(i,f){if(!n[i]){if(!e[i]){var c="function"==typeof require&&require;if(!f&&c)return c(i,!0);if(u)return u(i,!0);var a=new Error("Cannot find module '"+i+"'");throw a.code="MODULE_NOT_FOUND",a}var p=n[i]={exports:{}};e[i][0].call(p.exports,function(r){var n=e[i][1][r];return o(n||r)},p,p.exports,r,e,n,t)}return n[i].exports}for(var u="function"==typeof require&&require,i=0;i 0) { - throw new Error('Invalid string. Length must be a multiple of 4') - } - - // Trim off extra bytes after placeholder bytes are found - // See: https://github.com/beatgammit/base64-js/issues/42 - var validLen = b64.indexOf('=') - if (validLen === -1) validLen = len - - var placeHoldersLen = validLen === len - ? 0 - : 4 - (validLen % 4) - - return [validLen, placeHoldersLen] -} - -// base64 is 4/3 + up to two characters of the original data -function byteLength (b64) { - var lens = getLens(b64) - var validLen = lens[0] - var placeHoldersLen = lens[1] - return ((validLen + placeHoldersLen) * 3 / 4) - placeHoldersLen -} - -function _byteLength (b64, validLen, placeHoldersLen) { - return ((validLen + placeHoldersLen) * 3 / 4) - placeHoldersLen -} - -function toByteArray (b64) { - var tmp - var lens = getLens(b64) - var validLen = lens[0] - var placeHoldersLen = lens[1] - - var arr = new Arr(_byteLength(b64, validLen, placeHoldersLen)) - - var curByte = 0 - - // if there are placeholders, only get up to the last complete 4 chars - var len = placeHoldersLen > 0 - ? validLen - 4 - : validLen - - var i - for (i = 0; i < len; i += 4) { - tmp = - (revLookup[b64.charCodeAt(i)] << 18) | - (revLookup[b64.charCodeAt(i + 1)] << 12) | - (revLookup[b64.charCodeAt(i + 2)] << 6) | - revLookup[b64.charCodeAt(i + 3)] - arr[curByte++] = (tmp >> 16) & 0xFF - arr[curByte++] = (tmp >> 8) & 0xFF - arr[curByte++] = tmp & 0xFF - } - - if (placeHoldersLen === 2) { - tmp = - (revLookup[b64.charCodeAt(i)] << 2) | - (revLookup[b64.charCodeAt(i + 1)] >> 4) - arr[curByte++] = tmp & 0xFF - } - - if (placeHoldersLen === 1) { - tmp = - (revLookup[b64.charCodeAt(i)] << 10) | - (revLookup[b64.charCodeAt(i + 1)] << 4) | - (revLookup[b64.charCodeAt(i + 2)] >> 2) - arr[curByte++] = (tmp >> 8) & 0xFF - arr[curByte++] = tmp & 0xFF - } - - return arr -} - -function tripletToBase64 (num) { - return lookup[num >> 18 & 0x3F] + - lookup[num >> 12 & 0x3F] + - lookup[num >> 6 & 0x3F] + - lookup[num & 0x3F] -} - -function encodeChunk (uint8, start, end) { - var tmp - var output = [] - for (var i = start; i < end; i += 3) { - tmp = - ((uint8[i] << 16) & 0xFF0000) + - ((uint8[i + 1] << 8) & 0xFF00) + - (uint8[i + 2] & 0xFF) - output.push(tripletToBase64(tmp)) - } - return output.join('') -} - -function fromByteArray (uint8) { - var tmp - var len = uint8.length - var extraBytes = len % 3 // if we have 1 byte left, pad 2 bytes - var parts = [] - var maxChunkLength = 16383 // must be multiple of 3 - - // go through the array every three bytes, we'll deal with trailing stuff later - for (var i = 0, len2 = len - extraBytes; i < len2; i += maxChunkLength) { - parts.push(encodeChunk( - uint8, i, (i + maxChunkLength) > len2 ? len2 : (i + maxChunkLength) - )) - } - - // pad the end with zeros, but make sure to not forget the extra bytes - if (extraBytes === 1) { - tmp = uint8[len - 1] - parts.push( - lookup[tmp >> 2] + - lookup[(tmp << 4) & 0x3F] + - '==' - ) - } else if (extraBytes === 2) { - tmp = (uint8[len - 2] << 8) + uint8[len - 1] - parts.push( - lookup[tmp >> 10] + - lookup[(tmp >> 4) & 0x3F] + - lookup[(tmp << 2) & 0x3F] + - '=' - ) - } - - return parts.join('') -} - -},{}],2:[function(require,module,exports){ - -},{}],3:[function(require,module,exports){ -(function (Buffer){ -/*! - * The buffer module from node.js, for the browser. - * - * @author Feross Aboukhadijeh - * @license MIT - */ -/* eslint-disable no-proto */ - -'use strict' - -var base64 = require('base64-js') -var ieee754 = require('ieee754') - -exports.Buffer = Buffer -exports.SlowBuffer = SlowBuffer -exports.INSPECT_MAX_BYTES = 50 - -var K_MAX_LENGTH = 0x7fffffff -exports.kMaxLength = K_MAX_LENGTH - -/** - * If `Buffer.TYPED_ARRAY_SUPPORT`: - * === true Use Uint8Array implementation (fastest) - * === false Print warning and recommend using `buffer` v4.x which has an Object - * implementation (most compatible, even IE6) - * - * Browsers that support typed arrays are IE 10+, Firefox 4+, Chrome 7+, Safari 5.1+, - * Opera 11.6+, iOS 4.2+. - * - * We report that the browser does not support typed arrays if the are not subclassable - * using __proto__. Firefox 4-29 lacks support for adding new properties to `Uint8Array` - * (See: https://bugzilla.mozilla.org/show_bug.cgi?id=695438). IE 10 lacks support - * for __proto__ and has a buggy typed array implementation. - */ -Buffer.TYPED_ARRAY_SUPPORT = typedArraySupport() - -if (!Buffer.TYPED_ARRAY_SUPPORT && typeof console !== 'undefined' && - typeof console.error === 'function') { - console.error( - 'This browser lacks typed array (Uint8Array) support which is required by ' + - '`buffer` v5.x. Use `buffer` v4.x if you require old browser support.' - ) -} - -function typedArraySupport () { - // Can typed array instances can be augmented? - try { - var arr = new Uint8Array(1) - arr.__proto__ = { __proto__: Uint8Array.prototype, foo: function () { return 42 } } - return arr.foo() === 42 - } catch (e) { - return false - } -} - -Object.defineProperty(Buffer.prototype, 'parent', { - enumerable: true, - get: function () { - if (!Buffer.isBuffer(this)) return undefined - return this.buffer - } -}) - -Object.defineProperty(Buffer.prototype, 'offset', { - enumerable: true, - get: function () { - if (!Buffer.isBuffer(this)) return undefined - return this.byteOffset - } -}) - -function createBuffer (length) { - if (length > K_MAX_LENGTH) { - throw new RangeError('The value "' + length + '" is invalid for option "size"') - } - // Return an augmented `Uint8Array` instance - var buf = new Uint8Array(length) - buf.__proto__ = Buffer.prototype - return buf -} - -/** - * The Buffer constructor returns instances of `Uint8Array` that have their - * prototype changed to `Buffer.prototype`. Furthermore, `Buffer` is a subclass of - * `Uint8Array`, so the returned instances will have all the node `Buffer` methods - * and the `Uint8Array` methods. Square bracket notation works as expected -- it - * returns a single octet. - * - * The `Uint8Array` prototype remains unmodified. - */ - -function Buffer (arg, encodingOrOffset, length) { - // Common case. - if (typeof arg === 'number') { - if (typeof encodingOrOffset === 'string') { - throw new TypeError( - 'The "string" argument must be of type string. Received type number' - ) - } - return allocUnsafe(arg) - } - return from(arg, encodingOrOffset, length) -} - -// Fix subarray() in ES2016. See: https://github.com/feross/buffer/pull/97 -if (typeof Symbol !== 'undefined' && Symbol.species != null && - Buffer[Symbol.species] === Buffer) { - Object.defineProperty(Buffer, Symbol.species, { - value: null, - configurable: true, - enumerable: false, - writable: false - }) -} - -Buffer.poolSize = 8192 // not used by this implementation - -function from (value, encodingOrOffset, length) { - if (typeof value === 'string') { - return fromString(value, encodingOrOffset) - } - - if (ArrayBuffer.isView(value)) { - return fromArrayLike(value) - } - - if (value == null) { - throw TypeError( - 'The first argument must be one of type string, Buffer, ArrayBuffer, Array, ' + - 'or Array-like Object. Received type ' + (typeof value) - ) - } - - if (isInstance(value, ArrayBuffer) || - (value && isInstance(value.buffer, ArrayBuffer))) { - return fromArrayBuffer(value, encodingOrOffset, length) - } - - if (typeof value === 'number') { - throw new TypeError( - 'The "value" argument must not be of type number. Received type number' - ) - } - - var valueOf = value.valueOf && value.valueOf() - if (valueOf != null && valueOf !== value) { - return Buffer.from(valueOf, encodingOrOffset, length) - } - - var b = fromObject(value) - if (b) return b - - if (typeof Symbol !== 'undefined' && Symbol.toPrimitive != null && - typeof value[Symbol.toPrimitive] === 'function') { - return Buffer.from( - value[Symbol.toPrimitive]('string'), encodingOrOffset, length - ) - } - - throw new TypeError( - 'The first argument must be one of type string, Buffer, ArrayBuffer, Array, ' + - 'or Array-like Object. Received type ' + (typeof value) - ) -} - -/** - * Functionally equivalent to Buffer(arg, encoding) but throws a TypeError - * if value is a number. - * Buffer.from(str[, encoding]) - * Buffer.from(array) - * Buffer.from(buffer) - * Buffer.from(arrayBuffer[, byteOffset[, length]]) - **/ -Buffer.from = function (value, encodingOrOffset, length) { - return from(value, encodingOrOffset, length) -} - -// Note: Change prototype *after* Buffer.from is defined to workaround Chrome bug: -// https://github.com/feross/buffer/pull/148 -Buffer.prototype.__proto__ = Uint8Array.prototype -Buffer.__proto__ = Uint8Array - -function assertSize (size) { - if (typeof size !== 'number') { - throw new TypeError('"size" argument must be of type number') - } else if (size < 0) { - throw new RangeError('The value "' + size + '" is invalid for option "size"') - } -} - -function alloc (size, fill, encoding) { - assertSize(size) - if (size <= 0) { - return createBuffer(size) - } - if (fill !== undefined) { - // Only pay attention to encoding if it's a string. This - // prevents accidentally sending in a number that would - // be interpretted as a start offset. - return typeof encoding === 'string' - ? createBuffer(size).fill(fill, encoding) - : createBuffer(size).fill(fill) - } - return createBuffer(size) -} - -/** - * Creates a new filled Buffer instance. - * alloc(size[, fill[, encoding]]) - **/ -Buffer.alloc = function (size, fill, encoding) { - return alloc(size, fill, encoding) -} - -function allocUnsafe (size) { - assertSize(size) - return createBuffer(size < 0 ? 0 : checked(size) | 0) -} - -/** - * Equivalent to Buffer(num), by default creates a non-zero-filled Buffer instance. - * */ -Buffer.allocUnsafe = function (size) { - return allocUnsafe(size) -} -/** - * Equivalent to SlowBuffer(num), by default creates a non-zero-filled Buffer instance. - */ -Buffer.allocUnsafeSlow = function (size) { - return allocUnsafe(size) -} - -function fromString (string, encoding) { - if (typeof encoding !== 'string' || encoding === '') { - encoding = 'utf8' - } - - if (!Buffer.isEncoding(encoding)) { - throw new TypeError('Unknown encoding: ' + encoding) - } - - var length = byteLength(string, encoding) | 0 - var buf = createBuffer(length) - - var actual = buf.write(string, encoding) - - if (actual !== length) { - // Writing a hex string, for example, that contains invalid characters will - // cause everything after the first invalid character to be ignored. (e.g. - // 'abxxcd' will be treated as 'ab') - buf = buf.slice(0, actual) - } - - return buf -} - -function fromArrayLike (array) { - var length = array.length < 0 ? 0 : checked(array.length) | 0 - var buf = createBuffer(length) - for (var i = 0; i < length; i += 1) { - buf[i] = array[i] & 255 - } - return buf -} - -function fromArrayBuffer (array, byteOffset, length) { - if (byteOffset < 0 || array.byteLength < byteOffset) { - throw new RangeError('"offset" is outside of buffer bounds') - } - - if (array.byteLength < byteOffset + (length || 0)) { - throw new RangeError('"length" is outside of buffer bounds') - } - - var buf - if (byteOffset === undefined && length === undefined) { - buf = new Uint8Array(array) - } else if (length === undefined) { - buf = new Uint8Array(array, byteOffset) - } else { - buf = new Uint8Array(array, byteOffset, length) - } - - // Return an augmented `Uint8Array` instance - buf.__proto__ = Buffer.prototype - return buf -} - -function fromObject (obj) { - if (Buffer.isBuffer(obj)) { - var len = checked(obj.length) | 0 - var buf = createBuffer(len) - - if (buf.length === 0) { - return buf - } - - obj.copy(buf, 0, 0, len) - return buf - } - - if (obj.length !== undefined) { - if (typeof obj.length !== 'number' || numberIsNaN(obj.length)) { - return createBuffer(0) - } - return fromArrayLike(obj) - } - - if (obj.type === 'Buffer' && Array.isArray(obj.data)) { - return fromArrayLike(obj.data) - } -} - -function checked (length) { - // Note: cannot use `length < K_MAX_LENGTH` here because that fails when - // length is NaN (which is otherwise coerced to zero.) - if (length >= K_MAX_LENGTH) { - throw new RangeError('Attempt to allocate Buffer larger than maximum ' + - 'size: 0x' + K_MAX_LENGTH.toString(16) + ' bytes') - } - return length | 0 -} - -function SlowBuffer (length) { - if (+length != length) { // eslint-disable-line eqeqeq - length = 0 - } - return Buffer.alloc(+length) -} - -Buffer.isBuffer = function isBuffer (b) { - return b != null && b._isBuffer === true && - b !== Buffer.prototype // so Buffer.isBuffer(Buffer.prototype) will be false -} - -Buffer.compare = function compare (a, b) { - if (isInstance(a, Uint8Array)) a = Buffer.from(a, a.offset, a.byteLength) - if (isInstance(b, Uint8Array)) b = Buffer.from(b, b.offset, b.byteLength) - if (!Buffer.isBuffer(a) || !Buffer.isBuffer(b)) { - throw new TypeError( - 'The "buf1", "buf2" arguments must be one of type Buffer or Uint8Array' - ) - } - - if (a === b) return 0 - - var x = a.length - var y = b.length - - for (var i = 0, len = Math.min(x, y); i < len; ++i) { - if (a[i] !== b[i]) { - x = a[i] - y = b[i] - break - } - } - - if (x < y) return -1 - if (y < x) return 1 - return 0 -} - -Buffer.isEncoding = function isEncoding (encoding) { - switch (String(encoding).toLowerCase()) { - case 'hex': - case 'utf8': - case 'utf-8': - case 'ascii': - case 'latin1': - case 'binary': - case 'base64': - case 'ucs2': - case 'ucs-2': - case 'utf16le': - case 'utf-16le': - return true - default: - return false - } -} - -Buffer.concat = function concat (list, length) { - if (!Array.isArray(list)) { - throw new TypeError('"list" argument must be an Array of Buffers') - } - - if (list.length === 0) { - return Buffer.alloc(0) - } - - var i - if (length === undefined) { - length = 0 - for (i = 0; i < list.length; ++i) { - length += list[i].length - } - } - - var buffer = Buffer.allocUnsafe(length) - var pos = 0 - for (i = 0; i < list.length; ++i) { - var buf = list[i] - if (isInstance(buf, Uint8Array)) { - buf = Buffer.from(buf) - } - if (!Buffer.isBuffer(buf)) { - throw new TypeError('"list" argument must be an Array of Buffers') - } - buf.copy(buffer, pos) - pos += buf.length - } - return buffer -} - -function byteLength (string, encoding) { - if (Buffer.isBuffer(string)) { - return string.length - } - if (ArrayBuffer.isView(string) || isInstance(string, ArrayBuffer)) { - return string.byteLength - } - if (typeof string !== 'string') { - throw new TypeError( - 'The "string" argument must be one of type string, Buffer, or ArrayBuffer. ' + - 'Received type ' + typeof string - ) - } - - var len = string.length - var mustMatch = (arguments.length > 2 && arguments[2] === true) - if (!mustMatch && len === 0) return 0 - - // Use a for loop to avoid recursion - var loweredCase = false - for (;;) { - switch (encoding) { - case 'ascii': - case 'latin1': - case 'binary': - return len - case 'utf8': - case 'utf-8': - return utf8ToBytes(string).length - case 'ucs2': - case 'ucs-2': - case 'utf16le': - case 'utf-16le': - return len * 2 - case 'hex': - return len >>> 1 - case 'base64': - return base64ToBytes(string).length - default: - if (loweredCase) { - return mustMatch ? -1 : utf8ToBytes(string).length // assume utf8 - } - encoding = ('' + encoding).toLowerCase() - loweredCase = true - } - } -} -Buffer.byteLength = byteLength - -function slowToString (encoding, start, end) { - var loweredCase = false - - // No need to verify that "this.length <= MAX_UINT32" since it's a read-only - // property of a typed array. - - // This behaves neither like String nor Uint8Array in that we set start/end - // to their upper/lower bounds if the value passed is out of range. - // undefined is handled specially as per ECMA-262 6th Edition, - // Section 13.3.3.7 Runtime Semantics: KeyedBindingInitialization. - if (start === undefined || start < 0) { - start = 0 - } - // Return early if start > this.length. Done here to prevent potential uint32 - // coercion fail below. - if (start > this.length) { - return '' - } - - if (end === undefined || end > this.length) { - end = this.length - } - - if (end <= 0) { - return '' - } - - // Force coersion to uint32. This will also coerce falsey/NaN values to 0. - end >>>= 0 - start >>>= 0 - - if (end <= start) { - return '' - } - - if (!encoding) encoding = 'utf8' - - while (true) { - switch (encoding) { - case 'hex': - return hexSlice(this, start, end) - - case 'utf8': - case 'utf-8': - return utf8Slice(this, start, end) - - case 'ascii': - return asciiSlice(this, start, end) - - case 'latin1': - case 'binary': - return latin1Slice(this, start, end) - - case 'base64': - return base64Slice(this, start, end) - - case 'ucs2': - case 'ucs-2': - case 'utf16le': - case 'utf-16le': - return utf16leSlice(this, start, end) - - default: - if (loweredCase) throw new TypeError('Unknown encoding: ' + encoding) - encoding = (encoding + '').toLowerCase() - loweredCase = true - } - } -} - -// This property is used by `Buffer.isBuffer` (and the `is-buffer` npm package) -// to detect a Buffer instance. It's not possible to use `instanceof Buffer` -// reliably in a browserify context because there could be multiple different -// copies of the 'buffer' package in use. This method works even for Buffer -// instances that were created from another copy of the `buffer` package. -// See: https://github.com/feross/buffer/issues/154 -Buffer.prototype._isBuffer = true - -function swap (b, n, m) { - var i = b[n] - b[n] = b[m] - b[m] = i -} - -Buffer.prototype.swap16 = function swap16 () { - var len = this.length - if (len % 2 !== 0) { - throw new RangeError('Buffer size must be a multiple of 16-bits') - } - for (var i = 0; i < len; i += 2) { - swap(this, i, i + 1) - } - return this -} - -Buffer.prototype.swap32 = function swap32 () { - var len = this.length - if (len % 4 !== 0) { - throw new RangeError('Buffer size must be a multiple of 32-bits') - } - for (var i = 0; i < len; i += 4) { - swap(this, i, i + 3) - swap(this, i + 1, i + 2) - } - return this -} - -Buffer.prototype.swap64 = function swap64 () { - var len = this.length - if (len % 8 !== 0) { - throw new RangeError('Buffer size must be a multiple of 64-bits') - } - for (var i = 0; i < len; i += 8) { - swap(this, i, i + 7) - swap(this, i + 1, i + 6) - swap(this, i + 2, i + 5) - swap(this, i + 3, i + 4) - } - return this -} - -Buffer.prototype.toString = function toString () { - var length = this.length - if (length === 0) return '' - if (arguments.length === 0) return utf8Slice(this, 0, length) - return slowToString.apply(this, arguments) -} - -Buffer.prototype.toLocaleString = Buffer.prototype.toString - -Buffer.prototype.equals = function equals (b) { - if (!Buffer.isBuffer(b)) throw new TypeError('Argument must be a Buffer') - if (this === b) return true - return Buffer.compare(this, b) === 0 -} - -Buffer.prototype.inspect = function inspect () { - var str = '' - var max = exports.INSPECT_MAX_BYTES - str = this.toString('hex', 0, max).replace(/(.{2})/g, '$1 ').trim() - if (this.length > max) str += ' ... ' - return '' -} - -Buffer.prototype.compare = function compare (target, start, end, thisStart, thisEnd) { - if (isInstance(target, Uint8Array)) { - target = Buffer.from(target, target.offset, target.byteLength) - } - if (!Buffer.isBuffer(target)) { - throw new TypeError( - 'The "target" argument must be one of type Buffer or Uint8Array. ' + - 'Received type ' + (typeof target) - ) - } - - if (start === undefined) { - start = 0 - } - if (end === undefined) { - end = target ? target.length : 0 - } - if (thisStart === undefined) { - thisStart = 0 - } - if (thisEnd === undefined) { - thisEnd = this.length - } - - if (start < 0 || end > target.length || thisStart < 0 || thisEnd > this.length) { - throw new RangeError('out of range index') - } - - if (thisStart >= thisEnd && start >= end) { - return 0 - } - if (thisStart >= thisEnd) { - return -1 - } - if (start >= end) { - return 1 - } - - start >>>= 0 - end >>>= 0 - thisStart >>>= 0 - thisEnd >>>= 0 - - if (this === target) return 0 - - var x = thisEnd - thisStart - var y = end - start - var len = Math.min(x, y) - - var thisCopy = this.slice(thisStart, thisEnd) - var targetCopy = target.slice(start, end) - - for (var i = 0; i < len; ++i) { - if (thisCopy[i] !== targetCopy[i]) { - x = thisCopy[i] - y = targetCopy[i] - break - } - } - - if (x < y) return -1 - if (y < x) return 1 - return 0 -} - -// Finds either the first index of `val` in `buffer` at offset >= `byteOffset`, -// OR the last index of `val` in `buffer` at offset <= `byteOffset`. -// -// Arguments: -// - buffer - a Buffer to search -// - val - a string, Buffer, or number -// - byteOffset - an index into `buffer`; will be clamped to an int32 -// - encoding - an optional encoding, relevant is val is a string -// - dir - true for indexOf, false for lastIndexOf -function bidirectionalIndexOf (buffer, val, byteOffset, encoding, dir) { - // Empty buffer means no match - if (buffer.length === 0) return -1 - - // Normalize byteOffset - if (typeof byteOffset === 'string') { - encoding = byteOffset - byteOffset = 0 - } else if (byteOffset > 0x7fffffff) { - byteOffset = 0x7fffffff - } else if (byteOffset < -0x80000000) { - byteOffset = -0x80000000 - } - byteOffset = +byteOffset // Coerce to Number. - if (numberIsNaN(byteOffset)) { - // byteOffset: it it's undefined, null, NaN, "foo", etc, search whole buffer - byteOffset = dir ? 0 : (buffer.length - 1) - } - - // Normalize byteOffset: negative offsets start from the end of the buffer - if (byteOffset < 0) byteOffset = buffer.length + byteOffset - if (byteOffset >= buffer.length) { - if (dir) return -1 - else byteOffset = buffer.length - 1 - } else if (byteOffset < 0) { - if (dir) byteOffset = 0 - else return -1 - } - - // Normalize val - if (typeof val === 'string') { - val = Buffer.from(val, encoding) - } - - // Finally, search either indexOf (if dir is true) or lastIndexOf - if (Buffer.isBuffer(val)) { - // Special case: looking for empty string/buffer always fails - if (val.length === 0) { - return -1 - } - return arrayIndexOf(buffer, val, byteOffset, encoding, dir) - } else if (typeof val === 'number') { - val = val & 0xFF // Search for a byte value [0-255] - if (typeof Uint8Array.prototype.indexOf === 'function') { - if (dir) { - return Uint8Array.prototype.indexOf.call(buffer, val, byteOffset) - } else { - return Uint8Array.prototype.lastIndexOf.call(buffer, val, byteOffset) - } - } - return arrayIndexOf(buffer, [ val ], byteOffset, encoding, dir) - } - - throw new TypeError('val must be string, number or Buffer') -} - -function arrayIndexOf (arr, val, byteOffset, encoding, dir) { - var indexSize = 1 - var arrLength = arr.length - var valLength = val.length - - if (encoding !== undefined) { - encoding = String(encoding).toLowerCase() - if (encoding === 'ucs2' || encoding === 'ucs-2' || - encoding === 'utf16le' || encoding === 'utf-16le') { - if (arr.length < 2 || val.length < 2) { - return -1 - } - indexSize = 2 - arrLength /= 2 - valLength /= 2 - byteOffset /= 2 - } - } - - function read (buf, i) { - if (indexSize === 1) { - return buf[i] - } else { - return buf.readUInt16BE(i * indexSize) - } - } - - var i - if (dir) { - var foundIndex = -1 - for (i = byteOffset; i < arrLength; i++) { - if (read(arr, i) === read(val, foundIndex === -1 ? 0 : i - foundIndex)) { - if (foundIndex === -1) foundIndex = i - if (i - foundIndex + 1 === valLength) return foundIndex * indexSize - } else { - if (foundIndex !== -1) i -= i - foundIndex - foundIndex = -1 - } - } - } else { - if (byteOffset + valLength > arrLength) byteOffset = arrLength - valLength - for (i = byteOffset; i >= 0; i--) { - var found = true - for (var j = 0; j < valLength; j++) { - if (read(arr, i + j) !== read(val, j)) { - found = false - break - } - } - if (found) return i - } - } - - return -1 -} - -Buffer.prototype.includes = function includes (val, byteOffset, encoding) { - return this.indexOf(val, byteOffset, encoding) !== -1 -} - -Buffer.prototype.indexOf = function indexOf (val, byteOffset, encoding) { - return bidirectionalIndexOf(this, val, byteOffset, encoding, true) -} - -Buffer.prototype.lastIndexOf = function lastIndexOf (val, byteOffset, encoding) { - return bidirectionalIndexOf(this, val, byteOffset, encoding, false) -} - -function hexWrite (buf, string, offset, length) { - offset = Number(offset) || 0 - var remaining = buf.length - offset - if (!length) { - length = remaining - } else { - length = Number(length) - if (length > remaining) { - length = remaining - } - } - - var strLen = string.length - - if (length > strLen / 2) { - length = strLen / 2 - } - for (var i = 0; i < length; ++i) { - var parsed = parseInt(string.substr(i * 2, 2), 16) - if (numberIsNaN(parsed)) return i - buf[offset + i] = parsed - } - return i -} - -function utf8Write (buf, string, offset, length) { - return blitBuffer(utf8ToBytes(string, buf.length - offset), buf, offset, length) -} - -function asciiWrite (buf, string, offset, length) { - return blitBuffer(asciiToBytes(string), buf, offset, length) -} - -function latin1Write (buf, string, offset, length) { - return asciiWrite(buf, string, offset, length) -} - -function base64Write (buf, string, offset, length) { - return blitBuffer(base64ToBytes(string), buf, offset, length) -} - -function ucs2Write (buf, string, offset, length) { - return blitBuffer(utf16leToBytes(string, buf.length - offset), buf, offset, length) -} - -Buffer.prototype.write = function write (string, offset, length, encoding) { - // Buffer#write(string) - if (offset === undefined) { - encoding = 'utf8' - length = this.length - offset = 0 - // Buffer#write(string, encoding) - } else if (length === undefined && typeof offset === 'string') { - encoding = offset - length = this.length - offset = 0 - // Buffer#write(string, offset[, length][, encoding]) - } else if (isFinite(offset)) { - offset = offset >>> 0 - if (isFinite(length)) { - length = length >>> 0 - if (encoding === undefined) encoding = 'utf8' - } else { - encoding = length - length = undefined - } - } else { - throw new Error( - 'Buffer.write(string, encoding, offset[, length]) is no longer supported' - ) - } - - var remaining = this.length - offset - if (length === undefined || length > remaining) length = remaining - - if ((string.length > 0 && (length < 0 || offset < 0)) || offset > this.length) { - throw new RangeError('Attempt to write outside buffer bounds') - } - - if (!encoding) encoding = 'utf8' - - var loweredCase = false - for (;;) { - switch (encoding) { - case 'hex': - return hexWrite(this, string, offset, length) - - case 'utf8': - case 'utf-8': - return utf8Write(this, string, offset, length) - - case 'ascii': - return asciiWrite(this, string, offset, length) - - case 'latin1': - case 'binary': - return latin1Write(this, string, offset, length) - - case 'base64': - // Warning: maxLength not taken into account in base64Write - return base64Write(this, string, offset, length) - - case 'ucs2': - case 'ucs-2': - case 'utf16le': - case 'utf-16le': - return ucs2Write(this, string, offset, length) - - default: - if (loweredCase) throw new TypeError('Unknown encoding: ' + encoding) - encoding = ('' + encoding).toLowerCase() - loweredCase = true - } - } -} - -Buffer.prototype.toJSON = function toJSON () { - return { - type: 'Buffer', - data: Array.prototype.slice.call(this._arr || this, 0) - } -} - -function base64Slice (buf, start, end) { - if (start === 0 && end === buf.length) { - return base64.fromByteArray(buf) - } else { - return base64.fromByteArray(buf.slice(start, end)) - } -} - -function utf8Slice (buf, start, end) { - end = Math.min(buf.length, end) - var res = [] - - var i = start - while (i < end) { - var firstByte = buf[i] - var codePoint = null - var bytesPerSequence = (firstByte > 0xEF) ? 4 - : (firstByte > 0xDF) ? 3 - : (firstByte > 0xBF) ? 2 - : 1 - - if (i + bytesPerSequence <= end) { - var secondByte, thirdByte, fourthByte, tempCodePoint - - switch (bytesPerSequence) { - case 1: - if (firstByte < 0x80) { - codePoint = firstByte - } - break - case 2: - secondByte = buf[i + 1] - if ((secondByte & 0xC0) === 0x80) { - tempCodePoint = (firstByte & 0x1F) << 0x6 | (secondByte & 0x3F) - if (tempCodePoint > 0x7F) { - codePoint = tempCodePoint - } - } - break - case 3: - secondByte = buf[i + 1] - thirdByte = buf[i + 2] - if ((secondByte & 0xC0) === 0x80 && (thirdByte & 0xC0) === 0x80) { - tempCodePoint = (firstByte & 0xF) << 0xC | (secondByte & 0x3F) << 0x6 | (thirdByte & 0x3F) - if (tempCodePoint > 0x7FF && (tempCodePoint < 0xD800 || tempCodePoint > 0xDFFF)) { - codePoint = tempCodePoint - } - } - break - case 4: - secondByte = buf[i + 1] - thirdByte = buf[i + 2] - fourthByte = buf[i + 3] - if ((secondByte & 0xC0) === 0x80 && (thirdByte & 0xC0) === 0x80 && (fourthByte & 0xC0) === 0x80) { - tempCodePoint = (firstByte & 0xF) << 0x12 | (secondByte & 0x3F) << 0xC | (thirdByte & 0x3F) << 0x6 | (fourthByte & 0x3F) - if (tempCodePoint > 0xFFFF && tempCodePoint < 0x110000) { - codePoint = tempCodePoint - } - } - } - } - - if (codePoint === null) { - // we did not generate a valid codePoint so insert a - // replacement char (U+FFFD) and advance only 1 byte - codePoint = 0xFFFD - bytesPerSequence = 1 - } else if (codePoint > 0xFFFF) { - // encode to utf16 (surrogate pair dance) - codePoint -= 0x10000 - res.push(codePoint >>> 10 & 0x3FF | 0xD800) - codePoint = 0xDC00 | codePoint & 0x3FF - } - - res.push(codePoint) - i += bytesPerSequence - } - - return decodeCodePointsArray(res) -} - -// Based on http://stackoverflow.com/a/22747272/680742, the browser with -// the lowest limit is Chrome, with 0x10000 args. -// We go 1 magnitude less, for safety -var MAX_ARGUMENTS_LENGTH = 0x1000 - -function decodeCodePointsArray (codePoints) { - var len = codePoints.length - if (len <= MAX_ARGUMENTS_LENGTH) { - return String.fromCharCode.apply(String, codePoints) // avoid extra slice() - } - - // Decode in chunks to avoid "call stack size exceeded". - var res = '' - var i = 0 - while (i < len) { - res += String.fromCharCode.apply( - String, - codePoints.slice(i, i += MAX_ARGUMENTS_LENGTH) - ) - } - return res -} - -function asciiSlice (buf, start, end) { - var ret = '' - end = Math.min(buf.length, end) - - for (var i = start; i < end; ++i) { - ret += String.fromCharCode(buf[i] & 0x7F) - } - return ret -} - -function latin1Slice (buf, start, end) { - var ret = '' - end = Math.min(buf.length, end) - - for (var i = start; i < end; ++i) { - ret += String.fromCharCode(buf[i]) - } - return ret -} - -function hexSlice (buf, start, end) { - var len = buf.length - - if (!start || start < 0) start = 0 - if (!end || end < 0 || end > len) end = len - - var out = '' - for (var i = start; i < end; ++i) { - out += toHex(buf[i]) - } - return out -} - -function utf16leSlice (buf, start, end) { - var bytes = buf.slice(start, end) - var res = '' - for (var i = 0; i < bytes.length; i += 2) { - res += String.fromCharCode(bytes[i] + (bytes[i + 1] * 256)) - } - return res -} - -Buffer.prototype.slice = function slice (start, end) { - var len = this.length - start = ~~start - end = end === undefined ? len : ~~end - - if (start < 0) { - start += len - if (start < 0) start = 0 - } else if (start > len) { - start = len - } - - if (end < 0) { - end += len - if (end < 0) end = 0 - } else if (end > len) { - end = len - } - - if (end < start) end = start - - var newBuf = this.subarray(start, end) - // Return an augmented `Uint8Array` instance - newBuf.__proto__ = Buffer.prototype - return newBuf -} - -/* - * Need to make sure that buffer isn't trying to write out of bounds. - */ -function checkOffset (offset, ext, length) { - if ((offset % 1) !== 0 || offset < 0) throw new RangeError('offset is not uint') - if (offset + ext > length) throw new RangeError('Trying to access beyond buffer length') -} - -Buffer.prototype.readUIntLE = function readUIntLE (offset, byteLength, noAssert) { - offset = offset >>> 0 - byteLength = byteLength >>> 0 - if (!noAssert) checkOffset(offset, byteLength, this.length) - - var val = this[offset] - var mul = 1 - var i = 0 - while (++i < byteLength && (mul *= 0x100)) { - val += this[offset + i] * mul - } - - return val -} - -Buffer.prototype.readUIntBE = function readUIntBE (offset, byteLength, noAssert) { - offset = offset >>> 0 - byteLength = byteLength >>> 0 - if (!noAssert) { - checkOffset(offset, byteLength, this.length) - } - - var val = this[offset + --byteLength] - var mul = 1 - while (byteLength > 0 && (mul *= 0x100)) { - val += this[offset + --byteLength] * mul - } - - return val -} - -Buffer.prototype.readUInt8 = function readUInt8 (offset, noAssert) { - offset = offset >>> 0 - if (!noAssert) checkOffset(offset, 1, this.length) - return this[offset] -} - -Buffer.prototype.readUInt16LE = function readUInt16LE (offset, noAssert) { - offset = offset >>> 0 - if (!noAssert) checkOffset(offset, 2, this.length) - return this[offset] | (this[offset + 1] << 8) -} - -Buffer.prototype.readUInt16BE = function readUInt16BE (offset, noAssert) { - offset = offset >>> 0 - if (!noAssert) checkOffset(offset, 2, this.length) - return (this[offset] << 8) | this[offset + 1] -} - -Buffer.prototype.readUInt32LE = function readUInt32LE (offset, noAssert) { - offset = offset >>> 0 - if (!noAssert) checkOffset(offset, 4, this.length) - - return ((this[offset]) | - (this[offset + 1] << 8) | - (this[offset + 2] << 16)) + - (this[offset + 3] * 0x1000000) -} - -Buffer.prototype.readUInt32BE = function readUInt32BE (offset, noAssert) { - offset = offset >>> 0 - if (!noAssert) checkOffset(offset, 4, this.length) - - return (this[offset] * 0x1000000) + - ((this[offset + 1] << 16) | - (this[offset + 2] << 8) | - this[offset + 3]) -} - -Buffer.prototype.readIntLE = function readIntLE (offset, byteLength, noAssert) { - offset = offset >>> 0 - byteLength = byteLength >>> 0 - if (!noAssert) checkOffset(offset, byteLength, this.length) - - var val = this[offset] - var mul = 1 - var i = 0 - while (++i < byteLength && (mul *= 0x100)) { - val += this[offset + i] * mul - } - mul *= 0x80 - - if (val >= mul) val -= Math.pow(2, 8 * byteLength) - - return val -} - -Buffer.prototype.readIntBE = function readIntBE (offset, byteLength, noAssert) { - offset = offset >>> 0 - byteLength = byteLength >>> 0 - if (!noAssert) checkOffset(offset, byteLength, this.length) - - var i = byteLength - var mul = 1 - var val = this[offset + --i] - while (i > 0 && (mul *= 0x100)) { - val += this[offset + --i] * mul - } - mul *= 0x80 - - if (val >= mul) val -= Math.pow(2, 8 * byteLength) - - return val -} - -Buffer.prototype.readInt8 = function readInt8 (offset, noAssert) { - offset = offset >>> 0 - if (!noAssert) checkOffset(offset, 1, this.length) - if (!(this[offset] & 0x80)) return (this[offset]) - return ((0xff - this[offset] + 1) * -1) -} - -Buffer.prototype.readInt16LE = function readInt16LE (offset, noAssert) { - offset = offset >>> 0 - if (!noAssert) checkOffset(offset, 2, this.length) - var val = this[offset] | (this[offset + 1] << 8) - return (val & 0x8000) ? val | 0xFFFF0000 : val -} - -Buffer.prototype.readInt16BE = function readInt16BE (offset, noAssert) { - offset = offset >>> 0 - if (!noAssert) checkOffset(offset, 2, this.length) - var val = this[offset + 1] | (this[offset] << 8) - return (val & 0x8000) ? val | 0xFFFF0000 : val -} - -Buffer.prototype.readInt32LE = function readInt32LE (offset, noAssert) { - offset = offset >>> 0 - if (!noAssert) checkOffset(offset, 4, this.length) - - return (this[offset]) | - (this[offset + 1] << 8) | - (this[offset + 2] << 16) | - (this[offset + 3] << 24) -} - -Buffer.prototype.readInt32BE = function readInt32BE (offset, noAssert) { - offset = offset >>> 0 - if (!noAssert) checkOffset(offset, 4, this.length) - - return (this[offset] << 24) | - (this[offset + 1] << 16) | - (this[offset + 2] << 8) | - (this[offset + 3]) -} - -Buffer.prototype.readFloatLE = function readFloatLE (offset, noAssert) { - offset = offset >>> 0 - if (!noAssert) checkOffset(offset, 4, this.length) - return ieee754.read(this, offset, true, 23, 4) -} - -Buffer.prototype.readFloatBE = function readFloatBE (offset, noAssert) { - offset = offset >>> 0 - if (!noAssert) checkOffset(offset, 4, this.length) - return ieee754.read(this, offset, false, 23, 4) -} - -Buffer.prototype.readDoubleLE = function readDoubleLE (offset, noAssert) { - offset = offset >>> 0 - if (!noAssert) checkOffset(offset, 8, this.length) - return ieee754.read(this, offset, true, 52, 8) -} - -Buffer.prototype.readDoubleBE = function readDoubleBE (offset, noAssert) { - offset = offset >>> 0 - if (!noAssert) checkOffset(offset, 8, this.length) - return ieee754.read(this, offset, false, 52, 8) -} - -function checkInt (buf, value, offset, ext, max, min) { - if (!Buffer.isBuffer(buf)) throw new TypeError('"buffer" argument must be a Buffer instance') - if (value > max || value < min) throw new RangeError('"value" argument is out of bounds') - if (offset + ext > buf.length) throw new RangeError('Index out of range') -} - -Buffer.prototype.writeUIntLE = function writeUIntLE (value, offset, byteLength, noAssert) { - value = +value - offset = offset >>> 0 - byteLength = byteLength >>> 0 - if (!noAssert) { - var maxBytes = Math.pow(2, 8 * byteLength) - 1 - checkInt(this, value, offset, byteLength, maxBytes, 0) - } - - var mul = 1 - var i = 0 - this[offset] = value & 0xFF - while (++i < byteLength && (mul *= 0x100)) { - this[offset + i] = (value / mul) & 0xFF - } - - return offset + byteLength -} - -Buffer.prototype.writeUIntBE = function writeUIntBE (value, offset, byteLength, noAssert) { - value = +value - offset = offset >>> 0 - byteLength = byteLength >>> 0 - if (!noAssert) { - var maxBytes = Math.pow(2, 8 * byteLength) - 1 - checkInt(this, value, offset, byteLength, maxBytes, 0) - } - - var i = byteLength - 1 - var mul = 1 - this[offset + i] = value & 0xFF - while (--i >= 0 && (mul *= 0x100)) { - this[offset + i] = (value / mul) & 0xFF - } - - return offset + byteLength -} - -Buffer.prototype.writeUInt8 = function writeUInt8 (value, offset, noAssert) { - value = +value - offset = offset >>> 0 - if (!noAssert) checkInt(this, value, offset, 1, 0xff, 0) - this[offset] = (value & 0xff) - return offset + 1 -} - -Buffer.prototype.writeUInt16LE = function writeUInt16LE (value, offset, noAssert) { - value = +value - offset = offset >>> 0 - if (!noAssert) checkInt(this, value, offset, 2, 0xffff, 0) - this[offset] = (value & 0xff) - this[offset + 1] = (value >>> 8) - return offset + 2 -} - -Buffer.prototype.writeUInt16BE = function writeUInt16BE (value, offset, noAssert) { - value = +value - offset = offset >>> 0 - if (!noAssert) checkInt(this, value, offset, 2, 0xffff, 0) - this[offset] = (value >>> 8) - this[offset + 1] = (value & 0xff) - return offset + 2 -} - -Buffer.prototype.writeUInt32LE = function writeUInt32LE (value, offset, noAssert) { - value = +value - offset = offset >>> 0 - if (!noAssert) checkInt(this, value, offset, 4, 0xffffffff, 0) - this[offset + 3] = (value >>> 24) - this[offset + 2] = (value >>> 16) - this[offset + 1] = (value >>> 8) - this[offset] = (value & 0xff) - return offset + 4 -} - -Buffer.prototype.writeUInt32BE = function writeUInt32BE (value, offset, noAssert) { - value = +value - offset = offset >>> 0 - if (!noAssert) checkInt(this, value, offset, 4, 0xffffffff, 0) - this[offset] = (value >>> 24) - this[offset + 1] = (value >>> 16) - this[offset + 2] = (value >>> 8) - this[offset + 3] = (value & 0xff) - return offset + 4 -} - -Buffer.prototype.writeIntLE = function writeIntLE (value, offset, byteLength, noAssert) { - value = +value - offset = offset >>> 0 - if (!noAssert) { - var limit = Math.pow(2, (8 * byteLength) - 1) - - checkInt(this, value, offset, byteLength, limit - 1, -limit) - } - - var i = 0 - var mul = 1 - var sub = 0 - this[offset] = value & 0xFF - while (++i < byteLength && (mul *= 0x100)) { - if (value < 0 && sub === 0 && this[offset + i - 1] !== 0) { - sub = 1 - } - this[offset + i] = ((value / mul) >> 0) - sub & 0xFF - } - - return offset + byteLength -} - -Buffer.prototype.writeIntBE = function writeIntBE (value, offset, byteLength, noAssert) { - value = +value - offset = offset >>> 0 - if (!noAssert) { - var limit = Math.pow(2, (8 * byteLength) - 1) - - checkInt(this, value, offset, byteLength, limit - 1, -limit) - } - - var i = byteLength - 1 - var mul = 1 - var sub = 0 - this[offset + i] = value & 0xFF - while (--i >= 0 && (mul *= 0x100)) { - if (value < 0 && sub === 0 && this[offset + i + 1] !== 0) { - sub = 1 - } - this[offset + i] = ((value / mul) >> 0) - sub & 0xFF - } - - return offset + byteLength -} - -Buffer.prototype.writeInt8 = function writeInt8 (value, offset, noAssert) { - value = +value - offset = offset >>> 0 - if (!noAssert) checkInt(this, value, offset, 1, 0x7f, -0x80) - if (value < 0) value = 0xff + value + 1 - this[offset] = (value & 0xff) - return offset + 1 -} - -Buffer.prototype.writeInt16LE = function writeInt16LE (value, offset, noAssert) { - value = +value - offset = offset >>> 0 - if (!noAssert) checkInt(this, value, offset, 2, 0x7fff, -0x8000) - this[offset] = (value & 0xff) - this[offset + 1] = (value >>> 8) - return offset + 2 -} - -Buffer.prototype.writeInt16BE = function writeInt16BE (value, offset, noAssert) { - value = +value - offset = offset >>> 0 - if (!noAssert) checkInt(this, value, offset, 2, 0x7fff, -0x8000) - this[offset] = (value >>> 8) - this[offset + 1] = (value & 0xff) - return offset + 2 -} - -Buffer.prototype.writeInt32LE = function writeInt32LE (value, offset, noAssert) { - value = +value - offset = offset >>> 0 - if (!noAssert) checkInt(this, value, offset, 4, 0x7fffffff, -0x80000000) - this[offset] = (value & 0xff) - this[offset + 1] = (value >>> 8) - this[offset + 2] = (value >>> 16) - this[offset + 3] = (value >>> 24) - return offset + 4 -} - -Buffer.prototype.writeInt32BE = function writeInt32BE (value, offset, noAssert) { - value = +value - offset = offset >>> 0 - if (!noAssert) checkInt(this, value, offset, 4, 0x7fffffff, -0x80000000) - if (value < 0) value = 0xffffffff + value + 1 - this[offset] = (value >>> 24) - this[offset + 1] = (value >>> 16) - this[offset + 2] = (value >>> 8) - this[offset + 3] = (value & 0xff) - return offset + 4 -} - -function checkIEEE754 (buf, value, offset, ext, max, min) { - if (offset + ext > buf.length) throw new RangeError('Index out of range') - if (offset < 0) throw new RangeError('Index out of range') -} - -function writeFloat (buf, value, offset, littleEndian, noAssert) { - value = +value - offset = offset >>> 0 - if (!noAssert) { - checkIEEE754(buf, value, offset, 4, 3.4028234663852886e+38, -3.4028234663852886e+38) - } - ieee754.write(buf, value, offset, littleEndian, 23, 4) - return offset + 4 -} - -Buffer.prototype.writeFloatLE = function writeFloatLE (value, offset, noAssert) { - return writeFloat(this, value, offset, true, noAssert) -} - -Buffer.prototype.writeFloatBE = function writeFloatBE (value, offset, noAssert) { - return writeFloat(this, value, offset, false, noAssert) -} - -function writeDouble (buf, value, offset, littleEndian, noAssert) { - value = +value - offset = offset >>> 0 - if (!noAssert) { - checkIEEE754(buf, value, offset, 8, 1.7976931348623157E+308, -1.7976931348623157E+308) - } - ieee754.write(buf, value, offset, littleEndian, 52, 8) - return offset + 8 -} - -Buffer.prototype.writeDoubleLE = function writeDoubleLE (value, offset, noAssert) { - return writeDouble(this, value, offset, true, noAssert) -} - -Buffer.prototype.writeDoubleBE = function writeDoubleBE (value, offset, noAssert) { - return writeDouble(this, value, offset, false, noAssert) -} - -// copy(targetBuffer, targetStart=0, sourceStart=0, sourceEnd=buffer.length) -Buffer.prototype.copy = function copy (target, targetStart, start, end) { - if (!Buffer.isBuffer(target)) throw new TypeError('argument should be a Buffer') - if (!start) start = 0 - if (!end && end !== 0) end = this.length - if (targetStart >= target.length) targetStart = target.length - if (!targetStart) targetStart = 0 - if (end > 0 && end < start) end = start - - // Copy 0 bytes; we're done - if (end === start) return 0 - if (target.length === 0 || this.length === 0) return 0 - - // Fatal error conditions - if (targetStart < 0) { - throw new RangeError('targetStart out of bounds') - } - if (start < 0 || start >= this.length) throw new RangeError('Index out of range') - if (end < 0) throw new RangeError('sourceEnd out of bounds') - - // Are we oob? - if (end > this.length) end = this.length - if (target.length - targetStart < end - start) { - end = target.length - targetStart + start - } - - var len = end - start - - if (this === target && typeof Uint8Array.prototype.copyWithin === 'function') { - // Use built-in when available, missing from IE11 - this.copyWithin(targetStart, start, end) - } else if (this === target && start < targetStart && targetStart < end) { - // descending copy from end - for (var i = len - 1; i >= 0; --i) { - target[i + targetStart] = this[i + start] - } - } else { - Uint8Array.prototype.set.call( - target, - this.subarray(start, end), - targetStart - ) - } - - return len -} - -// Usage: -// buffer.fill(number[, offset[, end]]) -// buffer.fill(buffer[, offset[, end]]) -// buffer.fill(string[, offset[, end]][, encoding]) -Buffer.prototype.fill = function fill (val, start, end, encoding) { - // Handle string cases: - if (typeof val === 'string') { - if (typeof start === 'string') { - encoding = start - start = 0 - end = this.length - } else if (typeof end === 'string') { - encoding = end - end = this.length - } - if (encoding !== undefined && typeof encoding !== 'string') { - throw new TypeError('encoding must be a string') - } - if (typeof encoding === 'string' && !Buffer.isEncoding(encoding)) { - throw new TypeError('Unknown encoding: ' + encoding) - } - if (val.length === 1) { - var code = val.charCodeAt(0) - if ((encoding === 'utf8' && code < 128) || - encoding === 'latin1') { - // Fast path: If `val` fits into a single byte, use that numeric value. - val = code - } - } - } else if (typeof val === 'number') { - val = val & 255 - } - - // Invalid ranges are not set to a default, so can range check early. - if (start < 0 || this.length < start || this.length < end) { - throw new RangeError('Out of range index') - } - - if (end <= start) { - return this - } - - start = start >>> 0 - end = end === undefined ? this.length : end >>> 0 - - if (!val) val = 0 - - var i - if (typeof val === 'number') { - for (i = start; i < end; ++i) { - this[i] = val - } - } else { - var bytes = Buffer.isBuffer(val) - ? val - : Buffer.from(val, encoding) - var len = bytes.length - if (len === 0) { - throw new TypeError('The value "' + val + - '" is invalid for argument "value"') - } - for (i = 0; i < end - start; ++i) { - this[i + start] = bytes[i % len] - } - } - - return this -} - -// HELPER FUNCTIONS -// ================ - -var INVALID_BASE64_RE = /[^+/0-9A-Za-z-_]/g - -function base64clean (str) { - // Node takes equal signs as end of the Base64 encoding - str = str.split('=')[0] - // Node strips out invalid characters like \n and \t from the string, base64-js does not - str = str.trim().replace(INVALID_BASE64_RE, '') - // Node converts strings with length < 2 to '' - if (str.length < 2) return '' - // Node allows for non-padded base64 strings (missing trailing ===), base64-js does not - while (str.length % 4 !== 0) { - str = str + '=' - } - return str -} - -function toHex (n) { - if (n < 16) return '0' + n.toString(16) - return n.toString(16) -} - -function utf8ToBytes (string, units) { - units = units || Infinity - var codePoint - var length = string.length - var leadSurrogate = null - var bytes = [] - - for (var i = 0; i < length; ++i) { - codePoint = string.charCodeAt(i) - - // is surrogate component - if (codePoint > 0xD7FF && codePoint < 0xE000) { - // last char was a lead - if (!leadSurrogate) { - // no lead yet - if (codePoint > 0xDBFF) { - // unexpected trail - if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD) - continue - } else if (i + 1 === length) { - // unpaired lead - if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD) - continue - } - - // valid lead - leadSurrogate = codePoint - - continue - } - - // 2 leads in a row - if (codePoint < 0xDC00) { - if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD) - leadSurrogate = codePoint - continue - } - - // valid surrogate pair - codePoint = (leadSurrogate - 0xD800 << 10 | codePoint - 0xDC00) + 0x10000 - } else if (leadSurrogate) { - // valid bmp char, but last char was a lead - if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD) - } - - leadSurrogate = null - - // encode utf8 - if (codePoint < 0x80) { - if ((units -= 1) < 0) break - bytes.push(codePoint) - } else if (codePoint < 0x800) { - if ((units -= 2) < 0) break - bytes.push( - codePoint >> 0x6 | 0xC0, - codePoint & 0x3F | 0x80 - ) - } else if (codePoint < 0x10000) { - if ((units -= 3) < 0) break - bytes.push( - codePoint >> 0xC | 0xE0, - codePoint >> 0x6 & 0x3F | 0x80, - codePoint & 0x3F | 0x80 - ) - } else if (codePoint < 0x110000) { - if ((units -= 4) < 0) break - bytes.push( - codePoint >> 0x12 | 0xF0, - codePoint >> 0xC & 0x3F | 0x80, - codePoint >> 0x6 & 0x3F | 0x80, - codePoint & 0x3F | 0x80 - ) - } else { - throw new Error('Invalid code point') - } - } - - return bytes -} - -function asciiToBytes (str) { - var byteArray = [] - for (var i = 0; i < str.length; ++i) { - // Node's code seems to be doing this and not & 0x7F.. - byteArray.push(str.charCodeAt(i) & 0xFF) - } - return byteArray -} - -function utf16leToBytes (str, units) { - var c, hi, lo - var byteArray = [] - for (var i = 0; i < str.length; ++i) { - if ((units -= 2) < 0) break - - c = str.charCodeAt(i) - hi = c >> 8 - lo = c % 256 - byteArray.push(lo) - byteArray.push(hi) - } - - return byteArray -} - -function base64ToBytes (str) { - return base64.toByteArray(base64clean(str)) -} - -function blitBuffer (src, dst, offset, length) { - for (var i = 0; i < length; ++i) { - if ((i + offset >= dst.length) || (i >= src.length)) break - dst[i + offset] = src[i] - } - return i -} - -// ArrayBuffer or Uint8Array objects from other contexts (i.e. iframes) do not pass -// the `instanceof` check but they should be treated as of that type. -// See: https://github.com/feross/buffer/issues/166 -function isInstance (obj, type) { - return obj instanceof type || - (obj != null && obj.constructor != null && obj.constructor.name != null && - obj.constructor.name === type.name) -} -function numberIsNaN (obj) { - // For IE11 support - return obj !== obj // eslint-disable-line no-self-compare -} - -}).call(this,require("buffer").Buffer) -},{"base64-js":1,"buffer":3,"ieee754":6}],4:[function(require,module,exports){ -(function (Buffer){ -// Copyright Joyent, Inc. and other Node contributors. -// -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and associated documentation files (the -// "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, -// distribute, sublicense, and/or sell copies of the Software, and to permit -// persons to whom the Software is furnished to do so, subject to the -// following conditions: -// -// The above copyright notice and this permission notice shall be included -// in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN -// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE -// USE OR OTHER DEALINGS IN THE SOFTWARE. - -// NOTE: These type checking functions intentionally don't use `instanceof` -// because it is fragile and can be easily faked with `Object.create()`. - -function isArray(arg) { - if (Array.isArray) { - return Array.isArray(arg); - } - return objectToString(arg) === '[object Array]'; -} -exports.isArray = isArray; - -function isBoolean(arg) { - return typeof arg === 'boolean'; -} -exports.isBoolean = isBoolean; - -function isNull(arg) { - return arg === null; -} -exports.isNull = isNull; - -function isNullOrUndefined(arg) { - return arg == null; -} -exports.isNullOrUndefined = isNullOrUndefined; - -function isNumber(arg) { - return typeof arg === 'number'; -} -exports.isNumber = isNumber; - -function isString(arg) { - return typeof arg === 'string'; -} -exports.isString = isString; - -function isSymbol(arg) { - return typeof arg === 'symbol'; -} -exports.isSymbol = isSymbol; - -function isUndefined(arg) { - return arg === void 0; -} -exports.isUndefined = isUndefined; - -function isRegExp(re) { - return objectToString(re) === '[object RegExp]'; -} -exports.isRegExp = isRegExp; - -function isObject(arg) { - return typeof arg === 'object' && arg !== null; -} -exports.isObject = isObject; - -function isDate(d) { - return objectToString(d) === '[object Date]'; -} -exports.isDate = isDate; - -function isError(e) { - return (objectToString(e) === '[object Error]' || e instanceof Error); -} -exports.isError = isError; - -function isFunction(arg) { - return typeof arg === 'function'; -} -exports.isFunction = isFunction; - -function isPrimitive(arg) { - return arg === null || - typeof arg === 'boolean' || - typeof arg === 'number' || - typeof arg === 'string' || - typeof arg === 'symbol' || // ES6 symbol - typeof arg === 'undefined'; -} -exports.isPrimitive = isPrimitive; - -exports.isBuffer = Buffer.isBuffer; - -function objectToString(o) { - return Object.prototype.toString.call(o); -} - -}).call(this,{"isBuffer":require("../../is-buffer/index.js")}) -},{"../../is-buffer/index.js":8}],5:[function(require,module,exports){ -// Copyright Joyent, Inc. and other Node contributors. -// -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and associated documentation files (the -// "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, -// distribute, sublicense, and/or sell copies of the Software, and to permit -// persons to whom the Software is furnished to do so, subject to the -// following conditions: -// -// The above copyright notice and this permission notice shall be included -// in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN -// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE -// USE OR OTHER DEALINGS IN THE SOFTWARE. - -var objectCreate = Object.create || objectCreatePolyfill -var objectKeys = Object.keys || objectKeysPolyfill -var bind = Function.prototype.bind || functionBindPolyfill - -function EventEmitter() { - if (!this._events || !Object.prototype.hasOwnProperty.call(this, '_events')) { - this._events = objectCreate(null); - this._eventsCount = 0; - } - - this._maxListeners = this._maxListeners || undefined; -} -module.exports = EventEmitter; - -// Backwards-compat with node 0.10.x -EventEmitter.EventEmitter = EventEmitter; - -EventEmitter.prototype._events = undefined; -EventEmitter.prototype._maxListeners = undefined; - -// By default EventEmitters will print a warning if more than 10 listeners are -// added to it. This is a useful default which helps finding memory leaks. -var defaultMaxListeners = 10; - -var hasDefineProperty; -try { - var o = {}; - if (Object.defineProperty) Object.defineProperty(o, 'x', { value: 0 }); - hasDefineProperty = o.x === 0; -} catch (err) { hasDefineProperty = false } -if (hasDefineProperty) { - Object.defineProperty(EventEmitter, 'defaultMaxListeners', { - enumerable: true, - get: function() { - return defaultMaxListeners; - }, - set: function(arg) { - // check whether the input is a positive number (whose value is zero or - // greater and not a NaN). - if (typeof arg !== 'number' || arg < 0 || arg !== arg) - throw new TypeError('"defaultMaxListeners" must be a positive number'); - defaultMaxListeners = arg; - } - }); -} else { - EventEmitter.defaultMaxListeners = defaultMaxListeners; -} - -// Obviously not all Emitters should be limited to 10. This function allows -// that to be increased. Set to zero for unlimited. -EventEmitter.prototype.setMaxListeners = function setMaxListeners(n) { - if (typeof n !== 'number' || n < 0 || isNaN(n)) - throw new TypeError('"n" argument must be a positive number'); - this._maxListeners = n; - return this; -}; - -function $getMaxListeners(that) { - if (that._maxListeners === undefined) - return EventEmitter.defaultMaxListeners; - return that._maxListeners; -} - -EventEmitter.prototype.getMaxListeners = function getMaxListeners() { - return $getMaxListeners(this); -}; - -// These standalone emit* functions are used to optimize calling of event -// handlers for fast cases because emit() itself often has a variable number of -// arguments and can be deoptimized because of that. These functions always have -// the same number of arguments and thus do not get deoptimized, so the code -// inside them can execute faster. -function emitNone(handler, isFn, self) { - if (isFn) - handler.call(self); - else { - var len = handler.length; - var listeners = arrayClone(handler, len); - for (var i = 0; i < len; ++i) - listeners[i].call(self); - } -} -function emitOne(handler, isFn, self, arg1) { - if (isFn) - handler.call(self, arg1); - else { - var len = handler.length; - var listeners = arrayClone(handler, len); - for (var i = 0; i < len; ++i) - listeners[i].call(self, arg1); - } -} -function emitTwo(handler, isFn, self, arg1, arg2) { - if (isFn) - handler.call(self, arg1, arg2); - else { - var len = handler.length; - var listeners = arrayClone(handler, len); - for (var i = 0; i < len; ++i) - listeners[i].call(self, arg1, arg2); - } -} -function emitThree(handler, isFn, self, arg1, arg2, arg3) { - if (isFn) - handler.call(self, arg1, arg2, arg3); - else { - var len = handler.length; - var listeners = arrayClone(handler, len); - for (var i = 0; i < len; ++i) - listeners[i].call(self, arg1, arg2, arg3); - } -} - -function emitMany(handler, isFn, self, args) { - if (isFn) - handler.apply(self, args); - else { - var len = handler.length; - var listeners = arrayClone(handler, len); - for (var i = 0; i < len; ++i) - listeners[i].apply(self, args); - } -} - -EventEmitter.prototype.emit = function emit(type) { - var er, handler, len, args, i, events; - var doError = (type === 'error'); - - events = this._events; - if (events) - doError = (doError && events.error == null); - else if (!doError) - return false; - - // If there is no 'error' event listener then throw. - if (doError) { - if (arguments.length > 1) - er = arguments[1]; - if (er instanceof Error) { - throw er; // Unhandled 'error' event - } else { - // At least give some kind of context to the user - var err = new Error('Unhandled "error" event. (' + er + ')'); - err.context = er; - throw err; - } - return false; - } - - handler = events[type]; - - if (!handler) - return false; - - var isFn = typeof handler === 'function'; - len = arguments.length; - switch (len) { - // fast cases - case 1: - emitNone(handler, isFn, this); - break; - case 2: - emitOne(handler, isFn, this, arguments[1]); - break; - case 3: - emitTwo(handler, isFn, this, arguments[1], arguments[2]); - break; - case 4: - emitThree(handler, isFn, this, arguments[1], arguments[2], arguments[3]); - break; - // slower - default: - args = new Array(len - 1); - for (i = 1; i < len; i++) - args[i - 1] = arguments[i]; - emitMany(handler, isFn, this, args); - } - - return true; -}; - -function _addListener(target, type, listener, prepend) { - var m; - var events; - var existing; - - if (typeof listener !== 'function') - throw new TypeError('"listener" argument must be a function'); - - events = target._events; - if (!events) { - events = target._events = objectCreate(null); - target._eventsCount = 0; - } else { - // To avoid recursion in the case that type === "newListener"! Before - // adding it to the listeners, first emit "newListener". - if (events.newListener) { - target.emit('newListener', type, - listener.listener ? listener.listener : listener); - - // Re-assign `events` because a newListener handler could have caused the - // this._events to be assigned to a new object - events = target._events; - } - existing = events[type]; - } - - if (!existing) { - // Optimize the case of one listener. Don't need the extra array object. - existing = events[type] = listener; - ++target._eventsCount; - } else { - if (typeof existing === 'function') { - // Adding the second element, need to change to array. - existing = events[type] = - prepend ? [listener, existing] : [existing, listener]; - } else { - // If we've already got an array, just append. - if (prepend) { - existing.unshift(listener); - } else { - existing.push(listener); - } - } - - // Check for listener leak - if (!existing.warned) { - m = $getMaxListeners(target); - if (m && m > 0 && existing.length > m) { - existing.warned = true; - var w = new Error('Possible EventEmitter memory leak detected. ' + - existing.length + ' "' + String(type) + '" listeners ' + - 'added. Use emitter.setMaxListeners() to ' + - 'increase limit.'); - w.name = 'MaxListenersExceededWarning'; - w.emitter = target; - w.type = type; - w.count = existing.length; - if (typeof console === 'object' && console.warn) { - console.warn('%s: %s', w.name, w.message); - } - } - } - } - - return target; -} - -EventEmitter.prototype.addListener = function addListener(type, listener) { - return _addListener(this, type, listener, false); -}; - -EventEmitter.prototype.on = EventEmitter.prototype.addListener; - -EventEmitter.prototype.prependListener = - function prependListener(type, listener) { - return _addListener(this, type, listener, true); - }; - -function onceWrapper() { - if (!this.fired) { - this.target.removeListener(this.type, this.wrapFn); - this.fired = true; - switch (arguments.length) { - case 0: - return this.listener.call(this.target); - case 1: - return this.listener.call(this.target, arguments[0]); - case 2: - return this.listener.call(this.target, arguments[0], arguments[1]); - case 3: - return this.listener.call(this.target, arguments[0], arguments[1], - arguments[2]); - default: - var args = new Array(arguments.length); - for (var i = 0; i < args.length; ++i) - args[i] = arguments[i]; - this.listener.apply(this.target, args); - } - } -} - -function _onceWrap(target, type, listener) { - var state = { fired: false, wrapFn: undefined, target: target, type: type, listener: listener }; - var wrapped = bind.call(onceWrapper, state); - wrapped.listener = listener; - state.wrapFn = wrapped; - return wrapped; -} - -EventEmitter.prototype.once = function once(type, listener) { - if (typeof listener !== 'function') - throw new TypeError('"listener" argument must be a function'); - this.on(type, _onceWrap(this, type, listener)); - return this; -}; - -EventEmitter.prototype.prependOnceListener = - function prependOnceListener(type, listener) { - if (typeof listener !== 'function') - throw new TypeError('"listener" argument must be a function'); - this.prependListener(type, _onceWrap(this, type, listener)); - return this; - }; - -// Emits a 'removeListener' event if and only if the listener was removed. -EventEmitter.prototype.removeListener = - function removeListener(type, listener) { - var list, events, position, i, originalListener; - - if (typeof listener !== 'function') - throw new TypeError('"listener" argument must be a function'); - - events = this._events; - if (!events) - return this; - - list = events[type]; - if (!list) - return this; - - if (list === listener || list.listener === listener) { - if (--this._eventsCount === 0) - this._events = objectCreate(null); - else { - delete events[type]; - if (events.removeListener) - this.emit('removeListener', type, list.listener || listener); - } - } else if (typeof list !== 'function') { - position = -1; - - for (i = list.length - 1; i >= 0; i--) { - if (list[i] === listener || list[i].listener === listener) { - originalListener = list[i].listener; - position = i; - break; - } - } - - if (position < 0) - return this; - - if (position === 0) - list.shift(); - else - spliceOne(list, position); - - if (list.length === 1) - events[type] = list[0]; - - if (events.removeListener) - this.emit('removeListener', type, originalListener || listener); - } - - return this; - }; - -EventEmitter.prototype.removeAllListeners = - function removeAllListeners(type) { - var listeners, events, i; - - events = this._events; - if (!events) - return this; - - // not listening for removeListener, no need to emit - if (!events.removeListener) { - if (arguments.length === 0) { - this._events = objectCreate(null); - this._eventsCount = 0; - } else if (events[type]) { - if (--this._eventsCount === 0) - this._events = objectCreate(null); - else - delete events[type]; - } - return this; - } - - // emit removeListener for all listeners on all events - if (arguments.length === 0) { - var keys = objectKeys(events); - var key; - for (i = 0; i < keys.length; ++i) { - key = keys[i]; - if (key === 'removeListener') continue; - this.removeAllListeners(key); - } - this.removeAllListeners('removeListener'); - this._events = objectCreate(null); - this._eventsCount = 0; - return this; - } - - listeners = events[type]; - - if (typeof listeners === 'function') { - this.removeListener(type, listeners); - } else if (listeners) { - // LIFO order - for (i = listeners.length - 1; i >= 0; i--) { - this.removeListener(type, listeners[i]); - } - } - - return this; - }; - -function _listeners(target, type, unwrap) { - var events = target._events; - - if (!events) - return []; - - var evlistener = events[type]; - if (!evlistener) - return []; - - if (typeof evlistener === 'function') - return unwrap ? [evlistener.listener || evlistener] : [evlistener]; - - return unwrap ? unwrapListeners(evlistener) : arrayClone(evlistener, evlistener.length); -} - -EventEmitter.prototype.listeners = function listeners(type) { - return _listeners(this, type, true); -}; - -EventEmitter.prototype.rawListeners = function rawListeners(type) { - return _listeners(this, type, false); -}; - -EventEmitter.listenerCount = function(emitter, type) { - if (typeof emitter.listenerCount === 'function') { - return emitter.listenerCount(type); - } else { - return listenerCount.call(emitter, type); - } -}; - -EventEmitter.prototype.listenerCount = listenerCount; -function listenerCount(type) { - var events = this._events; - - if (events) { - var evlistener = events[type]; - - if (typeof evlistener === 'function') { - return 1; - } else if (evlistener) { - return evlistener.length; - } - } - - return 0; -} - -EventEmitter.prototype.eventNames = function eventNames() { - return this._eventsCount > 0 ? Reflect.ownKeys(this._events) : []; -}; - -// About 1.5x faster than the two-arg version of Array#splice(). -function spliceOne(list, index) { - for (var i = index, k = i + 1, n = list.length; k < n; i += 1, k += 1) - list[i] = list[k]; - list.pop(); -} - -function arrayClone(arr, n) { - var copy = new Array(n); - for (var i = 0; i < n; ++i) - copy[i] = arr[i]; - return copy; -} - -function unwrapListeners(arr) { - var ret = new Array(arr.length); - for (var i = 0; i < ret.length; ++i) { - ret[i] = arr[i].listener || arr[i]; - } - return ret; -} - -function objectCreatePolyfill(proto) { - var F = function() {}; - F.prototype = proto; - return new F; -} -function objectKeysPolyfill(obj) { - var keys = []; - for (var k in obj) if (Object.prototype.hasOwnProperty.call(obj, k)) { - keys.push(k); - } - return k; -} -function functionBindPolyfill(context) { - var fn = this; - return function () { - return fn.apply(context, arguments); - }; -} - -},{}],6:[function(require,module,exports){ -exports.read = function (buffer, offset, isLE, mLen, nBytes) { - var e, m - var eLen = (nBytes * 8) - mLen - 1 - var eMax = (1 << eLen) - 1 - var eBias = eMax >> 1 - var nBits = -7 - var i = isLE ? (nBytes - 1) : 0 - var d = isLE ? -1 : 1 - var s = buffer[offset + i] - - i += d - - e = s & ((1 << (-nBits)) - 1) - s >>= (-nBits) - nBits += eLen - for (; nBits > 0; e = (e * 256) + buffer[offset + i], i += d, nBits -= 8) {} - - m = e & ((1 << (-nBits)) - 1) - e >>= (-nBits) - nBits += mLen - for (; nBits > 0; m = (m * 256) + buffer[offset + i], i += d, nBits -= 8) {} - - if (e === 0) { - e = 1 - eBias - } else if (e === eMax) { - return m ? NaN : ((s ? -1 : 1) * Infinity) - } else { - m = m + Math.pow(2, mLen) - e = e - eBias - } - return (s ? -1 : 1) * m * Math.pow(2, e - mLen) -} - -exports.write = function (buffer, value, offset, isLE, mLen, nBytes) { - var e, m, c - var eLen = (nBytes * 8) - mLen - 1 - var eMax = (1 << eLen) - 1 - var eBias = eMax >> 1 - var rt = (mLen === 23 ? Math.pow(2, -24) - Math.pow(2, -77) : 0) - var i = isLE ? 0 : (nBytes - 1) - var d = isLE ? 1 : -1 - var s = value < 0 || (value === 0 && 1 / value < 0) ? 1 : 0 - - value = Math.abs(value) - - if (isNaN(value) || value === Infinity) { - m = isNaN(value) ? 1 : 0 - e = eMax - } else { - e = Math.floor(Math.log(value) / Math.LN2) - if (value * (c = Math.pow(2, -e)) < 1) { - e-- - c *= 2 - } - if (e + eBias >= 1) { - value += rt / c - } else { - value += rt * Math.pow(2, 1 - eBias) - } - if (value * c >= 2) { - e++ - c /= 2 - } - - if (e + eBias >= eMax) { - m = 0 - e = eMax - } else if (e + eBias >= 1) { - m = ((value * c) - 1) * Math.pow(2, mLen) - e = e + eBias - } else { - m = value * Math.pow(2, eBias - 1) * Math.pow(2, mLen) - e = 0 - } - } - - for (; mLen >= 8; buffer[offset + i] = m & 0xff, i += d, m /= 256, mLen -= 8) {} - - e = (e << mLen) | m - eLen += mLen - for (; eLen > 0; buffer[offset + i] = e & 0xff, i += d, e /= 256, eLen -= 8) {} - - buffer[offset + i - d] |= s * 128 -} - -},{}],7:[function(require,module,exports){ -if (typeof Object.create === 'function') { - // implementation from standard node.js 'util' module - module.exports = function inherits(ctor, superCtor) { - if (superCtor) { - ctor.super_ = superCtor - ctor.prototype = Object.create(superCtor.prototype, { - constructor: { - value: ctor, - enumerable: false, - writable: true, - configurable: true - } - }) - } - }; -} else { - // old school shim for old browsers - module.exports = function inherits(ctor, superCtor) { - if (superCtor) { - ctor.super_ = superCtor - var TempCtor = function () {} - TempCtor.prototype = superCtor.prototype - ctor.prototype = new TempCtor() - ctor.prototype.constructor = ctor - } - } -} - -},{}],8:[function(require,module,exports){ -/*! - * Determine if an object is a Buffer - * - * @author Feross Aboukhadijeh - * @license MIT - */ - -// The _isBuffer check is for Safari 5-7 support, because it's missing -// Object.prototype.constructor. Remove this eventually -module.exports = function (obj) { - return obj != null && (isBuffer(obj) || isSlowBuffer(obj) || !!obj._isBuffer) -} - -function isBuffer (obj) { - return !!obj.constructor && typeof obj.constructor.isBuffer === 'function' && obj.constructor.isBuffer(obj) -} - -// For Node v0.10 support. Remove this eventually. -function isSlowBuffer (obj) { - return typeof obj.readFloatLE === 'function' && typeof obj.slice === 'function' && isBuffer(obj.slice(0, 0)) -} - -},{}],9:[function(require,module,exports){ -var toString = {}.toString; - -module.exports = Array.isArray || function (arr) { - return toString.call(arr) == '[object Array]'; -}; - -},{}],10:[function(require,module,exports){ -(function (process){ -'use strict'; - -if (typeof process === 'undefined' || - !process.version || - process.version.indexOf('v0.') === 0 || - process.version.indexOf('v1.') === 0 && process.version.indexOf('v1.8.') !== 0) { - module.exports = { nextTick: nextTick }; -} else { - module.exports = process -} - -function nextTick(fn, arg1, arg2, arg3) { - if (typeof fn !== 'function') { - throw new TypeError('"callback" argument must be a function'); - } - var len = arguments.length; - var args, i; - switch (len) { - case 0: - case 1: - return process.nextTick(fn); - case 2: - return process.nextTick(function afterTickOne() { - fn.call(null, arg1); - }); - case 3: - return process.nextTick(function afterTickTwo() { - fn.call(null, arg1, arg2); - }); - case 4: - return process.nextTick(function afterTickThree() { - fn.call(null, arg1, arg2, arg3); - }); - default: - args = new Array(len - 1); - i = 0; - while (i < args.length) { - args[i++] = arguments[i]; - } - return process.nextTick(function afterTick() { - fn.apply(null, args); - }); - } -} - - -}).call(this,require('_process')) -},{"_process":11}],11:[function(require,module,exports){ -// shim for using process in browser -var process = module.exports = {}; - -// cached from whatever global is present so that test runners that stub it -// don't break things. But we need to wrap it in a try catch in case it is -// wrapped in strict mode code which doesn't define any globals. It's inside a -// function because try/catches deoptimize in certain engines. - -var cachedSetTimeout; -var cachedClearTimeout; - -function defaultSetTimout() { - throw new Error('setTimeout has not been defined'); -} -function defaultClearTimeout () { - throw new Error('clearTimeout has not been defined'); -} -(function () { - try { - if (typeof setTimeout === 'function') { - cachedSetTimeout = setTimeout; - } else { - cachedSetTimeout = defaultSetTimout; - } - } catch (e) { - cachedSetTimeout = defaultSetTimout; - } - try { - if (typeof clearTimeout === 'function') { - cachedClearTimeout = clearTimeout; - } else { - cachedClearTimeout = defaultClearTimeout; - } - } catch (e) { - cachedClearTimeout = defaultClearTimeout; - } -} ()) -function runTimeout(fun) { - if (cachedSetTimeout === setTimeout) { - //normal enviroments in sane situations - return setTimeout(fun, 0); - } - // if setTimeout wasn't available but was latter defined - if ((cachedSetTimeout === defaultSetTimout || !cachedSetTimeout) && setTimeout) { - cachedSetTimeout = setTimeout; - return setTimeout(fun, 0); - } - try { - // when when somebody has screwed with setTimeout but no I.E. maddness - return cachedSetTimeout(fun, 0); - } catch(e){ - try { - // When we are in I.E. but the script has been evaled so I.E. doesn't trust the global object when called normally - return cachedSetTimeout.call(null, fun, 0); - } catch(e){ - // same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error - return cachedSetTimeout.call(this, fun, 0); - } - } - - -} -function runClearTimeout(marker) { - if (cachedClearTimeout === clearTimeout) { - //normal enviroments in sane situations - return clearTimeout(marker); - } - // if clearTimeout wasn't available but was latter defined - if ((cachedClearTimeout === defaultClearTimeout || !cachedClearTimeout) && clearTimeout) { - cachedClearTimeout = clearTimeout; - return clearTimeout(marker); - } - try { - // when when somebody has screwed with setTimeout but no I.E. maddness - return cachedClearTimeout(marker); - } catch (e){ - try { - // When we are in I.E. but the script has been evaled so I.E. doesn't trust the global object when called normally - return cachedClearTimeout.call(null, marker); - } catch (e){ - // same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error. - // Some versions of I.E. have different rules for clearTimeout vs setTimeout - return cachedClearTimeout.call(this, marker); - } - } - - - -} -var queue = []; -var draining = false; -var currentQueue; -var queueIndex = -1; - -function cleanUpNextTick() { - if (!draining || !currentQueue) { - return; - } - draining = false; - if (currentQueue.length) { - queue = currentQueue.concat(queue); - } else { - queueIndex = -1; - } - if (queue.length) { - drainQueue(); - } -} - -function drainQueue() { - if (draining) { - return; - } - var timeout = runTimeout(cleanUpNextTick); - draining = true; - - var len = queue.length; - while(len) { - currentQueue = queue; - queue = []; - while (++queueIndex < len) { - if (currentQueue) { - currentQueue[queueIndex].run(); - } - } - queueIndex = -1; - len = queue.length; - } - currentQueue = null; - draining = false; - runClearTimeout(timeout); -} - -process.nextTick = function (fun) { - var args = new Array(arguments.length - 1); - if (arguments.length > 1) { - for (var i = 1; i < arguments.length; i++) { - args[i - 1] = arguments[i]; - } - } - queue.push(new Item(fun, args)); - if (queue.length === 1 && !draining) { - runTimeout(drainQueue); - } -}; - -// v8 likes predictible objects -function Item(fun, array) { - this.fun = fun; - this.array = array; -} -Item.prototype.run = function () { - this.fun.apply(null, this.array); -}; -process.title = 'browser'; -process.browser = true; -process.env = {}; -process.argv = []; -process.version = ''; // empty string to avoid regexp issues -process.versions = {}; - -function noop() {} - -process.on = noop; -process.addListener = noop; -process.once = noop; -process.off = noop; -process.removeListener = noop; -process.removeAllListeners = noop; -process.emit = noop; -process.prependListener = noop; -process.prependOnceListener = noop; - -process.listeners = function (name) { return [] } - -process.binding = function (name) { - throw new Error('process.binding is not supported'); -}; - -process.cwd = function () { return '/' }; -process.chdir = function (dir) { - throw new Error('process.chdir is not supported'); -}; -process.umask = function() { return 0; }; - -},{}],12:[function(require,module,exports){ -(function (global){ -/*! https://mths.be/punycode v1.4.1 by @mathias */ -;(function(root) { - - /** Detect free variables */ - var freeExports = typeof exports == 'object' && exports && - !exports.nodeType && exports; - var freeModule = typeof module == 'object' && module && - !module.nodeType && module; - var freeGlobal = typeof global == 'object' && global; - if ( - freeGlobal.global === freeGlobal || - freeGlobal.window === freeGlobal || - freeGlobal.self === freeGlobal - ) { - root = freeGlobal; - } - - /** - * The `punycode` object. - * @name punycode - * @type Object - */ - var punycode, - - /** Highest positive signed 32-bit float value */ - maxInt = 2147483647, // aka. 0x7FFFFFFF or 2^31-1 - - /** Bootstring parameters */ - base = 36, - tMin = 1, - tMax = 26, - skew = 38, - damp = 700, - initialBias = 72, - initialN = 128, // 0x80 - delimiter = '-', // '\x2D' - - /** Regular expressions */ - regexPunycode = /^xn--/, - regexNonASCII = /[^\x20-\x7E]/, // unprintable ASCII chars + non-ASCII chars - regexSeparators = /[\x2E\u3002\uFF0E\uFF61]/g, // RFC 3490 separators - - /** Error messages */ - errors = { - 'overflow': 'Overflow: input needs wider integers to process', - 'not-basic': 'Illegal input >= 0x80 (not a basic code point)', - 'invalid-input': 'Invalid input' - }, - - /** Convenience shortcuts */ - baseMinusTMin = base - tMin, - floor = Math.floor, - stringFromCharCode = String.fromCharCode, - - /** Temporary variable */ - key; - - /*--------------------------------------------------------------------------*/ - - /** - * A generic error utility function. - * @private - * @param {String} type The error type. - * @returns {Error} Throws a `RangeError` with the applicable error message. - */ - function error(type) { - throw new RangeError(errors[type]); - } - - /** - * A generic `Array#map` utility function. - * @private - * @param {Array} array The array to iterate over. - * @param {Function} callback The function that gets called for every array - * item. - * @returns {Array} A new array of values returned by the callback function. - */ - function map(array, fn) { - var length = array.length; - var result = []; - while (length--) { - result[length] = fn(array[length]); - } - return result; - } - - /** - * A simple `Array#map`-like wrapper to work with domain name strings or email - * addresses. - * @private - * @param {String} domain The domain name or email address. - * @param {Function} callback The function that gets called for every - * character. - * @returns {Array} A new string of characters returned by the callback - * function. - */ - function mapDomain(string, fn) { - var parts = string.split('@'); - var result = ''; - if (parts.length > 1) { - // In email addresses, only the domain name should be punycoded. Leave - // the local part (i.e. everything up to `@`) intact. - result = parts[0] + '@'; - string = parts[1]; - } - // Avoid `split(regex)` for IE8 compatibility. See #17. - string = string.replace(regexSeparators, '\x2E'); - var labels = string.split('.'); - var encoded = map(labels, fn).join('.'); - return result + encoded; - } - - /** - * Creates an array containing the numeric code points of each Unicode - * character in the string. While JavaScript uses UCS-2 internally, - * this function will convert a pair of surrogate halves (each of which - * UCS-2 exposes as separate characters) into a single code point, - * matching UTF-16. - * @see `punycode.ucs2.encode` - * @see - * @memberOf punycode.ucs2 - * @name decode - * @param {String} string The Unicode input string (UCS-2). - * @returns {Array} The new array of code points. - */ - function ucs2decode(string) { - var output = [], - counter = 0, - length = string.length, - value, - extra; - while (counter < length) { - value = string.charCodeAt(counter++); - if (value >= 0xD800 && value <= 0xDBFF && counter < length) { - // high surrogate, and there is a next character - extra = string.charCodeAt(counter++); - if ((extra & 0xFC00) == 0xDC00) { // low surrogate - output.push(((value & 0x3FF) << 10) + (extra & 0x3FF) + 0x10000); - } else { - // unmatched surrogate; only append this code unit, in case the next - // code unit is the high surrogate of a surrogate pair - output.push(value); - counter--; - } - } else { - output.push(value); - } - } - return output; - } - - /** - * Creates a string based on an array of numeric code points. - * @see `punycode.ucs2.decode` - * @memberOf punycode.ucs2 - * @name encode - * @param {Array} codePoints The array of numeric code points. - * @returns {String} The new Unicode string (UCS-2). - */ - function ucs2encode(array) { - return map(array, function(value) { - var output = ''; - if (value > 0xFFFF) { - value -= 0x10000; - output += stringFromCharCode(value >>> 10 & 0x3FF | 0xD800); - value = 0xDC00 | value & 0x3FF; - } - output += stringFromCharCode(value); - return output; - }).join(''); - } - - /** - * Converts a basic code point into a digit/integer. - * @see `digitToBasic()` - * @private - * @param {Number} codePoint The basic numeric code point value. - * @returns {Number} The numeric value of a basic code point (for use in - * representing integers) in the range `0` to `base - 1`, or `base` if - * the code point does not represent a value. - */ - function basicToDigit(codePoint) { - if (codePoint - 48 < 10) { - return codePoint - 22; - } - if (codePoint - 65 < 26) { - return codePoint - 65; - } - if (codePoint - 97 < 26) { - return codePoint - 97; - } - return base; - } - - /** - * Converts a digit/integer into a basic code point. - * @see `basicToDigit()` - * @private - * @param {Number} digit The numeric value of a basic code point. - * @returns {Number} The basic code point whose value (when used for - * representing integers) is `digit`, which needs to be in the range - * `0` to `base - 1`. If `flag` is non-zero, the uppercase form is - * used; else, the lowercase form is used. The behavior is undefined - * if `flag` is non-zero and `digit` has no uppercase form. - */ - function digitToBasic(digit, flag) { - // 0..25 map to ASCII a..z or A..Z - // 26..35 map to ASCII 0..9 - return digit + 22 + 75 * (digit < 26) - ((flag != 0) << 5); - } - - /** - * Bias adaptation function as per section 3.4 of RFC 3492. - * https://tools.ietf.org/html/rfc3492#section-3.4 - * @private - */ - function adapt(delta, numPoints, firstTime) { - var k = 0; - delta = firstTime ? floor(delta / damp) : delta >> 1; - delta += floor(delta / numPoints); - for (/* no initialization */; delta > baseMinusTMin * tMax >> 1; k += base) { - delta = floor(delta / baseMinusTMin); - } - return floor(k + (baseMinusTMin + 1) * delta / (delta + skew)); - } - - /** - * Converts a Punycode string of ASCII-only symbols to a string of Unicode - * symbols. - * @memberOf punycode - * @param {String} input The Punycode string of ASCII-only symbols. - * @returns {String} The resulting string of Unicode symbols. - */ - function decode(input) { - // Don't use UCS-2 - var output = [], - inputLength = input.length, - out, - i = 0, - n = initialN, - bias = initialBias, - basic, - j, - index, - oldi, - w, - k, - digit, - t, - /** Cached calculation results */ - baseMinusT; - - // Handle the basic code points: let `basic` be the number of input code - // points before the last delimiter, or `0` if there is none, then copy - // the first basic code points to the output. - - basic = input.lastIndexOf(delimiter); - if (basic < 0) { - basic = 0; - } - - for (j = 0; j < basic; ++j) { - // if it's not a basic code point - if (input.charCodeAt(j) >= 0x80) { - error('not-basic'); - } - output.push(input.charCodeAt(j)); - } - - // Main decoding loop: start just after the last delimiter if any basic code - // points were copied; start at the beginning otherwise. - - for (index = basic > 0 ? basic + 1 : 0; index < inputLength; /* no final expression */) { - - // `index` is the index of the next character to be consumed. - // Decode a generalized variable-length integer into `delta`, - // which gets added to `i`. The overflow checking is easier - // if we increase `i` as we go, then subtract off its starting - // value at the end to obtain `delta`. - for (oldi = i, w = 1, k = base; /* no condition */; k += base) { - - if (index >= inputLength) { - error('invalid-input'); - } - - digit = basicToDigit(input.charCodeAt(index++)); - - if (digit >= base || digit > floor((maxInt - i) / w)) { - error('overflow'); - } - - i += digit * w; - t = k <= bias ? tMin : (k >= bias + tMax ? tMax : k - bias); - - if (digit < t) { - break; - } - - baseMinusT = base - t; - if (w > floor(maxInt / baseMinusT)) { - error('overflow'); - } - - w *= baseMinusT; - - } - - out = output.length + 1; - bias = adapt(i - oldi, out, oldi == 0); - - // `i` was supposed to wrap around from `out` to `0`, - // incrementing `n` each time, so we'll fix that now: - if (floor(i / out) > maxInt - n) { - error('overflow'); - } - - n += floor(i / out); - i %= out; - - // Insert `n` at position `i` of the output - output.splice(i++, 0, n); - - } - - return ucs2encode(output); - } - - /** - * Converts a string of Unicode symbols (e.g. a domain name label) to a - * Punycode string of ASCII-only symbols. - * @memberOf punycode - * @param {String} input The string of Unicode symbols. - * @returns {String} The resulting Punycode string of ASCII-only symbols. - */ - function encode(input) { - var n, - delta, - handledCPCount, - basicLength, - bias, - j, - m, - q, - k, - t, - currentValue, - output = [], - /** `inputLength` will hold the number of code points in `input`. */ - inputLength, - /** Cached calculation results */ - handledCPCountPlusOne, - baseMinusT, - qMinusT; - - // Convert the input in UCS-2 to Unicode - input = ucs2decode(input); - - // Cache the length - inputLength = input.length; - - // Initialize the state - n = initialN; - delta = 0; - bias = initialBias; - - // Handle the basic code points - for (j = 0; j < inputLength; ++j) { - currentValue = input[j]; - if (currentValue < 0x80) { - output.push(stringFromCharCode(currentValue)); - } - } - - handledCPCount = basicLength = output.length; - - // `handledCPCount` is the number of code points that have been handled; - // `basicLength` is the number of basic code points. - - // Finish the basic string - if it is not empty - with a delimiter - if (basicLength) { - output.push(delimiter); - } - - // Main encoding loop: - while (handledCPCount < inputLength) { - - // All non-basic code points < n have been handled already. Find the next - // larger one: - for (m = maxInt, j = 0; j < inputLength; ++j) { - currentValue = input[j]; - if (currentValue >= n && currentValue < m) { - m = currentValue; - } - } - - // Increase `delta` enough to advance the decoder's state to , - // but guard against overflow - handledCPCountPlusOne = handledCPCount + 1; - if (m - n > floor((maxInt - delta) / handledCPCountPlusOne)) { - error('overflow'); - } - - delta += (m - n) * handledCPCountPlusOne; - n = m; - - for (j = 0; j < inputLength; ++j) { - currentValue = input[j]; - - if (currentValue < n && ++delta > maxInt) { - error('overflow'); - } - - if (currentValue == n) { - // Represent delta as a generalized variable-length integer - for (q = delta, k = base; /* no condition */; k += base) { - t = k <= bias ? tMin : (k >= bias + tMax ? tMax : k - bias); - if (q < t) { - break; - } - qMinusT = q - t; - baseMinusT = base - t; - output.push( - stringFromCharCode(digitToBasic(t + qMinusT % baseMinusT, 0)) - ); - q = floor(qMinusT / baseMinusT); - } - - output.push(stringFromCharCode(digitToBasic(q, 0))); - bias = adapt(delta, handledCPCountPlusOne, handledCPCount == basicLength); - delta = 0; - ++handledCPCount; - } - } - - ++delta; - ++n; - - } - return output.join(''); - } - - /** - * Converts a Punycode string representing a domain name or an email address - * to Unicode. Only the Punycoded parts of the input will be converted, i.e. - * it doesn't matter if you call it on a string that has already been - * converted to Unicode. - * @memberOf punycode - * @param {String} input The Punycoded domain name or email address to - * convert to Unicode. - * @returns {String} The Unicode representation of the given Punycode - * string. - */ - function toUnicode(input) { - return mapDomain(input, function(string) { - return regexPunycode.test(string) - ? decode(string.slice(4).toLowerCase()) - : string; - }); - } - - /** - * Converts a Unicode string representing a domain name or an email address to - * Punycode. Only the non-ASCII parts of the domain name will be converted, - * i.e. it doesn't matter if you call it with a domain that's already in - * ASCII. - * @memberOf punycode - * @param {String} input The domain name or email address to convert, as a - * Unicode string. - * @returns {String} The Punycode representation of the given domain name or - * email address. - */ - function toASCII(input) { - return mapDomain(input, function(string) { - return regexNonASCII.test(string) - ? 'xn--' + encode(string) - : string; - }); - } - - /*--------------------------------------------------------------------------*/ - - /** Define the public API */ - punycode = { - /** - * A string representing the current Punycode.js version number. - * @memberOf punycode - * @type String - */ - 'version': '1.4.1', - /** - * An object of methods to convert from JavaScript's internal character - * representation (UCS-2) to Unicode code points, and back. - * @see - * @memberOf punycode - * @type Object - */ - 'ucs2': { - 'decode': ucs2decode, - 'encode': ucs2encode - }, - 'decode': decode, - 'encode': encode, - 'toASCII': toASCII, - 'toUnicode': toUnicode - }; - - /** Expose `punycode` */ - // Some AMD build optimizers, like r.js, check for specific condition patterns - // like the following: - if ( - typeof define == 'function' && - typeof define.amd == 'object' && - define.amd - ) { - define('punycode', function() { - return punycode; - }); - } else if (freeExports && freeModule) { - if (module.exports == freeExports) { - // in Node.js, io.js, or RingoJS v0.8.0+ - freeModule.exports = punycode; - } else { - // in Narwhal or RingoJS v0.7.0- - for (key in punycode) { - punycode.hasOwnProperty(key) && (freeExports[key] = punycode[key]); - } - } - } else { - // in Rhino or a web browser - root.punycode = punycode; - } - -}(this)); - -}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) -},{}],13:[function(require,module,exports){ -// Copyright Joyent, Inc. and other Node contributors. -// -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and associated documentation files (the -// "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, -// distribute, sublicense, and/or sell copies of the Software, and to permit -// persons to whom the Software is furnished to do so, subject to the -// following conditions: -// -// The above copyright notice and this permission notice shall be included -// in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN -// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE -// USE OR OTHER DEALINGS IN THE SOFTWARE. - -'use strict'; - -// If obj.hasOwnProperty has been overridden, then calling -// obj.hasOwnProperty(prop) will break. -// See: https://github.com/joyent/node/issues/1707 -function hasOwnProperty(obj, prop) { - return Object.prototype.hasOwnProperty.call(obj, prop); -} - -module.exports = function(qs, sep, eq, options) { - sep = sep || '&'; - eq = eq || '='; - var obj = {}; - - if (typeof qs !== 'string' || qs.length === 0) { - return obj; - } - - var regexp = /\+/g; - qs = qs.split(sep); - - var maxKeys = 1000; - if (options && typeof options.maxKeys === 'number') { - maxKeys = options.maxKeys; - } - - var len = qs.length; - // maxKeys <= 0 means that we should not limit keys count - if (maxKeys > 0 && len > maxKeys) { - len = maxKeys; - } - - for (var i = 0; i < len; ++i) { - var x = qs[i].replace(regexp, '%20'), - idx = x.indexOf(eq), - kstr, vstr, k, v; - - if (idx >= 0) { - kstr = x.substr(0, idx); - vstr = x.substr(idx + 1); - } else { - kstr = x; - vstr = ''; - } - - k = decodeURIComponent(kstr); - v = decodeURIComponent(vstr); - - if (!hasOwnProperty(obj, k)) { - obj[k] = v; - } else if (isArray(obj[k])) { - obj[k].push(v); - } else { - obj[k] = [obj[k], v]; - } - } - - return obj; -}; - -var isArray = Array.isArray || function (xs) { - return Object.prototype.toString.call(xs) === '[object Array]'; -}; - -},{}],14:[function(require,module,exports){ -// Copyright Joyent, Inc. and other Node contributors. -// -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and associated documentation files (the -// "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, -// distribute, sublicense, and/or sell copies of the Software, and to permit -// persons to whom the Software is furnished to do so, subject to the -// following conditions: -// -// The above copyright notice and this permission notice shall be included -// in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN -// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE -// USE OR OTHER DEALINGS IN THE SOFTWARE. - -'use strict'; - -var stringifyPrimitive = function(v) { - switch (typeof v) { - case 'string': - return v; - - case 'boolean': - return v ? 'true' : 'false'; - - case 'number': - return isFinite(v) ? v : ''; - - default: - return ''; - } -}; - -module.exports = function(obj, sep, eq, name) { - sep = sep || '&'; - eq = eq || '='; - if (obj === null) { - obj = undefined; - } - - if (typeof obj === 'object') { - return map(objectKeys(obj), function(k) { - var ks = encodeURIComponent(stringifyPrimitive(k)) + eq; - if (isArray(obj[k])) { - return map(obj[k], function(v) { - return ks + encodeURIComponent(stringifyPrimitive(v)); - }).join(sep); - } else { - return ks + encodeURIComponent(stringifyPrimitive(obj[k])); - } - }).join(sep); - - } - - if (!name) return ''; - return encodeURIComponent(stringifyPrimitive(name)) + eq + - encodeURIComponent(stringifyPrimitive(obj)); -}; - -var isArray = Array.isArray || function (xs) { - return Object.prototype.toString.call(xs) === '[object Array]'; -}; - -function map (xs, f) { - if (xs.map) return xs.map(f); - var res = []; - for (var i = 0; i < xs.length; i++) { - res.push(f(xs[i], i)); - } - return res; -} - -var objectKeys = Object.keys || function (obj) { - var res = []; - for (var key in obj) { - if (Object.prototype.hasOwnProperty.call(obj, key)) res.push(key); - } - return res; -}; - -},{}],15:[function(require,module,exports){ -'use strict'; - -exports.decode = exports.parse = require('./decode'); -exports.encode = exports.stringify = require('./encode'); - -},{"./decode":13,"./encode":14}],16:[function(require,module,exports){ -module.exports = require('./lib/_stream_duplex.js'); - -},{"./lib/_stream_duplex.js":17}],17:[function(require,module,exports){ -// Copyright Joyent, Inc. and other Node contributors. -// -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and associated documentation files (the -// "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, -// distribute, sublicense, and/or sell copies of the Software, and to permit -// persons to whom the Software is furnished to do so, subject to the -// following conditions: -// -// The above copyright notice and this permission notice shall be included -// in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN -// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE -// USE OR OTHER DEALINGS IN THE SOFTWARE. - -// a duplex stream is just a stream that is both readable and writable. -// Since JS doesn't have multiple prototypal inheritance, this class -// prototypally inherits from Readable, and then parasitically from -// Writable. - -'use strict'; - -/**/ - -var pna = require('process-nextick-args'); -/**/ - -/**/ -var objectKeys = Object.keys || function (obj) { - var keys = []; - for (var key in obj) { - keys.push(key); - }return keys; -}; -/**/ - -module.exports = Duplex; - -/**/ -var util = Object.create(require('core-util-is')); -util.inherits = require('inherits'); -/**/ - -var Readable = require('./_stream_readable'); -var Writable = require('./_stream_writable'); - -util.inherits(Duplex, Readable); - -{ - // avoid scope creep, the keys array can then be collected - var keys = objectKeys(Writable.prototype); - for (var v = 0; v < keys.length; v++) { - var method = keys[v]; - if (!Duplex.prototype[method]) Duplex.prototype[method] = Writable.prototype[method]; - } -} - -function Duplex(options) { - if (!(this instanceof Duplex)) return new Duplex(options); - - Readable.call(this, options); - Writable.call(this, options); - - if (options && options.readable === false) this.readable = false; - - if (options && options.writable === false) this.writable = false; - - this.allowHalfOpen = true; - if (options && options.allowHalfOpen === false) this.allowHalfOpen = false; - - this.once('end', onend); -} - -Object.defineProperty(Duplex.prototype, 'writableHighWaterMark', { - // making it explicit this property is not enumerable - // because otherwise some prototype manipulation in - // userland will fail - enumerable: false, - get: function () { - return this._writableState.highWaterMark; - } -}); - -// the no-half-open enforcer -function onend() { - // if we allow half-open state, or if the writable side ended, - // then we're ok. - if (this.allowHalfOpen || this._writableState.ended) return; - - // no more data can be written. - // But allow more writes to happen in this tick. - pna.nextTick(onEndNT, this); -} - -function onEndNT(self) { - self.end(); -} - -Object.defineProperty(Duplex.prototype, 'destroyed', { - get: function () { - if (this._readableState === undefined || this._writableState === undefined) { - return false; - } - return this._readableState.destroyed && this._writableState.destroyed; - }, - set: function (value) { - // we ignore the value if the stream - // has not been initialized yet - if (this._readableState === undefined || this._writableState === undefined) { - return; - } - - // backward compatibility, the user is explicitly - // managing destroyed - this._readableState.destroyed = value; - this._writableState.destroyed = value; - } -}); - -Duplex.prototype._destroy = function (err, cb) { - this.push(null); - this.end(); - - pna.nextTick(cb, err); -}; -},{"./_stream_readable":19,"./_stream_writable":21,"core-util-is":4,"inherits":7,"process-nextick-args":10}],18:[function(require,module,exports){ -// Copyright Joyent, Inc. and other Node contributors. -// -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and associated documentation files (the -// "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, -// distribute, sublicense, and/or sell copies of the Software, and to permit -// persons to whom the Software is furnished to do so, subject to the -// following conditions: -// -// The above copyright notice and this permission notice shall be included -// in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN -// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE -// USE OR OTHER DEALINGS IN THE SOFTWARE. - -// a passthrough stream. -// basically just the most minimal sort of Transform stream. -// Every written chunk gets output as-is. - -'use strict'; - -module.exports = PassThrough; - -var Transform = require('./_stream_transform'); - -/**/ -var util = Object.create(require('core-util-is')); -util.inherits = require('inherits'); -/**/ - -util.inherits(PassThrough, Transform); - -function PassThrough(options) { - if (!(this instanceof PassThrough)) return new PassThrough(options); - - Transform.call(this, options); -} - -PassThrough.prototype._transform = function (chunk, encoding, cb) { - cb(null, chunk); -}; -},{"./_stream_transform":20,"core-util-is":4,"inherits":7}],19:[function(require,module,exports){ -(function (process,global){ -// Copyright Joyent, Inc. and other Node contributors. -// -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and associated documentation files (the -// "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, -// distribute, sublicense, and/or sell copies of the Software, and to permit -// persons to whom the Software is furnished to do so, subject to the -// following conditions: -// -// The above copyright notice and this permission notice shall be included -// in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN -// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE -// USE OR OTHER DEALINGS IN THE SOFTWARE. - -'use strict'; - -/**/ - -var pna = require('process-nextick-args'); -/**/ - -module.exports = Readable; - -/**/ -var isArray = require('isarray'); -/**/ - -/**/ -var Duplex; -/**/ - -Readable.ReadableState = ReadableState; - -/**/ -var EE = require('events').EventEmitter; - -var EElistenerCount = function (emitter, type) { - return emitter.listeners(type).length; -}; -/**/ - -/**/ -var Stream = require('./internal/streams/stream'); -/**/ - -/**/ - -var Buffer = require('safe-buffer').Buffer; -var OurUint8Array = global.Uint8Array || function () {}; -function _uint8ArrayToBuffer(chunk) { - return Buffer.from(chunk); -} -function _isUint8Array(obj) { - return Buffer.isBuffer(obj) || obj instanceof OurUint8Array; -} - -/**/ - -/**/ -var util = Object.create(require('core-util-is')); -util.inherits = require('inherits'); -/**/ - -/**/ -var debugUtil = require('util'); -var debug = void 0; -if (debugUtil && debugUtil.debuglog) { - debug = debugUtil.debuglog('stream'); -} else { - debug = function () {}; -} -/**/ - -var BufferList = require('./internal/streams/BufferList'); -var destroyImpl = require('./internal/streams/destroy'); -var StringDecoder; - -util.inherits(Readable, Stream); - -var kProxyEvents = ['error', 'close', 'destroy', 'pause', 'resume']; - -function prependListener(emitter, event, fn) { - // Sadly this is not cacheable as some libraries bundle their own - // event emitter implementation with them. - if (typeof emitter.prependListener === 'function') return emitter.prependListener(event, fn); - - // This is a hack to make sure that our error handler is attached before any - // userland ones. NEVER DO THIS. This is here only because this code needs - // to continue to work with older versions of Node.js that do not include - // the prependListener() method. The goal is to eventually remove this hack. - if (!emitter._events || !emitter._events[event]) emitter.on(event, fn);else if (isArray(emitter._events[event])) emitter._events[event].unshift(fn);else emitter._events[event] = [fn, emitter._events[event]]; -} - -function ReadableState(options, stream) { - Duplex = Duplex || require('./_stream_duplex'); - - options = options || {}; - - // Duplex streams are both readable and writable, but share - // the same options object. - // However, some cases require setting options to different - // values for the readable and the writable sides of the duplex stream. - // These options can be provided separately as readableXXX and writableXXX. - var isDuplex = stream instanceof Duplex; - - // object stream flag. Used to make read(n) ignore n and to - // make all the buffer merging and length checks go away - this.objectMode = !!options.objectMode; - - if (isDuplex) this.objectMode = this.objectMode || !!options.readableObjectMode; - - // the point at which it stops calling _read() to fill the buffer - // Note: 0 is a valid value, means "don't call _read preemptively ever" - var hwm = options.highWaterMark; - var readableHwm = options.readableHighWaterMark; - var defaultHwm = this.objectMode ? 16 : 16 * 1024; - - if (hwm || hwm === 0) this.highWaterMark = hwm;else if (isDuplex && (readableHwm || readableHwm === 0)) this.highWaterMark = readableHwm;else this.highWaterMark = defaultHwm; - - // cast to ints. - this.highWaterMark = Math.floor(this.highWaterMark); - - // A linked list is used to store data chunks instead of an array because the - // linked list can remove elements from the beginning faster than - // array.shift() - this.buffer = new BufferList(); - this.length = 0; - this.pipes = null; - this.pipesCount = 0; - this.flowing = null; - this.ended = false; - this.endEmitted = false; - this.reading = false; - - // a flag to be able to tell if the event 'readable'/'data' is emitted - // immediately, or on a later tick. We set this to true at first, because - // any actions that shouldn't happen until "later" should generally also - // not happen before the first read call. - this.sync = true; - - // whenever we return null, then we set a flag to say - // that we're awaiting a 'readable' event emission. - this.needReadable = false; - this.emittedReadable = false; - this.readableListening = false; - this.resumeScheduled = false; - - // has it been destroyed - this.destroyed = false; - - // Crypto is kind of old and crusty. Historically, its default string - // encoding is 'binary' so we have to make this configurable. - // Everything else in the universe uses 'utf8', though. - this.defaultEncoding = options.defaultEncoding || 'utf8'; - - // the number of writers that are awaiting a drain event in .pipe()s - this.awaitDrain = 0; - - // if true, a maybeReadMore has been scheduled - this.readingMore = false; - - this.decoder = null; - this.encoding = null; - if (options.encoding) { - if (!StringDecoder) StringDecoder = require('string_decoder/').StringDecoder; - this.decoder = new StringDecoder(options.encoding); - this.encoding = options.encoding; - } -} - -function Readable(options) { - Duplex = Duplex || require('./_stream_duplex'); - - if (!(this instanceof Readable)) return new Readable(options); - - this._readableState = new ReadableState(options, this); - - // legacy - this.readable = true; - - if (options) { - if (typeof options.read === 'function') this._read = options.read; - - if (typeof options.destroy === 'function') this._destroy = options.destroy; - } - - Stream.call(this); -} - -Object.defineProperty(Readable.prototype, 'destroyed', { - get: function () { - if (this._readableState === undefined) { - return false; - } - return this._readableState.destroyed; - }, - set: function (value) { - // we ignore the value if the stream - // has not been initialized yet - if (!this._readableState) { - return; - } - - // backward compatibility, the user is explicitly - // managing destroyed - this._readableState.destroyed = value; - } -}); - -Readable.prototype.destroy = destroyImpl.destroy; -Readable.prototype._undestroy = destroyImpl.undestroy; -Readable.prototype._destroy = function (err, cb) { - this.push(null); - cb(err); -}; - -// Manually shove something into the read() buffer. -// This returns true if the highWaterMark has not been hit yet, -// similar to how Writable.write() returns true if you should -// write() some more. -Readable.prototype.push = function (chunk, encoding) { - var state = this._readableState; - var skipChunkCheck; - - if (!state.objectMode) { - if (typeof chunk === 'string') { - encoding = encoding || state.defaultEncoding; - if (encoding !== state.encoding) { - chunk = Buffer.from(chunk, encoding); - encoding = ''; - } - skipChunkCheck = true; - } - } else { - skipChunkCheck = true; - } - - return readableAddChunk(this, chunk, encoding, false, skipChunkCheck); -}; - -// Unshift should *always* be something directly out of read() -Readable.prototype.unshift = function (chunk) { - return readableAddChunk(this, chunk, null, true, false); -}; - -function readableAddChunk(stream, chunk, encoding, addToFront, skipChunkCheck) { - var state = stream._readableState; - if (chunk === null) { - state.reading = false; - onEofChunk(stream, state); - } else { - var er; - if (!skipChunkCheck) er = chunkInvalid(state, chunk); - if (er) { - stream.emit('error', er); - } else if (state.objectMode || chunk && chunk.length > 0) { - if (typeof chunk !== 'string' && !state.objectMode && Object.getPrototypeOf(chunk) !== Buffer.prototype) { - chunk = _uint8ArrayToBuffer(chunk); - } - - if (addToFront) { - if (state.endEmitted) stream.emit('error', new Error('stream.unshift() after end event'));else addChunk(stream, state, chunk, true); - } else if (state.ended) { - stream.emit('error', new Error('stream.push() after EOF')); - } else { - state.reading = false; - if (state.decoder && !encoding) { - chunk = state.decoder.write(chunk); - if (state.objectMode || chunk.length !== 0) addChunk(stream, state, chunk, false);else maybeReadMore(stream, state); - } else { - addChunk(stream, state, chunk, false); - } - } - } else if (!addToFront) { - state.reading = false; - } - } - - return needMoreData(state); -} - -function addChunk(stream, state, chunk, addToFront) { - if (state.flowing && state.length === 0 && !state.sync) { - stream.emit('data', chunk); - stream.read(0); - } else { - // update the buffer info. - state.length += state.objectMode ? 1 : chunk.length; - if (addToFront) state.buffer.unshift(chunk);else state.buffer.push(chunk); - - if (state.needReadable) emitReadable(stream); - } - maybeReadMore(stream, state); -} - -function chunkInvalid(state, chunk) { - var er; - if (!_isUint8Array(chunk) && typeof chunk !== 'string' && chunk !== undefined && !state.objectMode) { - er = new TypeError('Invalid non-string/buffer chunk'); - } - return er; -} - -// if it's past the high water mark, we can push in some more. -// Also, if we have no data yet, we can stand some -// more bytes. This is to work around cases where hwm=0, -// such as the repl. Also, if the push() triggered a -// readable event, and the user called read(largeNumber) such that -// needReadable was set, then we ought to push more, so that another -// 'readable' event will be triggered. -function needMoreData(state) { - return !state.ended && (state.needReadable || state.length < state.highWaterMark || state.length === 0); -} - -Readable.prototype.isPaused = function () { - return this._readableState.flowing === false; -}; - -// backwards compatibility. -Readable.prototype.setEncoding = function (enc) { - if (!StringDecoder) StringDecoder = require('string_decoder/').StringDecoder; - this._readableState.decoder = new StringDecoder(enc); - this._readableState.encoding = enc; - return this; -}; - -// Don't raise the hwm > 8MB -var MAX_HWM = 0x800000; -function computeNewHighWaterMark(n) { - if (n >= MAX_HWM) { - n = MAX_HWM; - } else { - // Get the next highest power of 2 to prevent increasing hwm excessively in - // tiny amounts - n--; - n |= n >>> 1; - n |= n >>> 2; - n |= n >>> 4; - n |= n >>> 8; - n |= n >>> 16; - n++; - } - return n; -} - -// This function is designed to be inlinable, so please take care when making -// changes to the function body. -function howMuchToRead(n, state) { - if (n <= 0 || state.length === 0 && state.ended) return 0; - if (state.objectMode) return 1; - if (n !== n) { - // Only flow one buffer at a time - if (state.flowing && state.length) return state.buffer.head.data.length;else return state.length; - } - // If we're asking for more than the current hwm, then raise the hwm. - if (n > state.highWaterMark) state.highWaterMark = computeNewHighWaterMark(n); - if (n <= state.length) return n; - // Don't have enough - if (!state.ended) { - state.needReadable = true; - return 0; - } - return state.length; -} - -// you can override either this method, or the async _read(n) below. -Readable.prototype.read = function (n) { - debug('read', n); - n = parseInt(n, 10); - var state = this._readableState; - var nOrig = n; - - if (n !== 0) state.emittedReadable = false; - - // if we're doing read(0) to trigger a readable event, but we - // already have a bunch of data in the buffer, then just trigger - // the 'readable' event and move on. - if (n === 0 && state.needReadable && (state.length >= state.highWaterMark || state.ended)) { - debug('read: emitReadable', state.length, state.ended); - if (state.length === 0 && state.ended) endReadable(this);else emitReadable(this); - return null; - } - - n = howMuchToRead(n, state); - - // if we've ended, and we're now clear, then finish it up. - if (n === 0 && state.ended) { - if (state.length === 0) endReadable(this); - return null; - } - - // All the actual chunk generation logic needs to be - // *below* the call to _read. The reason is that in certain - // synthetic stream cases, such as passthrough streams, _read - // may be a completely synchronous operation which may change - // the state of the read buffer, providing enough data when - // before there was *not* enough. - // - // So, the steps are: - // 1. Figure out what the state of things will be after we do - // a read from the buffer. - // - // 2. If that resulting state will trigger a _read, then call _read. - // Note that this may be asynchronous, or synchronous. Yes, it is - // deeply ugly to write APIs this way, but that still doesn't mean - // that the Readable class should behave improperly, as streams are - // designed to be sync/async agnostic. - // Take note if the _read call is sync or async (ie, if the read call - // has returned yet), so that we know whether or not it's safe to emit - // 'readable' etc. - // - // 3. Actually pull the requested chunks out of the buffer and return. - - // if we need a readable event, then we need to do some reading. - var doRead = state.needReadable; - debug('need readable', doRead); - - // if we currently have less than the highWaterMark, then also read some - if (state.length === 0 || state.length - n < state.highWaterMark) { - doRead = true; - debug('length less than watermark', doRead); - } - - // however, if we've ended, then there's no point, and if we're already - // reading, then it's unnecessary. - if (state.ended || state.reading) { - doRead = false; - debug('reading or ended', doRead); - } else if (doRead) { - debug('do read'); - state.reading = true; - state.sync = true; - // if the length is currently zero, then we *need* a readable event. - if (state.length === 0) state.needReadable = true; - // call internal read method - this._read(state.highWaterMark); - state.sync = false; - // If _read pushed data synchronously, then `reading` will be false, - // and we need to re-evaluate how much data we can return to the user. - if (!state.reading) n = howMuchToRead(nOrig, state); - } - - var ret; - if (n > 0) ret = fromList(n, state);else ret = null; - - if (ret === null) { - state.needReadable = true; - n = 0; - } else { - state.length -= n; - } - - if (state.length === 0) { - // If we have nothing in the buffer, then we want to know - // as soon as we *do* get something into the buffer. - if (!state.ended) state.needReadable = true; - - // If we tried to read() past the EOF, then emit end on the next tick. - if (nOrig !== n && state.ended) endReadable(this); - } - - if (ret !== null) this.emit('data', ret); - - return ret; -}; - -function onEofChunk(stream, state) { - if (state.ended) return; - if (state.decoder) { - var chunk = state.decoder.end(); - if (chunk && chunk.length) { - state.buffer.push(chunk); - state.length += state.objectMode ? 1 : chunk.length; - } - } - state.ended = true; - - // emit 'readable' now to make sure it gets picked up. - emitReadable(stream); -} - -// Don't emit readable right away in sync mode, because this can trigger -// another read() call => stack overflow. This way, it might trigger -// a nextTick recursion warning, but that's not so bad. -function emitReadable(stream) { - var state = stream._readableState; - state.needReadable = false; - if (!state.emittedReadable) { - debug('emitReadable', state.flowing); - state.emittedReadable = true; - if (state.sync) pna.nextTick(emitReadable_, stream);else emitReadable_(stream); - } -} - -function emitReadable_(stream) { - debug('emit readable'); - stream.emit('readable'); - flow(stream); -} - -// at this point, the user has presumably seen the 'readable' event, -// and called read() to consume some data. that may have triggered -// in turn another _read(n) call, in which case reading = true if -// it's in progress. -// However, if we're not ended, or reading, and the length < hwm, -// then go ahead and try to read some more preemptively. -function maybeReadMore(stream, state) { - if (!state.readingMore) { - state.readingMore = true; - pna.nextTick(maybeReadMore_, stream, state); - } -} - -function maybeReadMore_(stream, state) { - var len = state.length; - while (!state.reading && !state.flowing && !state.ended && state.length < state.highWaterMark) { - debug('maybeReadMore read 0'); - stream.read(0); - if (len === state.length) - // didn't get any data, stop spinning. - break;else len = state.length; - } - state.readingMore = false; -} - -// abstract method. to be overridden in specific implementation classes. -// call cb(er, data) where data is <= n in length. -// for virtual (non-string, non-buffer) streams, "length" is somewhat -// arbitrary, and perhaps not very meaningful. -Readable.prototype._read = function (n) { - this.emit('error', new Error('_read() is not implemented')); -}; - -Readable.prototype.pipe = function (dest, pipeOpts) { - var src = this; - var state = this._readableState; - - switch (state.pipesCount) { - case 0: - state.pipes = dest; - break; - case 1: - state.pipes = [state.pipes, dest]; - break; - default: - state.pipes.push(dest); - break; - } - state.pipesCount += 1; - debug('pipe count=%d opts=%j', state.pipesCount, pipeOpts); - - var doEnd = (!pipeOpts || pipeOpts.end !== false) && dest !== process.stdout && dest !== process.stderr; - - var endFn = doEnd ? onend : unpipe; - if (state.endEmitted) pna.nextTick(endFn);else src.once('end', endFn); - - dest.on('unpipe', onunpipe); - function onunpipe(readable, unpipeInfo) { - debug('onunpipe'); - if (readable === src) { - if (unpipeInfo && unpipeInfo.hasUnpiped === false) { - unpipeInfo.hasUnpiped = true; - cleanup(); - } - } - } - - function onend() { - debug('onend'); - dest.end(); - } - - // when the dest drains, it reduces the awaitDrain counter - // on the source. This would be more elegant with a .once() - // handler in flow(), but adding and removing repeatedly is - // too slow. - var ondrain = pipeOnDrain(src); - dest.on('drain', ondrain); - - var cleanedUp = false; - function cleanup() { - debug('cleanup'); - // cleanup event handlers once the pipe is broken - dest.removeListener('close', onclose); - dest.removeListener('finish', onfinish); - dest.removeListener('drain', ondrain); - dest.removeListener('error', onerror); - dest.removeListener('unpipe', onunpipe); - src.removeListener('end', onend); - src.removeListener('end', unpipe); - src.removeListener('data', ondata); - - cleanedUp = true; - - // if the reader is waiting for a drain event from this - // specific writer, then it would cause it to never start - // flowing again. - // So, if this is awaiting a drain, then we just call it now. - // If we don't know, then assume that we are waiting for one. - if (state.awaitDrain && (!dest._writableState || dest._writableState.needDrain)) ondrain(); - } - - // If the user pushes more data while we're writing to dest then we'll end up - // in ondata again. However, we only want to increase awaitDrain once because - // dest will only emit one 'drain' event for the multiple writes. - // => Introduce a guard on increasing awaitDrain. - var increasedAwaitDrain = false; - src.on('data', ondata); - function ondata(chunk) { - debug('ondata'); - increasedAwaitDrain = false; - var ret = dest.write(chunk); - if (false === ret && !increasedAwaitDrain) { - // If the user unpiped during `dest.write()`, it is possible - // to get stuck in a permanently paused state if that write - // also returned false. - // => Check whether `dest` is still a piping destination. - if ((state.pipesCount === 1 && state.pipes === dest || state.pipesCount > 1 && indexOf(state.pipes, dest) !== -1) && !cleanedUp) { - debug('false write response, pause', src._readableState.awaitDrain); - src._readableState.awaitDrain++; - increasedAwaitDrain = true; - } - src.pause(); - } - } - - // if the dest has an error, then stop piping into it. - // however, don't suppress the throwing behavior for this. - function onerror(er) { - debug('onerror', er); - unpipe(); - dest.removeListener('error', onerror); - if (EElistenerCount(dest, 'error') === 0) dest.emit('error', er); - } - - // Make sure our error handler is attached before userland ones. - prependListener(dest, 'error', onerror); - - // Both close and finish should trigger unpipe, but only once. - function onclose() { - dest.removeListener('finish', onfinish); - unpipe(); - } - dest.once('close', onclose); - function onfinish() { - debug('onfinish'); - dest.removeListener('close', onclose); - unpipe(); - } - dest.once('finish', onfinish); - - function unpipe() { - debug('unpipe'); - src.unpipe(dest); - } - - // tell the dest that it's being piped to - dest.emit('pipe', src); - - // start the flow if it hasn't been started already. - if (!state.flowing) { - debug('pipe resume'); - src.resume(); - } - - return dest; -}; - -function pipeOnDrain(src) { - return function () { - var state = src._readableState; - debug('pipeOnDrain', state.awaitDrain); - if (state.awaitDrain) state.awaitDrain--; - if (state.awaitDrain === 0 && EElistenerCount(src, 'data')) { - state.flowing = true; - flow(src); - } - }; -} - -Readable.prototype.unpipe = function (dest) { - var state = this._readableState; - var unpipeInfo = { hasUnpiped: false }; - - // if we're not piping anywhere, then do nothing. - if (state.pipesCount === 0) return this; - - // just one destination. most common case. - if (state.pipesCount === 1) { - // passed in one, but it's not the right one. - if (dest && dest !== state.pipes) return this; - - if (!dest) dest = state.pipes; - - // got a match. - state.pipes = null; - state.pipesCount = 0; - state.flowing = false; - if (dest) dest.emit('unpipe', this, unpipeInfo); - return this; - } - - // slow case. multiple pipe destinations. - - if (!dest) { - // remove all. - var dests = state.pipes; - var len = state.pipesCount; - state.pipes = null; - state.pipesCount = 0; - state.flowing = false; - - for (var i = 0; i < len; i++) { - dests[i].emit('unpipe', this, unpipeInfo); - }return this; - } - - // try to find the right one. - var index = indexOf(state.pipes, dest); - if (index === -1) return this; - - state.pipes.splice(index, 1); - state.pipesCount -= 1; - if (state.pipesCount === 1) state.pipes = state.pipes[0]; - - dest.emit('unpipe', this, unpipeInfo); - - return this; -}; - -// set up data events if they are asked for -// Ensure readable listeners eventually get something -Readable.prototype.on = function (ev, fn) { - var res = Stream.prototype.on.call(this, ev, fn); - - if (ev === 'data') { - // Start flowing on next tick if stream isn't explicitly paused - if (this._readableState.flowing !== false) this.resume(); - } else if (ev === 'readable') { - var state = this._readableState; - if (!state.endEmitted && !state.readableListening) { - state.readableListening = state.needReadable = true; - state.emittedReadable = false; - if (!state.reading) { - pna.nextTick(nReadingNextTick, this); - } else if (state.length) { - emitReadable(this); - } - } - } - - return res; -}; -Readable.prototype.addListener = Readable.prototype.on; - -function nReadingNextTick(self) { - debug('readable nexttick read 0'); - self.read(0); -} - -// pause() and resume() are remnants of the legacy readable stream API -// If the user uses them, then switch into old mode. -Readable.prototype.resume = function () { - var state = this._readableState; - if (!state.flowing) { - debug('resume'); - state.flowing = true; - resume(this, state); - } - return this; -}; - -function resume(stream, state) { - if (!state.resumeScheduled) { - state.resumeScheduled = true; - pna.nextTick(resume_, stream, state); - } -} - -function resume_(stream, state) { - if (!state.reading) { - debug('resume read 0'); - stream.read(0); - } - - state.resumeScheduled = false; - state.awaitDrain = 0; - stream.emit('resume'); - flow(stream); - if (state.flowing && !state.reading) stream.read(0); -} - -Readable.prototype.pause = function () { - debug('call pause flowing=%j', this._readableState.flowing); - if (false !== this._readableState.flowing) { - debug('pause'); - this._readableState.flowing = false; - this.emit('pause'); - } - return this; -}; - -function flow(stream) { - var state = stream._readableState; - debug('flow', state.flowing); - while (state.flowing && stream.read() !== null) {} -} - -// wrap an old-style stream as the async data source. -// This is *not* part of the readable stream interface. -// It is an ugly unfortunate mess of history. -Readable.prototype.wrap = function (stream) { - var _this = this; - - var state = this._readableState; - var paused = false; - - stream.on('end', function () { - debug('wrapped end'); - if (state.decoder && !state.ended) { - var chunk = state.decoder.end(); - if (chunk && chunk.length) _this.push(chunk); - } - - _this.push(null); - }); - - stream.on('data', function (chunk) { - debug('wrapped data'); - if (state.decoder) chunk = state.decoder.write(chunk); - - // don't skip over falsy values in objectMode - if (state.objectMode && (chunk === null || chunk === undefined)) return;else if (!state.objectMode && (!chunk || !chunk.length)) return; - - var ret = _this.push(chunk); - if (!ret) { - paused = true; - stream.pause(); - } - }); - - // proxy all the other methods. - // important when wrapping filters and duplexes. - for (var i in stream) { - if (this[i] === undefined && typeof stream[i] === 'function') { - this[i] = function (method) { - return function () { - return stream[method].apply(stream, arguments); - }; - }(i); - } - } - - // proxy certain important events. - for (var n = 0; n < kProxyEvents.length; n++) { - stream.on(kProxyEvents[n], this.emit.bind(this, kProxyEvents[n])); - } - - // when we try to consume some more bytes, simply unpause the - // underlying stream. - this._read = function (n) { - debug('wrapped _read', n); - if (paused) { - paused = false; - stream.resume(); - } - }; - - return this; -}; - -Object.defineProperty(Readable.prototype, 'readableHighWaterMark', { - // making it explicit this property is not enumerable - // because otherwise some prototype manipulation in - // userland will fail - enumerable: false, - get: function () { - return this._readableState.highWaterMark; - } -}); - -// exposed for testing purposes only. -Readable._fromList = fromList; - -// Pluck off n bytes from an array of buffers. -// Length is the combined lengths of all the buffers in the list. -// This function is designed to be inlinable, so please take care when making -// changes to the function body. -function fromList(n, state) { - // nothing buffered - if (state.length === 0) return null; - - var ret; - if (state.objectMode) ret = state.buffer.shift();else if (!n || n >= state.length) { - // read it all, truncate the list - if (state.decoder) ret = state.buffer.join('');else if (state.buffer.length === 1) ret = state.buffer.head.data;else ret = state.buffer.concat(state.length); - state.buffer.clear(); - } else { - // read part of list - ret = fromListPartial(n, state.buffer, state.decoder); - } - - return ret; -} - -// Extracts only enough buffered data to satisfy the amount requested. -// This function is designed to be inlinable, so please take care when making -// changes to the function body. -function fromListPartial(n, list, hasStrings) { - var ret; - if (n < list.head.data.length) { - // slice is the same for buffers and strings - ret = list.head.data.slice(0, n); - list.head.data = list.head.data.slice(n); - } else if (n === list.head.data.length) { - // first chunk is a perfect match - ret = list.shift(); - } else { - // result spans more than one buffer - ret = hasStrings ? copyFromBufferString(n, list) : copyFromBuffer(n, list); - } - return ret; -} - -// Copies a specified amount of characters from the list of buffered data -// chunks. -// This function is designed to be inlinable, so please take care when making -// changes to the function body. -function copyFromBufferString(n, list) { - var p = list.head; - var c = 1; - var ret = p.data; - n -= ret.length; - while (p = p.next) { - var str = p.data; - var nb = n > str.length ? str.length : n; - if (nb === str.length) ret += str;else ret += str.slice(0, n); - n -= nb; - if (n === 0) { - if (nb === str.length) { - ++c; - if (p.next) list.head = p.next;else list.head = list.tail = null; - } else { - list.head = p; - p.data = str.slice(nb); - } - break; - } - ++c; - } - list.length -= c; - return ret; -} - -// Copies a specified amount of bytes from the list of buffered data chunks. -// This function is designed to be inlinable, so please take care when making -// changes to the function body. -function copyFromBuffer(n, list) { - var ret = Buffer.allocUnsafe(n); - var p = list.head; - var c = 1; - p.data.copy(ret); - n -= p.data.length; - while (p = p.next) { - var buf = p.data; - var nb = n > buf.length ? buf.length : n; - buf.copy(ret, ret.length - n, 0, nb); - n -= nb; - if (n === 0) { - if (nb === buf.length) { - ++c; - if (p.next) list.head = p.next;else list.head = list.tail = null; - } else { - list.head = p; - p.data = buf.slice(nb); - } - break; - } - ++c; - } - list.length -= c; - return ret; -} - -function endReadable(stream) { - var state = stream._readableState; - - // If we get here before consuming all the bytes, then that is a - // bug in node. Should never happen. - if (state.length > 0) throw new Error('"endReadable()" called on non-empty stream'); - - if (!state.endEmitted) { - state.ended = true; - pna.nextTick(endReadableNT, state, stream); - } -} - -function endReadableNT(state, stream) { - // Check that we didn't get one last unshift. - if (!state.endEmitted && state.length === 0) { - state.endEmitted = true; - stream.readable = false; - stream.emit('end'); - } -} - -function indexOf(xs, x) { - for (var i = 0, l = xs.length; i < l; i++) { - if (xs[i] === x) return i; - } - return -1; -} -}).call(this,require('_process'),typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) -},{"./_stream_duplex":17,"./internal/streams/BufferList":22,"./internal/streams/destroy":23,"./internal/streams/stream":24,"_process":11,"core-util-is":4,"events":5,"inherits":7,"isarray":9,"process-nextick-args":10,"safe-buffer":25,"string_decoder/":26,"util":2}],20:[function(require,module,exports){ -// Copyright Joyent, Inc. and other Node contributors. -// -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and associated documentation files (the -// "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, -// distribute, sublicense, and/or sell copies of the Software, and to permit -// persons to whom the Software is furnished to do so, subject to the -// following conditions: -// -// The above copyright notice and this permission notice shall be included -// in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN -// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE -// USE OR OTHER DEALINGS IN THE SOFTWARE. - -// a transform stream is a readable/writable stream where you do -// something with the data. Sometimes it's called a "filter", -// but that's not a great name for it, since that implies a thing where -// some bits pass through, and others are simply ignored. (That would -// be a valid example of a transform, of course.) -// -// While the output is causally related to the input, it's not a -// necessarily symmetric or synchronous transformation. For example, -// a zlib stream might take multiple plain-text writes(), and then -// emit a single compressed chunk some time in the future. -// -// Here's how this works: -// -// The Transform stream has all the aspects of the readable and writable -// stream classes. When you write(chunk), that calls _write(chunk,cb) -// internally, and returns false if there's a lot of pending writes -// buffered up. When you call read(), that calls _read(n) until -// there's enough pending readable data buffered up. -// -// In a transform stream, the written data is placed in a buffer. When -// _read(n) is called, it transforms the queued up data, calling the -// buffered _write cb's as it consumes chunks. If consuming a single -// written chunk would result in multiple output chunks, then the first -// outputted bit calls the readcb, and subsequent chunks just go into -// the read buffer, and will cause it to emit 'readable' if necessary. -// -// This way, back-pressure is actually determined by the reading side, -// since _read has to be called to start processing a new chunk. However, -// a pathological inflate type of transform can cause excessive buffering -// here. For example, imagine a stream where every byte of input is -// interpreted as an integer from 0-255, and then results in that many -// bytes of output. Writing the 4 bytes {ff,ff,ff,ff} would result in -// 1kb of data being output. In this case, you could write a very small -// amount of input, and end up with a very large amount of output. In -// such a pathological inflating mechanism, there'd be no way to tell -// the system to stop doing the transform. A single 4MB write could -// cause the system to run out of memory. -// -// However, even in such a pathological case, only a single written chunk -// would be consumed, and then the rest would wait (un-transformed) until -// the results of the previous transformed chunk were consumed. - -'use strict'; - -module.exports = Transform; - -var Duplex = require('./_stream_duplex'); - -/**/ -var util = Object.create(require('core-util-is')); -util.inherits = require('inherits'); -/**/ - -util.inherits(Transform, Duplex); - -function afterTransform(er, data) { - var ts = this._transformState; - ts.transforming = false; - - var cb = ts.writecb; - - if (!cb) { - return this.emit('error', new Error('write callback called multiple times')); - } - - ts.writechunk = null; - ts.writecb = null; - - if (data != null) // single equals check for both `null` and `undefined` - this.push(data); - - cb(er); - - var rs = this._readableState; - rs.reading = false; - if (rs.needReadable || rs.length < rs.highWaterMark) { - this._read(rs.highWaterMark); - } -} - -function Transform(options) { - if (!(this instanceof Transform)) return new Transform(options); - - Duplex.call(this, options); - - this._transformState = { - afterTransform: afterTransform.bind(this), - needTransform: false, - transforming: false, - writecb: null, - writechunk: null, - writeencoding: null - }; - - // start out asking for a readable event once data is transformed. - this._readableState.needReadable = true; - - // we have implemented the _read method, and done the other things - // that Readable wants before the first _read call, so unset the - // sync guard flag. - this._readableState.sync = false; - - if (options) { - if (typeof options.transform === 'function') this._transform = options.transform; - - if (typeof options.flush === 'function') this._flush = options.flush; - } - - // When the writable side finishes, then flush out anything remaining. - this.on('prefinish', prefinish); -} - -function prefinish() { - var _this = this; - - if (typeof this._flush === 'function') { - this._flush(function (er, data) { - done(_this, er, data); - }); - } else { - done(this, null, null); - } -} - -Transform.prototype.push = function (chunk, encoding) { - this._transformState.needTransform = false; - return Duplex.prototype.push.call(this, chunk, encoding); -}; - -// This is the part where you do stuff! -// override this function in implementation classes. -// 'chunk' is an input chunk. -// -// Call `push(newChunk)` to pass along transformed output -// to the readable side. You may call 'push' zero or more times. -// -// Call `cb(err)` when you are done with this chunk. If you pass -// an error, then that'll put the hurt on the whole operation. If you -// never call cb(), then you'll never get another chunk. -Transform.prototype._transform = function (chunk, encoding, cb) { - throw new Error('_transform() is not implemented'); -}; - -Transform.prototype._write = function (chunk, encoding, cb) { - var ts = this._transformState; - ts.writecb = cb; - ts.writechunk = chunk; - ts.writeencoding = encoding; - if (!ts.transforming) { - var rs = this._readableState; - if (ts.needTransform || rs.needReadable || rs.length < rs.highWaterMark) this._read(rs.highWaterMark); - } -}; - -// Doesn't matter what the args are here. -// _transform does all the work. -// That we got here means that the readable side wants more data. -Transform.prototype._read = function (n) { - var ts = this._transformState; - - if (ts.writechunk !== null && ts.writecb && !ts.transforming) { - ts.transforming = true; - this._transform(ts.writechunk, ts.writeencoding, ts.afterTransform); - } else { - // mark that we need a transform, so that any data that comes in - // will get processed, now that we've asked for it. - ts.needTransform = true; - } -}; - -Transform.prototype._destroy = function (err, cb) { - var _this2 = this; - - Duplex.prototype._destroy.call(this, err, function (err2) { - cb(err2); - _this2.emit('close'); - }); -}; - -function done(stream, er, data) { - if (er) return stream.emit('error', er); - - if (data != null) // single equals check for both `null` and `undefined` - stream.push(data); - - // if there's nothing in the write buffer, then that means - // that nothing more will ever be provided - if (stream._writableState.length) throw new Error('Calling transform done when ws.length != 0'); - - if (stream._transformState.transforming) throw new Error('Calling transform done when still transforming'); - - return stream.push(null); -} -},{"./_stream_duplex":17,"core-util-is":4,"inherits":7}],21:[function(require,module,exports){ -(function (process,global,setImmediate){ -// Copyright Joyent, Inc. and other Node contributors. -// -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and associated documentation files (the -// "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, -// distribute, sublicense, and/or sell copies of the Software, and to permit -// persons to whom the Software is furnished to do so, subject to the -// following conditions: -// -// The above copyright notice and this permission notice shall be included -// in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN -// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE -// USE OR OTHER DEALINGS IN THE SOFTWARE. - -// A bit simpler than readable streams. -// Implement an async ._write(chunk, encoding, cb), and it'll handle all -// the drain event emission and buffering. - -'use strict'; - -/**/ - -var pna = require('process-nextick-args'); -/**/ - -module.exports = Writable; - -/* */ -function WriteReq(chunk, encoding, cb) { - this.chunk = chunk; - this.encoding = encoding; - this.callback = cb; - this.next = null; -} - -// It seems a linked list but it is not -// there will be only 2 of these for each stream -function CorkedRequest(state) { - var _this = this; - - this.next = null; - this.entry = null; - this.finish = function () { - onCorkedFinish(_this, state); - }; -} -/* */ - -/**/ -var asyncWrite = !process.browser && ['v0.10', 'v0.9.'].indexOf(process.version.slice(0, 5)) > -1 ? setImmediate : pna.nextTick; -/**/ - -/**/ -var Duplex; -/**/ - -Writable.WritableState = WritableState; - -/**/ -var util = Object.create(require('core-util-is')); -util.inherits = require('inherits'); -/**/ - -/**/ -var internalUtil = { - deprecate: require('util-deprecate') -}; -/**/ - -/**/ -var Stream = require('./internal/streams/stream'); -/**/ - -/**/ - -var Buffer = require('safe-buffer').Buffer; -var OurUint8Array = global.Uint8Array || function () {}; -function _uint8ArrayToBuffer(chunk) { - return Buffer.from(chunk); -} -function _isUint8Array(obj) { - return Buffer.isBuffer(obj) || obj instanceof OurUint8Array; -} - -/**/ - -var destroyImpl = require('./internal/streams/destroy'); - -util.inherits(Writable, Stream); - -function nop() {} - -function WritableState(options, stream) { - Duplex = Duplex || require('./_stream_duplex'); - - options = options || {}; - - // Duplex streams are both readable and writable, but share - // the same options object. - // However, some cases require setting options to different - // values for the readable and the writable sides of the duplex stream. - // These options can be provided separately as readableXXX and writableXXX. - var isDuplex = stream instanceof Duplex; - - // object stream flag to indicate whether or not this stream - // contains buffers or objects. - this.objectMode = !!options.objectMode; - - if (isDuplex) this.objectMode = this.objectMode || !!options.writableObjectMode; - - // the point at which write() starts returning false - // Note: 0 is a valid value, means that we always return false if - // the entire buffer is not flushed immediately on write() - var hwm = options.highWaterMark; - var writableHwm = options.writableHighWaterMark; - var defaultHwm = this.objectMode ? 16 : 16 * 1024; - - if (hwm || hwm === 0) this.highWaterMark = hwm;else if (isDuplex && (writableHwm || writableHwm === 0)) this.highWaterMark = writableHwm;else this.highWaterMark = defaultHwm; - - // cast to ints. - this.highWaterMark = Math.floor(this.highWaterMark); - - // if _final has been called - this.finalCalled = false; - - // drain event flag. - this.needDrain = false; - // at the start of calling end() - this.ending = false; - // when end() has been called, and returned - this.ended = false; - // when 'finish' is emitted - this.finished = false; - - // has it been destroyed - this.destroyed = false; - - // should we decode strings into buffers before passing to _write? - // this is here so that some node-core streams can optimize string - // handling at a lower level. - var noDecode = options.decodeStrings === false; - this.decodeStrings = !noDecode; - - // Crypto is kind of old and crusty. Historically, its default string - // encoding is 'binary' so we have to make this configurable. - // Everything else in the universe uses 'utf8', though. - this.defaultEncoding = options.defaultEncoding || 'utf8'; - - // not an actual buffer we keep track of, but a measurement - // of how much we're waiting to get pushed to some underlying - // socket or file. - this.length = 0; - - // a flag to see when we're in the middle of a write. - this.writing = false; - - // when true all writes will be buffered until .uncork() call - this.corked = 0; - - // a flag to be able to tell if the onwrite cb is called immediately, - // or on a later tick. We set this to true at first, because any - // actions that shouldn't happen until "later" should generally also - // not happen before the first write call. - this.sync = true; - - // a flag to know if we're processing previously buffered items, which - // may call the _write() callback in the same tick, so that we don't - // end up in an overlapped onwrite situation. - this.bufferProcessing = false; - - // the callback that's passed to _write(chunk,cb) - this.onwrite = function (er) { - onwrite(stream, er); - }; - - // the callback that the user supplies to write(chunk,encoding,cb) - this.writecb = null; - - // the amount that is being written when _write is called. - this.writelen = 0; - - this.bufferedRequest = null; - this.lastBufferedRequest = null; - - // number of pending user-supplied write callbacks - // this must be 0 before 'finish' can be emitted - this.pendingcb = 0; - - // emit prefinish if the only thing we're waiting for is _write cbs - // This is relevant for synchronous Transform streams - this.prefinished = false; - - // True if the error was already emitted and should not be thrown again - this.errorEmitted = false; - - // count buffered requests - this.bufferedRequestCount = 0; - - // allocate the first CorkedRequest, there is always - // one allocated and free to use, and we maintain at most two - this.corkedRequestsFree = new CorkedRequest(this); -} - -WritableState.prototype.getBuffer = function getBuffer() { - var current = this.bufferedRequest; - var out = []; - while (current) { - out.push(current); - current = current.next; - } - return out; -}; - -(function () { - try { - Object.defineProperty(WritableState.prototype, 'buffer', { - get: internalUtil.deprecate(function () { - return this.getBuffer(); - }, '_writableState.buffer is deprecated. Use _writableState.getBuffer ' + 'instead.', 'DEP0003') - }); - } catch (_) {} -})(); - -// Test _writableState for inheritance to account for Duplex streams, -// whose prototype chain only points to Readable. -var realHasInstance; -if (typeof Symbol === 'function' && Symbol.hasInstance && typeof Function.prototype[Symbol.hasInstance] === 'function') { - realHasInstance = Function.prototype[Symbol.hasInstance]; - Object.defineProperty(Writable, Symbol.hasInstance, { - value: function (object) { - if (realHasInstance.call(this, object)) return true; - if (this !== Writable) return false; - - return object && object._writableState instanceof WritableState; - } - }); -} else { - realHasInstance = function (object) { - return object instanceof this; - }; -} - -function Writable(options) { - Duplex = Duplex || require('./_stream_duplex'); - - // Writable ctor is applied to Duplexes, too. - // `realHasInstance` is necessary because using plain `instanceof` - // would return false, as no `_writableState` property is attached. - - // Trying to use the custom `instanceof` for Writable here will also break the - // Node.js LazyTransform implementation, which has a non-trivial getter for - // `_writableState` that would lead to infinite recursion. - if (!realHasInstance.call(Writable, this) && !(this instanceof Duplex)) { - return new Writable(options); - } - - this._writableState = new WritableState(options, this); - - // legacy. - this.writable = true; - - if (options) { - if (typeof options.write === 'function') this._write = options.write; - - if (typeof options.writev === 'function') this._writev = options.writev; - - if (typeof options.destroy === 'function') this._destroy = options.destroy; - - if (typeof options.final === 'function') this._final = options.final; - } - - Stream.call(this); -} - -// Otherwise people can pipe Writable streams, which is just wrong. -Writable.prototype.pipe = function () { - this.emit('error', new Error('Cannot pipe, not readable')); -}; - -function writeAfterEnd(stream, cb) { - var er = new Error('write after end'); - // TODO: defer error events consistently everywhere, not just the cb - stream.emit('error', er); - pna.nextTick(cb, er); -} - -// Checks that a user-supplied chunk is valid, especially for the particular -// mode the stream is in. Currently this means that `null` is never accepted -// and undefined/non-string values are only allowed in object mode. -function validChunk(stream, state, chunk, cb) { - var valid = true; - var er = false; - - if (chunk === null) { - er = new TypeError('May not write null values to stream'); - } else if (typeof chunk !== 'string' && chunk !== undefined && !state.objectMode) { - er = new TypeError('Invalid non-string/buffer chunk'); - } - if (er) { - stream.emit('error', er); - pna.nextTick(cb, er); - valid = false; - } - return valid; -} - -Writable.prototype.write = function (chunk, encoding, cb) { - var state = this._writableState; - var ret = false; - var isBuf = !state.objectMode && _isUint8Array(chunk); - - if (isBuf && !Buffer.isBuffer(chunk)) { - chunk = _uint8ArrayToBuffer(chunk); - } - - if (typeof encoding === 'function') { - cb = encoding; - encoding = null; - } - - if (isBuf) encoding = 'buffer';else if (!encoding) encoding = state.defaultEncoding; - - if (typeof cb !== 'function') cb = nop; - - if (state.ended) writeAfterEnd(this, cb);else if (isBuf || validChunk(this, state, chunk, cb)) { - state.pendingcb++; - ret = writeOrBuffer(this, state, isBuf, chunk, encoding, cb); - } - - return ret; -}; - -Writable.prototype.cork = function () { - var state = this._writableState; - - state.corked++; -}; - -Writable.prototype.uncork = function () { - var state = this._writableState; - - if (state.corked) { - state.corked--; - - if (!state.writing && !state.corked && !state.finished && !state.bufferProcessing && state.bufferedRequest) clearBuffer(this, state); - } -}; - -Writable.prototype.setDefaultEncoding = function setDefaultEncoding(encoding) { - // node::ParseEncoding() requires lower case. - if (typeof encoding === 'string') encoding = encoding.toLowerCase(); - if (!(['hex', 'utf8', 'utf-8', 'ascii', 'binary', 'base64', 'ucs2', 'ucs-2', 'utf16le', 'utf-16le', 'raw'].indexOf((encoding + '').toLowerCase()) > -1)) throw new TypeError('Unknown encoding: ' + encoding); - this._writableState.defaultEncoding = encoding; - return this; -}; - -function decodeChunk(state, chunk, encoding) { - if (!state.objectMode && state.decodeStrings !== false && typeof chunk === 'string') { - chunk = Buffer.from(chunk, encoding); - } - return chunk; -} - -Object.defineProperty(Writable.prototype, 'writableHighWaterMark', { - // making it explicit this property is not enumerable - // because otherwise some prototype manipulation in - // userland will fail - enumerable: false, - get: function () { - return this._writableState.highWaterMark; - } -}); - -// if we're already writing something, then just put this -// in the queue, and wait our turn. Otherwise, call _write -// If we return false, then we need a drain event, so set that flag. -function writeOrBuffer(stream, state, isBuf, chunk, encoding, cb) { - if (!isBuf) { - var newChunk = decodeChunk(state, chunk, encoding); - if (chunk !== newChunk) { - isBuf = true; - encoding = 'buffer'; - chunk = newChunk; - } - } - var len = state.objectMode ? 1 : chunk.length; - - state.length += len; - - var ret = state.length < state.highWaterMark; - // we must ensure that previous needDrain will not be reset to false. - if (!ret) state.needDrain = true; - - if (state.writing || state.corked) { - var last = state.lastBufferedRequest; - state.lastBufferedRequest = { - chunk: chunk, - encoding: encoding, - isBuf: isBuf, - callback: cb, - next: null - }; - if (last) { - last.next = state.lastBufferedRequest; - } else { - state.bufferedRequest = state.lastBufferedRequest; - } - state.bufferedRequestCount += 1; - } else { - doWrite(stream, state, false, len, chunk, encoding, cb); - } - - return ret; -} - -function doWrite(stream, state, writev, len, chunk, encoding, cb) { - state.writelen = len; - state.writecb = cb; - state.writing = true; - state.sync = true; - if (writev) stream._writev(chunk, state.onwrite);else stream._write(chunk, encoding, state.onwrite); - state.sync = false; -} - -function onwriteError(stream, state, sync, er, cb) { - --state.pendingcb; - - if (sync) { - // defer the callback if we are being called synchronously - // to avoid piling up things on the stack - pna.nextTick(cb, er); - // this can emit finish, and it will always happen - // after error - pna.nextTick(finishMaybe, stream, state); - stream._writableState.errorEmitted = true; - stream.emit('error', er); - } else { - // the caller expect this to happen before if - // it is async - cb(er); - stream._writableState.errorEmitted = true; - stream.emit('error', er); - // this can emit finish, but finish must - // always follow error - finishMaybe(stream, state); - } -} - -function onwriteStateUpdate(state) { - state.writing = false; - state.writecb = null; - state.length -= state.writelen; - state.writelen = 0; -} - -function onwrite(stream, er) { - var state = stream._writableState; - var sync = state.sync; - var cb = state.writecb; - - onwriteStateUpdate(state); - - if (er) onwriteError(stream, state, sync, er, cb);else { - // Check if we're actually ready to finish, but don't emit yet - var finished = needFinish(state); - - if (!finished && !state.corked && !state.bufferProcessing && state.bufferedRequest) { - clearBuffer(stream, state); - } - - if (sync) { - /**/ - asyncWrite(afterWrite, stream, state, finished, cb); - /**/ - } else { - afterWrite(stream, state, finished, cb); - } - } -} - -function afterWrite(stream, state, finished, cb) { - if (!finished) onwriteDrain(stream, state); - state.pendingcb--; - cb(); - finishMaybe(stream, state); -} - -// Must force callback to be called on nextTick, so that we don't -// emit 'drain' before the write() consumer gets the 'false' return -// value, and has a chance to attach a 'drain' listener. -function onwriteDrain(stream, state) { - if (state.length === 0 && state.needDrain) { - state.needDrain = false; - stream.emit('drain'); - } -} - -// if there's something in the buffer waiting, then process it -function clearBuffer(stream, state) { - state.bufferProcessing = true; - var entry = state.bufferedRequest; - - if (stream._writev && entry && entry.next) { - // Fast case, write everything using _writev() - var l = state.bufferedRequestCount; - var buffer = new Array(l); - var holder = state.corkedRequestsFree; - holder.entry = entry; - - var count = 0; - var allBuffers = true; - while (entry) { - buffer[count] = entry; - if (!entry.isBuf) allBuffers = false; - entry = entry.next; - count += 1; - } - buffer.allBuffers = allBuffers; - - doWrite(stream, state, true, state.length, buffer, '', holder.finish); - - // doWrite is almost always async, defer these to save a bit of time - // as the hot path ends with doWrite - state.pendingcb++; - state.lastBufferedRequest = null; - if (holder.next) { - state.corkedRequestsFree = holder.next; - holder.next = null; - } else { - state.corkedRequestsFree = new CorkedRequest(state); - } - state.bufferedRequestCount = 0; - } else { - // Slow case, write chunks one-by-one - while (entry) { - var chunk = entry.chunk; - var encoding = entry.encoding; - var cb = entry.callback; - var len = state.objectMode ? 1 : chunk.length; - - doWrite(stream, state, false, len, chunk, encoding, cb); - entry = entry.next; - state.bufferedRequestCount--; - // if we didn't call the onwrite immediately, then - // it means that we need to wait until it does. - // also, that means that the chunk and cb are currently - // being processed, so move the buffer counter past them. - if (state.writing) { - break; - } - } - - if (entry === null) state.lastBufferedRequest = null; - } - - state.bufferedRequest = entry; - state.bufferProcessing = false; -} - -Writable.prototype._write = function (chunk, encoding, cb) { - cb(new Error('_write() is not implemented')); -}; - -Writable.prototype._writev = null; - -Writable.prototype.end = function (chunk, encoding, cb) { - var state = this._writableState; - - if (typeof chunk === 'function') { - cb = chunk; - chunk = null; - encoding = null; - } else if (typeof encoding === 'function') { - cb = encoding; - encoding = null; - } - - if (chunk !== null && chunk !== undefined) this.write(chunk, encoding); - - // .end() fully uncorks - if (state.corked) { - state.corked = 1; - this.uncork(); - } - - // ignore unnecessary end() calls. - if (!state.ending && !state.finished) endWritable(this, state, cb); -}; - -function needFinish(state) { - return state.ending && state.length === 0 && state.bufferedRequest === null && !state.finished && !state.writing; -} -function callFinal(stream, state) { - stream._final(function (err) { - state.pendingcb--; - if (err) { - stream.emit('error', err); - } - state.prefinished = true; - stream.emit('prefinish'); - finishMaybe(stream, state); - }); -} -function prefinish(stream, state) { - if (!state.prefinished && !state.finalCalled) { - if (typeof stream._final === 'function') { - state.pendingcb++; - state.finalCalled = true; - pna.nextTick(callFinal, stream, state); - } else { - state.prefinished = true; - stream.emit('prefinish'); - } - } -} - -function finishMaybe(stream, state) { - var need = needFinish(state); - if (need) { - prefinish(stream, state); - if (state.pendingcb === 0) { - state.finished = true; - stream.emit('finish'); - } - } - return need; -} - -function endWritable(stream, state, cb) { - state.ending = true; - finishMaybe(stream, state); - if (cb) { - if (state.finished) pna.nextTick(cb);else stream.once('finish', cb); - } - state.ended = true; - stream.writable = false; -} - -function onCorkedFinish(corkReq, state, err) { - var entry = corkReq.entry; - corkReq.entry = null; - while (entry) { - var cb = entry.callback; - state.pendingcb--; - cb(err); - entry = entry.next; - } - if (state.corkedRequestsFree) { - state.corkedRequestsFree.next = corkReq; - } else { - state.corkedRequestsFree = corkReq; - } -} - -Object.defineProperty(Writable.prototype, 'destroyed', { - get: function () { - if (this._writableState === undefined) { - return false; - } - return this._writableState.destroyed; - }, - set: function (value) { - // we ignore the value if the stream - // has not been initialized yet - if (!this._writableState) { - return; - } - - // backward compatibility, the user is explicitly - // managing destroyed - this._writableState.destroyed = value; - } -}); - -Writable.prototype.destroy = destroyImpl.destroy; -Writable.prototype._undestroy = destroyImpl.undestroy; -Writable.prototype._destroy = function (err, cb) { - this.end(); - cb(err); -}; -}).call(this,require('_process'),typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {},require("timers").setImmediate) -},{"./_stream_duplex":17,"./internal/streams/destroy":23,"./internal/streams/stream":24,"_process":11,"core-util-is":4,"inherits":7,"process-nextick-args":10,"safe-buffer":25,"timers":32,"util-deprecate":34}],22:[function(require,module,exports){ -'use strict'; - -function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } - -var Buffer = require('safe-buffer').Buffer; -var util = require('util'); - -function copyBuffer(src, target, offset) { - src.copy(target, offset); -} - -module.exports = function () { - function BufferList() { - _classCallCheck(this, BufferList); - - this.head = null; - this.tail = null; - this.length = 0; - } - - BufferList.prototype.push = function push(v) { - var entry = { data: v, next: null }; - if (this.length > 0) this.tail.next = entry;else this.head = entry; - this.tail = entry; - ++this.length; - }; - - BufferList.prototype.unshift = function unshift(v) { - var entry = { data: v, next: this.head }; - if (this.length === 0) this.tail = entry; - this.head = entry; - ++this.length; - }; - - BufferList.prototype.shift = function shift() { - if (this.length === 0) return; - var ret = this.head.data; - if (this.length === 1) this.head = this.tail = null;else this.head = this.head.next; - --this.length; - return ret; - }; - - BufferList.prototype.clear = function clear() { - this.head = this.tail = null; - this.length = 0; - }; - - BufferList.prototype.join = function join(s) { - if (this.length === 0) return ''; - var p = this.head; - var ret = '' + p.data; - while (p = p.next) { - ret += s + p.data; - }return ret; - }; - - BufferList.prototype.concat = function concat(n) { - if (this.length === 0) return Buffer.alloc(0); - if (this.length === 1) return this.head.data; - var ret = Buffer.allocUnsafe(n >>> 0); - var p = this.head; - var i = 0; - while (p) { - copyBuffer(p.data, ret, i); - i += p.data.length; - p = p.next; - } - return ret; - }; - - return BufferList; -}(); - -if (util && util.inspect && util.inspect.custom) { - module.exports.prototype[util.inspect.custom] = function () { - var obj = util.inspect({ length: this.length }); - return this.constructor.name + ' ' + obj; - }; -} -},{"safe-buffer":25,"util":2}],23:[function(require,module,exports){ -'use strict'; - -/**/ - -var pna = require('process-nextick-args'); -/**/ - -// undocumented cb() API, needed for core, not for public API -function destroy(err, cb) { - var _this = this; - - var readableDestroyed = this._readableState && this._readableState.destroyed; - var writableDestroyed = this._writableState && this._writableState.destroyed; - - if (readableDestroyed || writableDestroyed) { - if (cb) { - cb(err); - } else if (err && (!this._writableState || !this._writableState.errorEmitted)) { - pna.nextTick(emitErrorNT, this, err); - } - return this; - } - - // we set destroyed to true before firing error callbacks in order - // to make it re-entrance safe in case destroy() is called within callbacks - - if (this._readableState) { - this._readableState.destroyed = true; - } - - // if this is a duplex stream mark the writable part as destroyed as well - if (this._writableState) { - this._writableState.destroyed = true; - } - - this._destroy(err || null, function (err) { - if (!cb && err) { - pna.nextTick(emitErrorNT, _this, err); - if (_this._writableState) { - _this._writableState.errorEmitted = true; - } - } else if (cb) { - cb(err); - } - }); - - return this; -} - -function undestroy() { - if (this._readableState) { - this._readableState.destroyed = false; - this._readableState.reading = false; - this._readableState.ended = false; - this._readableState.endEmitted = false; - } - - if (this._writableState) { - this._writableState.destroyed = false; - this._writableState.ended = false; - this._writableState.ending = false; - this._writableState.finished = false; - this._writableState.errorEmitted = false; - } -} - -function emitErrorNT(self, err) { - self.emit('error', err); -} - -module.exports = { - destroy: destroy, - undestroy: undestroy -}; -},{"process-nextick-args":10}],24:[function(require,module,exports){ -module.exports = require('events').EventEmitter; - -},{"events":5}],25:[function(require,module,exports){ -/* eslint-disable node/no-deprecated-api */ -var buffer = require('buffer') -var Buffer = buffer.Buffer - -// alternative to using Object.keys for old browsers -function copyProps (src, dst) { - for (var key in src) { - dst[key] = src[key] - } -} -if (Buffer.from && Buffer.alloc && Buffer.allocUnsafe && Buffer.allocUnsafeSlow) { - module.exports = buffer -} else { - // Copy properties from require('buffer') - copyProps(buffer, exports) - exports.Buffer = SafeBuffer -} - -function SafeBuffer (arg, encodingOrOffset, length) { - return Buffer(arg, encodingOrOffset, length) -} - -// Copy static methods from Buffer -copyProps(Buffer, SafeBuffer) - -SafeBuffer.from = function (arg, encodingOrOffset, length) { - if (typeof arg === 'number') { - throw new TypeError('Argument must not be a number') - } - return Buffer(arg, encodingOrOffset, length) -} - -SafeBuffer.alloc = function (size, fill, encoding) { - if (typeof size !== 'number') { - throw new TypeError('Argument must be a number') - } - var buf = Buffer(size) - if (fill !== undefined) { - if (typeof encoding === 'string') { - buf.fill(fill, encoding) - } else { - buf.fill(fill) - } - } else { - buf.fill(0) - } - return buf -} - -SafeBuffer.allocUnsafe = function (size) { - if (typeof size !== 'number') { - throw new TypeError('Argument must be a number') - } - return Buffer(size) -} - -SafeBuffer.allocUnsafeSlow = function (size) { - if (typeof size !== 'number') { - throw new TypeError('Argument must be a number') - } - return buffer.SlowBuffer(size) -} - -},{"buffer":3}],26:[function(require,module,exports){ -// Copyright Joyent, Inc. and other Node contributors. -// -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and associated documentation files (the -// "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, -// distribute, sublicense, and/or sell copies of the Software, and to permit -// persons to whom the Software is furnished to do so, subject to the -// following conditions: -// -// The above copyright notice and this permission notice shall be included -// in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN -// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE -// USE OR OTHER DEALINGS IN THE SOFTWARE. - -'use strict'; - -/**/ - -var Buffer = require('safe-buffer').Buffer; -/**/ - -var isEncoding = Buffer.isEncoding || function (encoding) { - encoding = '' + encoding; - switch (encoding && encoding.toLowerCase()) { - case 'hex':case 'utf8':case 'utf-8':case 'ascii':case 'binary':case 'base64':case 'ucs2':case 'ucs-2':case 'utf16le':case 'utf-16le':case 'raw': - return true; - default: - return false; - } -}; - -function _normalizeEncoding(enc) { - if (!enc) return 'utf8'; - var retried; - while (true) { - switch (enc) { - case 'utf8': - case 'utf-8': - return 'utf8'; - case 'ucs2': - case 'ucs-2': - case 'utf16le': - case 'utf-16le': - return 'utf16le'; - case 'latin1': - case 'binary': - return 'latin1'; - case 'base64': - case 'ascii': - case 'hex': - return enc; - default: - if (retried) return; // undefined - enc = ('' + enc).toLowerCase(); - retried = true; - } - } -}; - -// Do not cache `Buffer.isEncoding` when checking encoding names as some -// modules monkey-patch it to support additional encodings -function normalizeEncoding(enc) { - var nenc = _normalizeEncoding(enc); - if (typeof nenc !== 'string' && (Buffer.isEncoding === isEncoding || !isEncoding(enc))) throw new Error('Unknown encoding: ' + enc); - return nenc || enc; -} - -// StringDecoder provides an interface for efficiently splitting a series of -// buffers into a series of JS strings without breaking apart multi-byte -// characters. -exports.StringDecoder = StringDecoder; -function StringDecoder(encoding) { - this.encoding = normalizeEncoding(encoding); - var nb; - switch (this.encoding) { - case 'utf16le': - this.text = utf16Text; - this.end = utf16End; - nb = 4; - break; - case 'utf8': - this.fillLast = utf8FillLast; - nb = 4; - break; - case 'base64': - this.text = base64Text; - this.end = base64End; - nb = 3; - break; - default: - this.write = simpleWrite; - this.end = simpleEnd; - return; - } - this.lastNeed = 0; - this.lastTotal = 0; - this.lastChar = Buffer.allocUnsafe(nb); -} - -StringDecoder.prototype.write = function (buf) { - if (buf.length === 0) return ''; - var r; - var i; - if (this.lastNeed) { - r = this.fillLast(buf); - if (r === undefined) return ''; - i = this.lastNeed; - this.lastNeed = 0; - } else { - i = 0; - } - if (i < buf.length) return r ? r + this.text(buf, i) : this.text(buf, i); - return r || ''; -}; - -StringDecoder.prototype.end = utf8End; - -// Returns only complete characters in a Buffer -StringDecoder.prototype.text = utf8Text; - -// Attempts to complete a partial non-UTF-8 character using bytes from a Buffer -StringDecoder.prototype.fillLast = function (buf) { - if (this.lastNeed <= buf.length) { - buf.copy(this.lastChar, this.lastTotal - this.lastNeed, 0, this.lastNeed); - return this.lastChar.toString(this.encoding, 0, this.lastTotal); - } - buf.copy(this.lastChar, this.lastTotal - this.lastNeed, 0, buf.length); - this.lastNeed -= buf.length; -}; - -// Checks the type of a UTF-8 byte, whether it's ASCII, a leading byte, or a -// continuation byte. If an invalid byte is detected, -2 is returned. -function utf8CheckByte(byte) { - if (byte <= 0x7F) return 0;else if (byte >> 5 === 0x06) return 2;else if (byte >> 4 === 0x0E) return 3;else if (byte >> 3 === 0x1E) return 4; - return byte >> 6 === 0x02 ? -1 : -2; -} - -// Checks at most 3 bytes at the end of a Buffer in order to detect an -// incomplete multi-byte UTF-8 character. The total number of bytes (2, 3, or 4) -// needed to complete the UTF-8 character (if applicable) are returned. -function utf8CheckIncomplete(self, buf, i) { - var j = buf.length - 1; - if (j < i) return 0; - var nb = utf8CheckByte(buf[j]); - if (nb >= 0) { - if (nb > 0) self.lastNeed = nb - 1; - return nb; - } - if (--j < i || nb === -2) return 0; - nb = utf8CheckByte(buf[j]); - if (nb >= 0) { - if (nb > 0) self.lastNeed = nb - 2; - return nb; - } - if (--j < i || nb === -2) return 0; - nb = utf8CheckByte(buf[j]); - if (nb >= 0) { - if (nb > 0) { - if (nb === 2) nb = 0;else self.lastNeed = nb - 3; - } - return nb; - } - return 0; -} - -// Validates as many continuation bytes for a multi-byte UTF-8 character as -// needed or are available. If we see a non-continuation byte where we expect -// one, we "replace" the validated continuation bytes we've seen so far with -// a single UTF-8 replacement character ('\ufffd'), to match v8's UTF-8 decoding -// behavior. The continuation byte check is included three times in the case -// where all of the continuation bytes for a character exist in the same buffer. -// It is also done this way as a slight performance increase instead of using a -// loop. -function utf8CheckExtraBytes(self, buf, p) { - if ((buf[0] & 0xC0) !== 0x80) { - self.lastNeed = 0; - return '\ufffd'; - } - if (self.lastNeed > 1 && buf.length > 1) { - if ((buf[1] & 0xC0) !== 0x80) { - self.lastNeed = 1; - return '\ufffd'; - } - if (self.lastNeed > 2 && buf.length > 2) { - if ((buf[2] & 0xC0) !== 0x80) { - self.lastNeed = 2; - return '\ufffd'; - } - } - } -} - -// Attempts to complete a multi-byte UTF-8 character using bytes from a Buffer. -function utf8FillLast(buf) { - var p = this.lastTotal - this.lastNeed; - var r = utf8CheckExtraBytes(this, buf, p); - if (r !== undefined) return r; - if (this.lastNeed <= buf.length) { - buf.copy(this.lastChar, p, 0, this.lastNeed); - return this.lastChar.toString(this.encoding, 0, this.lastTotal); - } - buf.copy(this.lastChar, p, 0, buf.length); - this.lastNeed -= buf.length; -} - -// Returns all complete UTF-8 characters in a Buffer. If the Buffer ended on a -// partial character, the character's bytes are buffered until the required -// number of bytes are available. -function utf8Text(buf, i) { - var total = utf8CheckIncomplete(this, buf, i); - if (!this.lastNeed) return buf.toString('utf8', i); - this.lastTotal = total; - var end = buf.length - (total - this.lastNeed); - buf.copy(this.lastChar, 0, end); - return buf.toString('utf8', i, end); -} - -// For UTF-8, a replacement character is added when ending on a partial -// character. -function utf8End(buf) { - var r = buf && buf.length ? this.write(buf) : ''; - if (this.lastNeed) return r + '\ufffd'; - return r; -} - -// UTF-16LE typically needs two bytes per character, but even if we have an even -// number of bytes available, we need to check if we end on a leading/high -// surrogate. In that case, we need to wait for the next two bytes in order to -// decode the last character properly. -function utf16Text(buf, i) { - if ((buf.length - i) % 2 === 0) { - var r = buf.toString('utf16le', i); - if (r) { - var c = r.charCodeAt(r.length - 1); - if (c >= 0xD800 && c <= 0xDBFF) { - this.lastNeed = 2; - this.lastTotal = 4; - this.lastChar[0] = buf[buf.length - 2]; - this.lastChar[1] = buf[buf.length - 1]; - return r.slice(0, -1); - } - } - return r; - } - this.lastNeed = 1; - this.lastTotal = 2; - this.lastChar[0] = buf[buf.length - 1]; - return buf.toString('utf16le', i, buf.length - 1); -} - -// For UTF-16LE we do not explicitly append special replacement characters if we -// end on a partial character, we simply let v8 handle that. -function utf16End(buf) { - var r = buf && buf.length ? this.write(buf) : ''; - if (this.lastNeed) { - var end = this.lastTotal - this.lastNeed; - return r + this.lastChar.toString('utf16le', 0, end); - } - return r; -} - -function base64Text(buf, i) { - var n = (buf.length - i) % 3; - if (n === 0) return buf.toString('base64', i); - this.lastNeed = 3 - n; - this.lastTotal = 3; - if (n === 1) { - this.lastChar[0] = buf[buf.length - 1]; - } else { - this.lastChar[0] = buf[buf.length - 2]; - this.lastChar[1] = buf[buf.length - 1]; - } - return buf.toString('base64', i, buf.length - n); -} - -function base64End(buf) { - var r = buf && buf.length ? this.write(buf) : ''; - if (this.lastNeed) return r + this.lastChar.toString('base64', 0, 3 - this.lastNeed); - return r; -} - -// Pass bytes on through for single-byte encodings (e.g. ascii, latin1, hex) -function simpleWrite(buf) { - return buf.toString(this.encoding); -} - -function simpleEnd(buf) { - return buf && buf.length ? this.write(buf) : ''; -} -},{"safe-buffer":25}],27:[function(require,module,exports){ -module.exports = require('./readable').PassThrough - -},{"./readable":28}],28:[function(require,module,exports){ -exports = module.exports = require('./lib/_stream_readable.js'); -exports.Stream = exports; -exports.Readable = exports; -exports.Writable = require('./lib/_stream_writable.js'); -exports.Duplex = require('./lib/_stream_duplex.js'); -exports.Transform = require('./lib/_stream_transform.js'); -exports.PassThrough = require('./lib/_stream_passthrough.js'); - -},{"./lib/_stream_duplex.js":17,"./lib/_stream_passthrough.js":18,"./lib/_stream_readable.js":19,"./lib/_stream_transform.js":20,"./lib/_stream_writable.js":21}],29:[function(require,module,exports){ -module.exports = require('./readable').Transform - -},{"./readable":28}],30:[function(require,module,exports){ -module.exports = require('./lib/_stream_writable.js'); - -},{"./lib/_stream_writable.js":21}],31:[function(require,module,exports){ -// Copyright Joyent, Inc. and other Node contributors. -// -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and associated documentation files (the -// "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, -// distribute, sublicense, and/or sell copies of the Software, and to permit -// persons to whom the Software is furnished to do so, subject to the -// following conditions: -// -// The above copyright notice and this permission notice shall be included -// in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN -// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE -// USE OR OTHER DEALINGS IN THE SOFTWARE. - -module.exports = Stream; - -var EE = require('events').EventEmitter; -var inherits = require('inherits'); - -inherits(Stream, EE); -Stream.Readable = require('readable-stream/readable.js'); -Stream.Writable = require('readable-stream/writable.js'); -Stream.Duplex = require('readable-stream/duplex.js'); -Stream.Transform = require('readable-stream/transform.js'); -Stream.PassThrough = require('readable-stream/passthrough.js'); - -// Backwards-compat with node 0.4.x -Stream.Stream = Stream; - - - -// old-style streams. Note that the pipe method (the only relevant -// part of this class) is overridden in the Readable class. - -function Stream() { - EE.call(this); -} - -Stream.prototype.pipe = function(dest, options) { - var source = this; - - function ondata(chunk) { - if (dest.writable) { - if (false === dest.write(chunk) && source.pause) { - source.pause(); - } - } - } - - source.on('data', ondata); - - function ondrain() { - if (source.readable && source.resume) { - source.resume(); - } - } - - dest.on('drain', ondrain); - - // If the 'end' option is not supplied, dest.end() will be called when - // source gets the 'end' or 'close' events. Only dest.end() once. - if (!dest._isStdio && (!options || options.end !== false)) { - source.on('end', onend); - source.on('close', onclose); - } - - var didOnEnd = false; - function onend() { - if (didOnEnd) return; - didOnEnd = true; - - dest.end(); - } - - - function onclose() { - if (didOnEnd) return; - didOnEnd = true; - - if (typeof dest.destroy === 'function') dest.destroy(); - } - - // don't leave dangling pipes when there are errors. - function onerror(er) { - cleanup(); - if (EE.listenerCount(this, 'error') === 0) { - throw er; // Unhandled stream error in pipe. - } - } - - source.on('error', onerror); - dest.on('error', onerror); - - // remove all the event listeners that were added. - function cleanup() { - source.removeListener('data', ondata); - dest.removeListener('drain', ondrain); - - source.removeListener('end', onend); - source.removeListener('close', onclose); - - source.removeListener('error', onerror); - dest.removeListener('error', onerror); - - source.removeListener('end', cleanup); - source.removeListener('close', cleanup); - - dest.removeListener('close', cleanup); - } - - source.on('end', cleanup); - source.on('close', cleanup); - - dest.on('close', cleanup); - - dest.emit('pipe', source); - - // Allow for unix-like usage: A.pipe(B).pipe(C) - return dest; -}; - -},{"events":5,"inherits":7,"readable-stream/duplex.js":16,"readable-stream/passthrough.js":27,"readable-stream/readable.js":28,"readable-stream/transform.js":29,"readable-stream/writable.js":30}],32:[function(require,module,exports){ -(function (setImmediate,clearImmediate){ -var nextTick = require('process/browser.js').nextTick; -var apply = Function.prototype.apply; -var slice = Array.prototype.slice; -var immediateIds = {}; -var nextImmediateId = 0; - -// DOM APIs, for completeness - -exports.setTimeout = function() { - return new Timeout(apply.call(setTimeout, window, arguments), clearTimeout); -}; -exports.setInterval = function() { - return new Timeout(apply.call(setInterval, window, arguments), clearInterval); -}; -exports.clearTimeout = -exports.clearInterval = function(timeout) { timeout.close(); }; - -function Timeout(id, clearFn) { - this._id = id; - this._clearFn = clearFn; -} -Timeout.prototype.unref = Timeout.prototype.ref = function() {}; -Timeout.prototype.close = function() { - this._clearFn.call(window, this._id); -}; - -// Does not start the time, just sets up the members needed. -exports.enroll = function(item, msecs) { - clearTimeout(item._idleTimeoutId); - item._idleTimeout = msecs; -}; - -exports.unenroll = function(item) { - clearTimeout(item._idleTimeoutId); - item._idleTimeout = -1; -}; - -exports._unrefActive = exports.active = function(item) { - clearTimeout(item._idleTimeoutId); - - var msecs = item._idleTimeout; - if (msecs >= 0) { - item._idleTimeoutId = setTimeout(function onTimeout() { - if (item._onTimeout) - item._onTimeout(); - }, msecs); - } -}; - -// That's not how node.js implements it but the exposed api is the same. -exports.setImmediate = typeof setImmediate === "function" ? setImmediate : function(fn) { - var id = nextImmediateId++; - var args = arguments.length < 2 ? false : slice.call(arguments, 1); - - immediateIds[id] = true; - - nextTick(function onNextTick() { - if (immediateIds[id]) { - // fn.call() is faster so we optimize for the common use-case - // @see http://jsperf.com/call-apply-segu - if (args) { - fn.apply(null, args); - } else { - fn.call(null); - } - // Prevent ids from leaking - exports.clearImmediate(id); - } - }); - - return id; -}; - -exports.clearImmediate = typeof clearImmediate === "function" ? clearImmediate : function(id) { - delete immediateIds[id]; -}; -}).call(this,require("timers").setImmediate,require("timers").clearImmediate) -},{"process/browser.js":11,"timers":32}],33:[function(require,module,exports){ -'use strict'; - -module.exports = { - isString: function(arg) { - return typeof(arg) === 'string'; - }, - isObject: function(arg) { - return typeof(arg) === 'object' && arg !== null; - }, - isNull: function(arg) { - return arg === null; - }, - isNullOrUndefined: function(arg) { - return arg == null; - } -}; - -},{}],34:[function(require,module,exports){ -(function (global){ - -/** - * Module exports. - */ - -module.exports = deprecate; - -/** - * Mark that a method should not be used. - * Returns a modified function which warns once by default. - * - * If `localStorage.noDeprecation = true` is set, then it is a no-op. - * - * If `localStorage.throwDeprecation = true` is set, then deprecated functions - * will throw an Error when invoked. - * - * If `localStorage.traceDeprecation = true` is set, then deprecated functions - * will invoke `console.trace()` instead of `console.error()`. - * - * @param {Function} fn - the function to deprecate - * @param {String} msg - the string to print to the console when `fn` is invoked - * @returns {Function} a new "deprecated" version of `fn` - * @api public - */ - -function deprecate (fn, msg) { - if (config('noDeprecation')) { - return fn; - } - - var warned = false; - function deprecated() { - if (!warned) { - if (config('throwDeprecation')) { - throw new Error(msg); - } else if (config('traceDeprecation')) { - console.trace(msg); - } else { - console.warn(msg); - } - warned = true; - } - return fn.apply(this, arguments); - } - - return deprecated; -} - -/** - * Checks `localStorage` for boolean values for the given `name`. - * - * @param {String} name - * @returns {Boolean} - * @api private - */ - -function config (name) { - // accessing global.localStorage can trigger a DOMException in sandboxed iframes - try { - if (!global.localStorage) return false; - } catch (_) { - return false; - } - var val = global.localStorage[name]; - if (null == val) return false; - return String(val).toLowerCase() === 'true'; -} - -}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) -},{}],35:[function(require,module,exports){ -const matMul = require('../lib/linalgebra/mat-mul.js'); -const transpose = require('../lib/linalgebra/transpose.js'); -const add = require('../lib/linalgebra/add.js'); -const invert = require('../lib/linalgebra/invert.js'); -const sub = require('../lib/linalgebra/sub.js'); -const getIdentity = require('../lib/linalgebra/identity.js'); -const State = require('./state.js'); - -/** -* @callback ObservationCallback -* @param {Object} opts -* @param {Number} opts.index -* @param {Number} opts.previousCorrected -*/ - -/** -* @typedef {Object} ObservationConfig -* @property {Number} dimension -* @property {Array.Array.> | ObservationCallback} stateProjection, -* @property {Array.Array.> | ObservationCallback} covariance -*/ - -/** -* @callback DynamicCallback -* @param {Object} opts -* @param {Number} opts.index -* @param {State} opts.predicted -* @param {Observation} opts.observation -*/ - -/** -* @typedef {Object} DynamicConfig -* @property {Number} dimension -* @property {Array.Array.> | DynamicCallback} transition, -* @property {Array.Array.> | DynamicCallback} covariance -*/ - -const defaultLogger = { - info: (...args) => console.log(...args), - debug: () => {}, - warn: (...args) => console.log(...args), - error: (...args) => console.log(...args) -}; - -/** -* @class -* @property {DynamicConfig} dynamic the system's dynamic model -* @property {ObservationConfig} observation the system's observation model -*@property logger a Winston-like logger -*/ -class CoreKalmanFilter { - /** - * @param {DynamicConfig} dynamic - * @param {ObservationConfig} observation the system's observation model - */ - - constructor({dynamic, observation, logger = defaultLogger}) { - this.dynamic = dynamic; - this.observation = observation; - this.logger = logger; - } - - getValue(fn, options) { - return (typeof (fn) === 'function' ? fn(options) : fn); - } - - getInitState() { - const {mean: meanInit, covariance: covarianceInit, index: indexInit} = this.dynamic.init; - const initState = new State({ - mean: meanInit, - covariance: covarianceInit, - index: indexInit}); - return initState; - } - - /** - This will return the predicted covariance of a given previousCorrected State, this will help us to build the asymptoticState. - * @param {State} previousCorrected - * @returns{Array.>} - */ - - getPredictedCovariance({previousCorrected} = {}) { - previousCorrected = previousCorrected || this.getInitState(); - - const getValueOptions = {previousCorrected, index: previousCorrected.index}; - const d = this.getValue(this.dynamic.transition, getValueOptions); - const dTransposed = transpose(d); - const covarianceInter = matMul(d, previousCorrected.covariance); - const covariancePrevious = matMul(covarianceInter, dTransposed); - const dynCov = this.getValue(this.dynamic.covariance, getValueOptions); - - const covariance = add( - dynCov, - covariancePrevious - ); - return covariance; - } - - /** - This will return the new prediction, relatively to the dynamic model chosen - * @param {State} previousCorrected State relative to our dynamic model - * @returns{State} predicted State - */ - - predict({previousCorrected} = {}) { - previousCorrected = previousCorrected || this.getInitState(); - - State.check(previousCorrected, {dimension: this.dynamic.dimension}); - - const getValueOptions = {previousCorrected, index: previousCorrected.index}; - const d = this.getValue(this.dynamic.transition, getValueOptions); - - const mean = matMul(d, previousCorrected.mean); - - const covariance = this.getPredictedCovariance({previousCorrected}); - let index; - if (typeof (previousCorrected.index) === 'number') { - index = previousCorrected.index + 1; - } - else { - index = 'Index key is not defined' - } - - const predicted = new State({mean, covariance, index}); - this.logger.debug('Prediction done', predicted); - return predicted; - } - /** - This will return the new correction, taking into account the prediction made - and the observation of the sensor - * @param {State} predicted the previous State - * @returns{Array} kalmanGain - */ - - getGain({predicted, stateProjection}) { - const getValueOptions = {predicted, index: predicted.index}; - stateProjection = stateProjection || this.getValue(this.observation.stateProjection, getValueOptions); - const obsCovariance = this.getValue(this.observation.covariance, getValueOptions); - const stateProjTransposed = transpose(stateProjection); - const noiselessInnovation = matMul( - matMul(stateProjection, predicted.covariance), - stateProjTransposed - ); - const innovationCovariance = add(noiselessInnovation, obsCovariance); - const optimalKalmanGain = matMul( - matMul(predicted.covariance, stateProjTransposed), - invert(innovationCovariance) - ); - return optimalKalmanGain; - } - - /** - This will return the corrected covariance of a given predicted State, this will help us to build the asymptoticState. - * @param {State} predicted the previous State - * @returns{Array.>} - */ - - getCorrectedCovariance({predicted}) { - const getValueOptions = {predicted, index: predicted.index}; - const identity = getIdentity(predicted.covariance.length); - const stateProj = this.getValue(this.observation.stateProjection, getValueOptions); - const optimalKalmanGain = this.getGain({predicted, stateProjection: stateProj}); - return matMul( - sub(identity, matMul(optimalKalmanGain, stateProj)), - predicted.covariance - ); - } - - /** - This will return the new correction, taking into account the prediction made - and the observation of the sensor - * @param {State} predicted the previous State - * @param {Array} observation the observation of the sensor - * @returns{State} corrected State of the Kalman Filter - */ - - correct({predicted, observation}) { - State.check(predicted, {dimension: this.dynamic.dimension}); - if (!observation) { - throw (new Error('no measure available')); - } - - const getValueOptions = {predicted, index: predicted.index}; - const stateProj = this.getValue(this.observation.stateProjection, getValueOptions); - - const optimalKalmanGain = this.getGain({predicted, stateProjection: stateProj}); - const innovation = sub( - observation, - matMul(stateProj, predicted.mean) - ); - const mean = add( - predicted.mean, - matMul(optimalKalmanGain, innovation) - ); - - const covariance = this.getCorrectedCovariance({predicted}); - const corrected = new State({mean, covariance, index: predicted.index}); - this.logger.debug('Correction done', corrected); - return corrected; - } -} - -module.exports = CoreKalmanFilter; - -},{"../lib/linalgebra/add.js":39,"../lib/linalgebra/identity.js":43,"../lib/linalgebra/invert.js":44,"../lib/linalgebra/mat-mul.js":45,"../lib/linalgebra/sub.js":47,"../lib/linalgebra/transpose.js":50,"./state.js":58}],36:[function(require,module,exports){ -const identity = require('../linalgebra/identity.js'); - -/** -*Creates a dynamic model, following constant acceleration model with respect with the dimensions provided in the observation parameters -* @param {DynamicConfig} dynamic -* @param {ObservationConfig} observation -* @returns {DynamicConfig} -*/ - -module.exports = function (dynamic, observation) { - const timeStep = dynamic.timeStep || 1; - const observedProjection = observation.observedProjection; - const stateProjection = observation.stateProjection; - const observationDimension = observation.dimension; - let dimension; - - if (stateProjection && Number.isInteger(stateProjection[0].length / 3)) { - dimension = observation.stateProjection[0].length; - } else if (observedProjection) { - dimension = observedProjection[0].length * 3; - } else if (observationDimension) { - dimension = observationDimension * 3; - } else { - throw (new Error('observedProjection or stateProjection should be defined in observation in order to use constant-speed filter')); - } - - const baseDimension = dimension / 3; - // We construct the transition and covariance matrices - const transition = identity(dimension); - for (let i = 0; i < baseDimension; i++) { - transition[i][i + baseDimension] = timeStep; - transition[i][i + (2 * baseDimension)] = 0.5 * (timeStep ** 2); - transition[i + baseDimension][i + (2 * baseDimension)] = timeStep; - } - - const arrayCovariance = new Array(baseDimension).fill(1) - .concat(new Array(baseDimension).fill(timeStep * timeStep)) - .concat(new Array(baseDimension).fill(timeStep ** 4)); - const covariance = dynamic.covariance || arrayCovariance; - return Object.assign({}, dynamic, {dimension, transition, covariance}); -}; - -},{"../linalgebra/identity.js":43}],37:[function(require,module,exports){ -const identity = require('../linalgebra/identity.js'); -/** -*Creates a dynamic model, following constant position model with respect with the dimensions provided in the observation parameters -* @param {DynamicConfig} dynamic -* @param {ObservationConfig} observation -* @returns {DynamicConfig} -*/ - -module.exports = function (dynamic, observation) { - let dimension = dynamic.dimension; - const observationDimension = observation.dimension; - const observedProjection = observation.observedProjection; - const stateProjection = observation.stateProjection; - let covariance = dynamic.covariance; - - if (!dynamic.dimension) { - if (observationDimension) { - dimension = observationDimension; - } else if (observedProjection) { - dimension = observedProjection[0].length; - } else if (stateProjection) { - dimension = stateProjection[0].length; - } - } - - const transition = identity(dimension); - covariance = covariance || identity(dimension); - return Object.assign({}, dynamic, {dimension, transition, covariance}); -}; - -},{"../linalgebra/identity.js":43}],38:[function(require,module,exports){ -const identity = require('../linalgebra/identity.js'); - -/** -*Creates a dynamic model, following constant position model with respect with the dimensions provided in the observation parameters -* @param {DynamicConfig} dynamic -* @param {ObservationConfig} observation -* @returns {DynamicConfig} -*/ - -module.exports = function (dynamic, observation) { - const timeStep = dynamic.timeStep || 1; - const observedProjection = observation.observedProjection; - const stateProjection = observation.stateProjection; - const observationDimension = observation.dimension; - let dimension; - - if (stateProjection && Number.isInteger(stateProjection[0].length / 2)) { - dimension = observation.stateProjection[0].length; - } else if (observedProjection) { - dimension = observedProjection[0].length * 2; - } else if (observationDimension) { - dimension = observationDimension * 2; - } else { - throw (new Error('observedProjection or stateProjection should be defined in observation in order to use constant-speed filter')); - } - - const baseDimension = dimension / 2; - // We construct the transition and covariance matrices - const transition = identity(dimension); - for (let i = 0; i < baseDimension; i++) { - transition[i][i + baseDimension] = timeStep; - } - - const arrayCovariance = new Array(baseDimension).fill(1).concat(new Array(baseDimension).fill(timeStep * timeStep)); - const covariance = dynamic.covariance || arrayCovariance; - return Object.assign({}, dynamic, {dimension, transition, covariance}); -}; - -},{"../linalgebra/identity.js":43}],39:[function(require,module,exports){ -const elemWise = require('./elem-wise'); -/** -* Add matrixes together -* @param {...>} args list of matrix -* @returns {Array.>} sum -*/ -module.exports = function (...args) { - return elemWise(args, args2 => { - return args2.reduce((a, b) => a + b, 0); - }); -}; - -},{"./elem-wise":42}],40:[function(require,module,exports){ -const zeros = require('./zeros'); - -module.exports = function (mat) { - const result = zeros(mat.length, mat.length); - - for (const [i, element] of mat.entries()) { - result[i][i] = element; - } - - return result; -}; - -},{"./zeros":51}],41:[function(require,module,exports){ -const trace = require('./trace.js'); -const transpose = require('./transpose.js'); -const matSub = require('./sub.js'); -const matMul = require('./mat-mul.js'); -const sum = require('./sum.js'); - -// [Frobenius norm](https://en.wikipedia.org/wiki/Matrix_norm#Frobenius_norm ) -module.exports = function (array1, array2) { - if (typeof (array1) === 'undefined') { - return sum(array2); - } - - if (typeof (array2) === 'undefined') { - return sum(array1); - } - - const m = matSub(array1, array2); - const p = matMul(transpose(m), m); - return Math.sqrt(trace(p)); -}; - -},{"./mat-mul.js":45,"./sub.js":47,"./sum.js":48,"./trace.js":49,"./transpose.js":50}],42:[function(require,module,exports){ -/** -* @callback elemWiseCb -* @param {Array.} arr -* @param {Number} rowId -* @param {Number} colId -*/ -/** -* run a function on cell per cell for each Matrixes -* @param {>>} arrMatrixes list of matrixes -* @param {elemWiseCb} fn -* @returns {Array.>} resulting matrix -* @example -// this will do m1 + m2 + m3 + m4 on matrixes -elemWise([m1, m2, m3, m4], args2 => { - return args2.reduce((a, b) => a + b, 0); -}); -*/ - -module.exports = function (arrayMatrixes, fn) { - return arrayMatrixes[0].map((row, rowId) => { - return row.map((cell, colId) => { - const array = arrayMatrixes.map(m => m[rowId][colId]); - return fn(array, rowId, colId); - }); - }); -}; - - -},{}],43:[function(require,module,exports){ -module.exports = function (stateSize) { - const identityArray = []; - for (let i = 0; i < stateSize; i++) { - const rowIdentity = []; - for (let j = 0; j < stateSize; j++) { - if (i === j) { - rowIdentity.push(1); - } else { - rowIdentity.push(0); - } - } - - identityArray.push(rowIdentity); - } - - return identityArray; -}; - -},{}],44:[function(require,module,exports){ -const matrixInverse = require('matrix-inverse'); - -module.exports = function (m) { - return matrixInverse(m); -}; - -},{"matrix-inverse":81}],45:[function(require,module,exports){ -/** -* Multiply 2 matrixes together -* @param {>} m1 -* @param {>} m2 -* @returns {Array.>} -*/ -module.exports = function (m1, m2) { - // Console.log({m1, m2}); - const result = []; - for (let i = 0; i < m1.length; i++) { - result[i] = []; - for (let j = 0; j < m2[0].length; j++) { - let sum = 0; - for (let k = 0; k < m1[0].length; k++) { - sum += m1[i][k] * m2[k][j]; - } - - result[i][j] = sum; - } - } - - return result; -}; - -},{}],46:[function(require,module,exports){ -/** -*This function returns the stateProjection paded with zeros with respect to a given -*observedProjection -*@param {Array. | Array.>} array the array we need to pad -*@param {Number} dimension in our case, the dynamic dimension -*@returns {Array. | Array.>} paded array -*/ -module.exports = function (array, {dimension}) { - const l = array[0].length; - if (dimension < l) { - throw (new TypeError('Dynamic dimension does not match with observedProjection')); - } - - for (let i = 0; i < l; i++) { - for (let j = 0; j < dimension - l; j++) { - array[i].push(0); - } - } - - return array; -}; - -},{}],47:[function(require,module,exports){ -const elemWise = require('./elem-wise'); - -module.exports = function (...args) { - return elemWise(args, ([a, b]) => a - b); -}; - -},{"./elem-wise":42}],48:[function(require,module,exports){ -// Sum all the terms of a given matrix -module.exports = function (array) { - let s = 0; - for (let i = 0; i < array.length; i++) { - for (let j = 0; j < array.length; j++) { - s += array[i][j]; - } - } - - return s; -}; - -},{}],49:[function(require,module,exports){ -module.exports = function (array) { - let diag = 0; - for (const [row, element] of array.entries()) { - diag += element[row]; - } - - return diag; -}; - -},{}],50:[function(require,module,exports){ -module.exports = function (array) { - return array[0].map((col, i) => array.map(row => row[i])); -}; - -},{}],51:[function(require,module,exports){ -module.exports = function (rows, cols) { - return new Array(rows).fill(1).map(() => new Array(cols).fill(0)); -}; - -},{}],52:[function(require,module,exports){ -const registeredDynamicModels = { - 'constant-position': require('../lib/dynamic/constant-position.js'), - 'constant-speed': require('../lib/dynamic/constant-speed.js'), - 'constant-acceleration': require('../lib/dynamic/constant-acceleration.js') -}; -const registeredObservationModels = { - sensors: require('../lib/observation/sensor.js') -}; - -/** -*RegisterObservation enables to create a new observation model and stock it -* @param {String} name -* @callback fn the function corresponding to the desired model -*/ - -/** -*registerDynamic enables to create a new dynamic model and stocks it -* @param {String} name -* @callback fn the function corresponding to the desired model -*/ - -/** -*buildObservation enables to build a model given an observation configuration -* @param {ObservationConfig} observation -* @returns {ObservationConfig} the configuration with respect to the model -*/ - -/** -*buildDynamic enables to build a model given dynamic and observation configurations -* @param {DynamicConfig} dynamic -* @param {ObservationConfig} observation -* @returns {DynamicConfig} the dynamic configuration with respect to the model -*/ - -module.exports = { - registerObservation: (name, fn) => { - registeredObservationModels[name] = fn; - }, - registerDynamic: (name, fn) => { - registeredDynamicModels[name] = fn; - }, - buildObservation: observation => { - if (!registeredObservationModels[observation.name]) { - throw (new Error('The provided observation model name is not registered')); - } - - return registeredObservationModels[observation.name](observation); - }, - buildDynamic: (dynamic, observation) => { - if (!registeredDynamicModels[dynamic.name]) { - throw (new Error('The provided dynamic model name is not registered')); - } - - return registeredDynamicModels[dynamic.name](dynamic, observation); - } -}; - -},{"../lib/dynamic/constant-acceleration.js":36,"../lib/dynamic/constant-position.js":37,"../lib/dynamic/constant-speed.js":38,"../lib/observation/sensor.js":53}],53:[function(require,module,exports){ -const identity = require('../linalgebra/identity.js'); -const polymorphMatrix = require('../utils/polymorph-matrix.js'); - -/** -* @param {Number} sensorDimension -* @param {CovarianceParam} sensorCovariance -* @param {Number} nSensors -* @returns {ObservationConfig} -*/ - -module.exports = function (options) { - const {sensorDimension = 1, sensorCovariance = 1, nSensors = 1} = options; - const sensorsCovariance = polymorphMatrix(sensorCovariance, {dimension: sensorDimension}); - const oneSensorObservedProjection = identity(sensorDimension); - let concatenatedObservedProjection = []; - let concatenatedCovariance = []; - for (let i = 0; i < nSensors; i++) { - concatenatedObservedProjection = concatenatedObservedProjection.concat(oneSensorObservedProjection); - concatenatedCovariance = concatenatedCovariance.concat(sensorsCovariance); - } - - const formattedCovariance = polymorphMatrix(concatenatedCovariance, {dimension: nSensors * sensorDimension}); - return Object.assign({}, options, { - dimension: sensorDimension * nSensors, - observedProjection: concatenatedObservedProjection, - covariance: formattedCovariance - }); -}; - -},{"../linalgebra/identity.js":43,"../utils/polymorph-matrix.js":62}],54:[function(require,module,exports){ -const padWithZeros = require('../linalgebra/pad-with-zeros.js'); -const identity = require('../linalgebra/identity.js'); -/** -*Builds the stateProjection given an observedProjection -*@param {ObservationConfig} observation -*@param {DynamicConfig} dynamic -*@returns {ObservationConfig, DynamicConfig} the model containing the created stateProjection -*/ - -module.exports = function ({observation, dynamic}) { - const {observedProjection, stateProjection} = observation; - const observationDimension = observation.dimension; - const dynamicDimension = dynamic.dimension; - if (observedProjection && stateProjection) { - throw (new TypeError('You cannot use both observedProjection and stateProjection')); - } - - if (observedProjection) { - return { - observation: Object.assign({}, observation, { - stateProjection: padWithZeros(observedProjection, {dimension: dynamicDimension}) - }), - dynamic - }; - } - - if (observationDimension && dynamicDimension) { - const observationMatrix = identity(observationDimension); - return { - observation: Object.assign({}, observation, { - stateProjection: padWithZeros(observationMatrix, {dimension: dynamicDimension}) - }), - dynamic - }; - } - - return {observation, dynamic}; -}; - -},{"../linalgebra/identity.js":43,"../linalgebra/pad-with-zeros.js":46}],55:[function(require,module,exports){ -/** -*Verifies that dynamic.dimension and observation.dimension are set -*@param {ObservationConfig} observation -*@param {DynamicConfig} dynamic -*/ - -module.exports = function ({observation, dynamic}) { - const dynamicDimension = dynamic.dimension; - const observationDimension = observation.dimension; - if (!dynamicDimension || !observationDimension) { - throw (new TypeError('Dimension is not set')); - } - - return {observation, dynamic}; -}; - -},{}],56:[function(require,module,exports){ -const diag = require('../linalgebra/diag.js'); - -/** -*Initializes the dynamic.init when not given -*@param {ObservationConfig} observation -*@param {DynamicConfig} dynamic -*@returns {ObservationConfig, DynamicConfig} -*/ - -module.exports = function ({observation, dynamic}) { - if (!dynamic.init) { - const huge = 1e6; - const dynamicDimension = dynamic.dimension; - const meanArray = new Array(dynamicDimension).fill(0); - const covarianceArray = new Array(dynamicDimension).fill(huge); - const withInitOptions = { - observation, - dynamic: Object.assign({}, dynamic, { - init: { - mean: meanArray.map(element => [element]), - covariance: diag(covarianceArray) - } - }) - }; - return withInitOptions; - } - - return {observation, dynamic}; -}; - -},{"../linalgebra/diag.js":40}],57:[function(require,module,exports){ -/** -*Verifies that dimensions are matching and set dynamic.dimension and observation.dimension -* with respect of stateProjection and transition dimensions -*@param {ObservationConfig} observation -*@param {DynamicConfig} dynamic -*@returns {ObservationConfig, DynamicConfig} -*/ - -module.exports = function ({observation, dynamic}) { - const stateProjection = observation.stateProjection; - const transition = dynamic.transition; - const dynamicDimension = dynamic.dimension; - const observationDimension = observation.dimension; - - if (dynamicDimension && observationDimension && Array.isArray(stateProjection)) { - if (dynamicDimension !== stateProjection[0].length || observationDimension !== stateProjection.length) { - throw (new TypeError('stateProjection dimensions not matching with observation and dynamic dimensions')); - } - } - - if (dynamicDimension && Array.isArray(transition)) { - if (dynamicDimension !== transition.length) { - throw (new TypeError('transition dimension not matching with dynamic dimension')); - } - } - - if (Array.isArray(stateProjection)) { - return { - observation: Object.assign({}, observation, { - dimension: stateProjection.length - }), - dynamic: Object.assign({}, dynamic, { - dimension: stateProjection[0].length - }) - }; - } - - if (Array.isArray(transition)) { - return { - observation, - dynamic: Object.assign({}, dynamic, { - dimension: transition.length - }) - }; - } - - return {observation, dynamic}; -}; - -},{}],58:[function(require,module,exports){ -const checkMatrix = function (matrix, shape) { - if (matrix.reduce((a, b) => a.concat(b)).filter(a => Number.isNaN(a)).length > 0) { - throw (new Error('Matrix should not have a NaN')); - } - - if (shape) { - checkShape(matrix, shape); - } -}; - -const checkShape = function (matrix, shape) { - if (matrix.length !== shape[0]) { - throw (new Error('shape and length do not match')); - } - - if (shape.length > 1) { - return matrix.forEach(m => checkShape(m, shape.slice(1))); - } -}; - -/** - * @class - * Class representing a multi dimensionnal gaussian, with his mean and his covariance - * @property {Number} [index=0] the index of the State in the process, this is not mandatory for simple Kalman Filter, but is needed for most of the use case of extended kalman filter - * @property {Array.>} covariance square matrix of size dimension - * @property {Array.>} mean column matrix of size dimension x 1 - */ -class State { - constructor({mean, covariance, index}) { - this.mean = mean; - this.covariance = covariance; - this.index = index; - } - - /** - * Check the consistency of the State - */ - check() { - this.constructor.check(this); - } - - /** - * Check the consistency of the State's attributes - */ - - static check(state, {dimension = null} = {}) { - if (!(state instanceof State)) { - throw (new TypeError('The argument is not a state')); - } - - const {mean, covariance} = state; // Index - const meanDimension = mean.length; - if (typeof (dimension) === 'number' && meanDimension !== dimension) { - throw (new Error(`${meanDimension} and ${dimension} are not the same`)); - } - - checkMatrix(mean, [meanDimension, 1]); - checkMatrix(covariance, [meanDimension, meanDimension]); - - // If (typeof (index) !== 'number') { - // throw (new TypeError('t must be a number')); - // } - } -} - -module.exports = State; - -},{}],59:[function(require,module,exports){ -/** -*Returns the corresponding matrix in dim*1, given an dim matrix, and checks -* if corresponding with the observation dimension -*@param {Array. | Array.>} observation -*@param {Number} dimension -*@returns {Array.>} -*/ - -module.exports = function ({observation, dimension}) { - if (!Array.isArray(observation)) { - throw (new TypeError('The observation should be an array')); - } - - if (observation.length !== dimension) { - throw (new TypeError('Observation and dimension not matching')); - } - - if (typeof (observation[0]) === 'number') { - return observation.map(element => [element]); - } - - return observation; -}; - -},{}],60:[function(require,module,exports){ -const uniq = require('./uniq.js'); -const limit = 100; - -/** -*Equivalent to the Object.assign methode, takes several arguments and creates a new object corresponding to the assignment of the arguments -* @param {Object} args -* @param {Number} step -*/ -const deepAssign = function (args, step) { - if (step > limit) { - throw (new Error(`In deepAssign, number of recursive call (${step}) reached limit (${limit}), deepAssign is not working on self-referencing objects`)); - } - - const filterArguments = args.filter(arg => typeof (arg) !== 'undefined' && arg !== null); - const lastArgument = filterArguments[filterArguments.length - 1]; - if (filterArguments.length === 1) { - return filterArguments[0]; - } - - if (typeof (lastArgument) !== 'object' || Array.isArray(lastArgument)) { - return lastArgument; - } - - if (filterArguments.length === 0) { - return null; - } - - const objectsArguments = filterArguments.filter(arg => typeof (arg) === 'object'); - let keys = []; - objectsArguments.forEach(arg => { - keys = keys.concat(Object.keys(arg)); - }); - const uniqKeys = uniq(keys); - const result = {}; - uniqKeys.forEach(key => { - const values = objectsArguments.map(arg => arg[key]); - result[key] = deepAssign(values, step + 1); - }); - return result; -}; - -module.exports = ((...args) => deepAssign(args, 0)); - -},{"./uniq.js":64}],61:[function(require,module,exports){ -/** -* @param {Object} opts -* @param {Array.>} opts.measures a list of measure, size is LxN L the number of sample, N the dimension -* @param {Array.>} opts.averages a list of averages, size is LxN L the number of sample, N the dimension -* @returns {Array.>} covariance matrix size is NxN -*/ - -module.exports = function ({measures, averages}) { - const l = measures.length; - const n = measures[0].length; - - if (l === 0) { - throw (new Error('Cannot find covariance for empty sample')); - } - - return (new Array(n).fill(1)).map((_, rowIndex) => { - return (new Array(n).fill(1)).map((_, colIndex) => { - const stds = measures.map((m, i) => (m[rowIndex] - averages[i][rowIndex]) * (m[colIndex] - averages[i][colIndex])); - const result = stds.reduce((a, b) => a + b) / l; - if (Number.isNaN(result)) { - throw (new TypeError('result is NaN')); - } - - return result; - }); - }); -}; - -},{}],62:[function(require,module,exports){ -/** -* @typedef {Number | Array. | Array.>} CovarianceParam -*/ -const diag = require('../linalgebra/diag'); -/** -* If cov is a number, result will be Identity*cov -* If cov is an Array., result will be diag(cov) -* If cov is an Array.>, result will be cov -* @param {CovarianceParam} cov -* @param {Number} dimension -* @returns {Array.>} -*/ -module.exports = function (array, {dimension} = {}) { - if (typeof (array) === 'number' || Array.isArray(array)) { - if (typeof (array) === 'number' && typeof (dimension) === 'number') { - return diag(new Array(dimension).fill(array)); - } - - if ((Array.isArray(array)) && (Array.isArray(array[0]))) { - return array; - } - - if ((Array.isArray(array)) && (typeof (array[0]) === 'number')) { - return diag(array); - } - } - - return array; -}; - -},{"../linalgebra/diag":40}],63:[function(require,module,exports){ -// Const diag = require('../linalgebra/diag.js'); - -/** -* @callback MatrixCallback -* @returns > -*/ - -/** -* Tranforms: -** a 2d array into a function (() => array) -** a 1d array into a function (() => diag(array)) -*@param {Array. | Array.>} array -*@returns {MatrixCallback} -*/ - -module.exports = function (array) { - if (typeof (array) === 'function') { - return array; - } - - if (Array.isArray(array)) { - return function () { - return array; - }; - } - - throw (new Error('Only arrays and functions are authorized')); -}; - -},{}],64:[function(require,module,exports){ -module.exports = function (array) { - return array.filter((value, index) => - array.indexOf(value) === index - ); -}; - -},{}],65:[function(require,module,exports){ -const Abstract = require('./lib/hasard/abstract'); -const Function = require('./lib/hasard/function'); -const operators = require('./lib/operators'); - -const cstrs = { - Integer: require('./lib/hasard/integer'), - Value: require('./lib/hasard/value'), - Array: require('./lib/hasard/array'), - Object: require('./lib/hasard/object'), - Number: require('./lib/hasard/number'), - Matrix: require('./lib/hasard/matrix'), - String: require('./lib/hasard/string'), - Boolean: require('./lib/hasard/boolean'), - Reference: require('./lib/hasard/reference'), - Function -}; - -const shortcuts = {}; -Object.keys(cstrs).forEach(key => { - shortcuts[key.toLowerCase()] = cstrs[key].build.bind(cstrs[key], this); -}); - -const helpers = { - isHasard: Abstract.isHasard, - fn: shortcuts.function, - int: shortcuts.integer, - num: shortcuts.number, - str: shortcuts.string, - ref: shortcuts.reference -}; - -const methods = function (hasardContext) { - return Object.assign({}, cstrs, shortcuts, operators(hasardContext), helpers); -}; - -class Hasard { - constructor(prng = Math.random.bind(Math)) { - this.prng = prng; - const meths = methods(this); - Object.keys(meths).forEach(m => { - this[m] = meths[m].bind(this); - }); - } -} - -module.exports = Object.assign(Hasard, methods(null)); - -},{"./lib/hasard/abstract":66,"./lib/hasard/array":67,"./lib/hasard/boolean":68,"./lib/hasard/function":69,"./lib/hasard/integer":70,"./lib/hasard/matrix":71,"./lib/hasard/number":72,"./lib/hasard/object":73,"./lib/hasard/reference":74,"./lib/hasard/string":75,"./lib/hasard/value":76,"./lib/operators":80}],66:[function(require,module,exports){ -const HasardReadableStream = require('../helpers/readable-stream.js'); - -class AbstractHasard { - constructor(...args) { - this._hasard = true; - if (args.length === 0) { - return; - } - - this.set(...args); - } - - set(opts) { - this._set = true; - this._opts = opts; - const all = this.getOpts(opts); - this._unresolved = {}; - this._resolved = {}; - if (opts && (typeof (opts.prng) === 'function')) { - this._prng = opts.prng.bind(opts); - } - - this._contextName = opts && opts.contextName; - Object.keys(all).forEach(k => { - if (AbstractHasard.isHasard(all[k])) { - this._unresolved[k] = all[k]; - } else { - this.check(k, all[k]); - this._resolved[k] = all[k]; - } - }); - } - - static build(hasardContext, ...args) { - const instance = new this(...args); - if (hasardContext && hasardContext.prng) { - hasardContext._prng = hasardContext.prng; - } - - return instance; - } - - prng() { - return this._prng ? this._prng() : Math.random(); - } - - static isHasard(o) { - return o && Boolean(o._hasard); - } - - runAsync(n) { - return Promise.resolve(this.run(n)); - } - - stream(number, runOpts) { - return new HasardReadableStream({ - hasardInstance: this, - number, - runOpts - }); - } - - resolve(unresolved, runOpts) { - const ctxt = {}; - if (typeof (unresolved) === 'undefined') { - throw (new TypeError('This instance of hasard has not been set properly')); - } - - Object.keys(unresolved).forEach(k => { - ctxt[k] = unresolved[k].runOnce(runOpts); - this.check(k, ctxt[k]); - }); - return ctxt; - } - - _runOnce(runOpts) { - const ctxt = Object.assign({}, this.resolve(this._unresolved, runOpts), this._resolved); - - const res = this.generate(ctxt, runOpts); - if (this._contextName && runOpts.refs && runOpts.refs[this._contextName]) { - delete runOpts.refs[this._contextName]; - } - - return res; - } - - run(n, runOpts) { - const res = []; - for (let i = 0; i < n; i++) { - res.push(this.runOnce(runOpts)); - } - - return res; - } - - runOnce(runOpts = {}) { - return this._runOnce(runOpts); - } - - generate() { - throw (new Error('override me')); - } - - getOpts(opts) { - delete opts.prng; - return opts; - } - - check() { - // Do nothing, override me to do sthg - } -} - -module.exports = AbstractHasard; - -},{"../helpers/readable-stream.js":77}],67:[function(require,module,exports){ -const AbstractHasard = require('./abstract'); - -class ArrayHasard extends AbstractHasard { - check(key, value) { - if (key === 'values' && value !== null && typeof (value) !== 'undefined') { - if (!Array.isArray(value)) { - throw (new TypeError(`${key} ${value} must be an array`)); - } - } - } - - resolve(unresolved, runOpts) { - // Do not resolve "value" here, it will be resolved in generate - const overrideUnresolved = Object.assign({}, unresolved); - delete overrideUnresolved.value; - - return Object.assign(super.resolve(overrideUnresolved, runOpts), {value: unresolved.value}); - } - - getOpts(opts) { - let values = null; - let size; - let value; - let randomOrder; - if (Array.isArray(opts)) { - values = opts; - size = values.length; - value = null; - randomOrder = false; - } else { - size = opts.size; - values = opts.values; - value = opts.value; - randomOrder = opts.randomOrder; - } - - return { - size, - value, - values, - randomOrder - }; - } - - generate(ctx, runOpts) { - if (ArrayHasard.isHasard(ctx.value)) { - return new Array(ctx.size).fill(1).map(() => ctx.value.runOnce(runOpts)); - } - - if (ctx.values) { - let newValues; - - if (typeof (ctx.size) === 'number' || ctx.randomOrder) { - const size = typeof (ctx.size) === 'number' ? ctx.size : ctx.values.length; - - if (size > ctx.values.length) { - throw (new Error(`Cannot pick ${size} elements in ${ctx.values.length}-size array`)); - } - - let selectedObjs = ctx.values - .map((v, i) => ({strength: this.prng(), value: v, index: i})) - .sort((a, b) => a.strength - b.strength) - .slice(0, size); - - if (!ctx.randomOrder) { - selectedObjs = selectedObjs.sort((a, b) => a.index - b.index); - } - - newValues = selectedObjs.map(({value}) => value); - } else { - newValues = ctx.values; - } - - return newValues.map(v => { - if (ArrayHasard.isHasard(v)) { - const res = v.runOnce(runOpts); - return res; - } - - return v; - }); - } - - return new Array(ctx.size).fill(1).map(() => ctx.value); - } -} - -module.exports = ArrayHasard; - -},{"./abstract":66}],68:[function(require,module,exports){ -const AbstractHasard = require('./abstract'); - -class BooleanHasard extends AbstractHasard { - constructor(...args) { - super(...args); - if (args.length === 0) { - return this.set(0.5); - } - - this.set(...args); - } - - check(key, value) { - if (key === 'prob') { - if (typeof (value) !== 'number') { - throw (new TypeError(`${key} ${value} must be a number`)); - } - - if (value < 0 || value > 1) { - throw (new Error(`${key} ${value} must be between 0 and 1`)); - } - } - } - - getOpts(prob = 0.5) { - return { - prob - }; - } - - generate(ctx) { - if (typeof (ctx.prob) !== 'number') { - return (this.prng() > 0.5); - } - - return (this.prng() < ctx.prob); - } -} - -module.exports = BooleanHasard; - -},{"./abstract":66}],69:[function(require,module,exports){ -const AbstractHasard = require('./abstract'); -const RandomArray = require('./array'); - -class FunctionHasard extends AbstractHasard { - check(key, value) { - if (key === 'fn') { - if (typeof (value) !== 'function') { - throw (new TypeError(`${key} ${value} must be a function`)); - } - } - - if (key === 'args') { - if (value && !Array.isArray(value)) { - throw (new TypeError(`${key} ${value} must be an array`)); - } - } - } - - getOpts({args, fn}) { - return { - args, - fn - }; - } - - generate(ctx) { - return ctx.fn(...ctx.args); - } - - static build(hasardContext, fn) { - return function (...args) { - const f = new FunctionHasard({args: new RandomArray(args), fn}); - if (hasardContext && hasardContext.prng) { - f._prng = hasardContext.prng; - } - - return f; - }; - } -} - -module.exports = FunctionHasard; - -},{"./abstract":66,"./array":67}],70:[function(require,module,exports){ -const AbstractHasard = require('./abstract'); - -class IntegerHasard extends AbstractHasard { - check(key, value) { - if (key === 'start' || key === 'end') { - if (Math.floor(value) !== value) { - throw (new TypeError(`${key} (${value}) must be an integer`)); - } - } - - if (key === 'type' && ['poisson', 'uniform'].indexOf(value) === -1) { - throw (new TypeError(`${key} ${value} is invalid`)); - } - } - - set(start, end) { - if (typeof (end) === 'undefined') { - super.set(start); - } else if (typeof (end) === 'number' || this.constructor.isHasard(end)) { - super.set([start, end]); - } else { - throw (new Error(`second argument ${end} is not valid`)); - } - } - - getOpts(opts) { - if (Array.isArray(opts)) { - if (opts.length !== 2) { - throw (new TypeError(`${opts} must be a length-2 array`)); - } - - const start = opts[0]; - const end = opts[1]; - return { - start, - end, - type: 'uniform' - }; - } - - return opts; - } - - generate(ctx) { - if (ctx.type === 'poisson') { - const l = Math.exp(-ctx.lambda); - let p = 1; - let k = 0; - - do { - k++; - p *= this.prng(); - } while (p > l); - - return k - 1; - } - - return Math.floor(ctx.start + (this.prng() * (ctx.end + 1 - ctx.start))); - } -} - -module.exports = IntegerHasard; - -},{"./abstract":66}],71:[function(require,module,exports){ -const reshape = require('../helpers/reshape'); -const ArrayHasard = require('./array'); - -const fact = function (array) { - if (array.length === 0) { - return 1; - } - - return array[0] * fact(array.slice(1)); -}; - -class MatrixHasard extends ArrayHasard { - check(key, value) { - super.check(key, value); - if (key === 'shape') { - if (!Array.isArray(value)) { - throw (new TypeError(`${key} (${value}) must be an array`)); - } - - if (value.length === 0) { - throw (new Error(`${key} (${value}) should not be empty`)); - } - - value.forEach(v => { - if (Math.floor(v) !== v) { - throw (new Error(`${key} (${v}) must be an integer`)); - } - }); - } - } - - getOpts(opts) { - return Object.assign({}, super.getOpts(opts), {shape: opts.shape}); - } - - generate(ctx, runOpts) { - const size = fact(ctx.shape); - const ctx2 = Object.assign({}, ctx, {size}); - const resArray = super.generate(ctx2, runOpts); - return reshape(resArray, [size], ctx.shape); - } -} - -module.exports = MatrixHasard; - -},{"../helpers/reshape":79,"./array":67}],72:[function(require,module,exports){ -const AbstractHasard = require('./abstract'); - -class NumberHasard extends AbstractHasard { - check(key, value) { - if (key === 'start' || key === 'end') { - if (typeof (value) !== 'number') { - throw (new TypeError(`${key} (${value}) must be a number`)); - } - } - - if (key === 'type' && ['normal', 'uniform', 'truncated-normal'].indexOf(value) === -1) { - throw (new TypeError(`${key} ${value} is invalid`)); - } - } - - set(start, end) { - if (typeof (end) === 'undefined') { - super.set(start); - } else if (typeof (end) === 'number' || this.constructor.isHasard(end)) { - super.set([start, end]); - } else { - throw (new Error(`second argument ${end} is not valid`)); - } - } - - getOpts(opts) { - let res = opts; - - if (Array.isArray(opts)) { - if (opts.length !== 2) { - throw (new TypeError('invalid array, range array length must be 2')); - } - - res = { - type: 'uniform', - start: opts[0], - end: opts[1] - }; - } else { - res = opts; - } - - return res; - } - - _pickNormalNumber(mean = 0, std = 1) { - // From http://blog.yjl.im/2010/09/simulating-normal-random-variable-using.html - - let v1; - let v2; - let s; - - do { - const u1 = this.prng(); - const u2 = this.prng(); - v1 = (2 * u1) - 1; - v2 = (2 * u2) - 1; - s = (v1 * v1) + (v2 * v2); - } while (s > 1); - - return mean + (std * Math.sqrt(-2 * Math.log(s) / s) * v1); - } - - generate(ctx) { - if (ctx.type === 'uniform') { - return ctx.start + (this.prng() * (ctx.end - ctx.start)); - } - - if (ctx.type === 'normal') { - const mean = ctx.mean || 0; - const std = ctx.std || 1; - return this._pickNormalNumber(mean, std); - } - - if (ctx.type === 'truncated-normal') { - const mean = ctx.mean || 0; - const std = ctx.std || 1; - let n; - do { - n = this._pickNormalNumber(mean, std); - } while ((n > mean + (2 * std)) || (n < mean - (2 * std))); - - return n; - } - - throw (new Error(`type ${ctx.type} is invalid`)); - } -} - -module.exports = NumberHasard; - -},{"./abstract":66}],73:[function(require,module,exports){ -const AbstractHasard = require('./abstract'); - -class ObjectHasard extends AbstractHasard { - set(keys, value) { - if (ObjectHasard.isHasard(keys) || Array.isArray(keys)) { - if (typeof (value) === 'undefined') { - throw (new TypeError('h.object(keys, value) should have a value param')); - } - - super.set(Object.assign({}, {__hasardKeys: keys, __hasardValue: value})); - } else if (typeof (keys) === 'object') { - super.set(Object.assign({}, keys)); - } else { - throw (new TypeError('invalid params for h.object')); - } - } - - check(key, value) { - if (key === '__hasardKeys' && value !== null && typeof (value) !== 'undefined') { - const k = 'keys'; - if (!Array.isArray(value)) { - throw (new TypeError(`${k} ${value} must be an array`)); - } - - value.forEach((v, index) => { - // Check unicity - if (value.indexOf(v) !== index) { - throw (new TypeError(`keys must be unique (${k}[${index}] '${v}' is duplicated)`)); - } - - // Check string type - if (typeof (v) !== 'string') { - throw (new TypeError(`keys must be string array (${k}[${index}] '${v}' should be a string)`)); - } - }); - } - } - - getOpts(opts) { - const res = Object.assign({}, opts, {__hasardKeys: opts.__hasardKeys, __hasardValue: opts.__hasardValue}); - return res; - } - - resolve(unresolved, runOpts) { - // Do not resolve "value" here, it will be resolved in generate - const overrideUnresolved = Object.assign({}, unresolved); - delete overrideUnresolved.__hasardValue; - const res = Object.assign(super.resolve(overrideUnresolved, runOpts), {__hasardValue: unresolved.__hasardValue}); - return res; - } - - generate(ctx, runOpts) { - if (ctx.__hasardKeys) { - // Console.log('here', ctx, this.constructor.isHasard(ctx.__hasardValue), ctx.__hasardValue) - let values; - if (this.constructor.isHasard(ctx.__hasardValue)) { - values = ctx.__hasardValue.run(ctx.__hasardKeys.length, runOpts); - } else { - values = new Array(ctx.__hasardKeys.length).fill(ctx.__hasardValue); - } - - const res = {}; - ctx.__hasardKeys.forEach((k, index) => { - res[k] = values[index]; - }); - return res; - } - - delete ctx.__hasardKeys; - delete ctx.__hasardValue; - return ctx; - } -} - -module.exports = ObjectHasard; - -},{"./abstract":66}],74:[function(require,module,exports){ -const AbstractHasard = require('./abstract'); -const RandomString = require('./string'); -const RandomValue = require('./value'); - -class ReferenceHasard extends AbstractHasard { - resolve(unresolved, runOpts) { - // Do not resolve "source" here, it will be resolved in generate - const overrideUnresolved = Object.assign({}, unresolved); - delete overrideUnresolved.source; - - return Object.assign(super.resolve(overrideUnresolved, runOpts), {source: unresolved.source}); - } - - generate({id, context, source}, runOpts) { - if (!this.constructor.isHasard(source)) { - return source; - } - - const ctx = typeof (context) === 'string' ? context : 'global'; - - if (!runOpts.refs || !runOpts.refs[ctx] || typeof (runOpts.refs[ctx][id]) === 'undefined') { - const res = source.runOnce(runOpts); - if (!runOpts.refs) { - runOpts.refs = {}; - } - - if (!runOpts.refs[ctx]) { - runOpts.refs[ctx] = {}; - } - - runOpts.refs[ctx][id] = res; - return res; - } - - return runOpts.refs[ctx][id]; - } - - check(key, value) { - if (key === 'context' && value !== null && typeof (value) !== 'undefined') { - if (typeof (value) !== 'string') { - throw (new TypeError(`${key} (${value}) must be a string`)); - } - } - } - - getOpts(opts) { - const randomString = new RandomString({ - value: new RandomValue('0123456789ABCDEF'.split('')), - size: 16 - }); - let source; - let context; - if (AbstractHasard.isHasard(opts)) { - source = opts; - context = null; - } else if (typeof (opts) === 'object') { - source = opts.source; - context = opts.context; - } else { - source = opts; - context = null; - } - - return { - source, - context, - id: randomString.runOnce() - }; - } -} - -module.exports = ReferenceHasard; - -},{"./abstract":66,"./string":75,"./value":76}],75:[function(require,module,exports){ -const ArrayHasard = require('./array'); - -class StringHasard extends ArrayHasard { - generate(ctx, runOpts) { - return super.generate(ctx, runOpts).join(''); - } -} - -module.exports = StringHasard; - -},{"./array":67}],76:[function(require,module,exports){ -const AbstractHasard = require('./abstract'); - -const getRanges = function (array) { - const res = []; - let current = 0; - array.forEach(v => { - res.push([current, current + v]); - current += v; - }); - return res; -}; - -class ValueHasard extends AbstractHasard { - check(key, value) { - if (key === 'weights' && Array.isArray(value)) { - const sum = value.reduce((a, b) => a + b, 0); - const tolerance = 1e-6; - if (Math.abs(sum - 1) > tolerance) { - throw (new Error(`sum of weights must be 1 (is ${sum})`)); - } - } - } - - getOpts(opts) { - let choices; - - if (Array.isArray(opts)) { - choices = opts; - } else if (AbstractHasard.isHasard(opts)) { - choices = opts; - } else { - choices = opts.choices; - } - - const {weights} = opts; - - return { - choices, - weights - }; - } - - generate(ctx) { - let choice; - - if (ctx.weights) { - if (!Array.isArray(ctx.choices)) { - throw (new TypeError('choices must be defined in h.value')); - } - - const ranges = getRanges(ctx.weights); - const v = this.prng(); - const {index} = ranges.map((value, index) => ({value, index})).filter(({value}) => (value[0] <= v && v < value[1]))[0]; - choice = ctx.choices[index]; - } else { - choice = ctx.choices[Math.floor(this.prng() * ctx.choices.length)]; - } - - if (this.constructor.isHasard(choice)) { - return choice.runOnce(); - } - - return choice; - } -} - -module.exports = ValueHasard; - -},{"./abstract":66}],77:[function(require,module,exports){ -(function (setImmediate){ -const {Readable} = require('stream'); - -class HasardReadableStream extends Readable { - constructor(options) { - options.objectMode = true; - super(options); - const { - hasardInstance, - number, - runOpts - } = options; - - this._hasardInstance = hasardInstance; - this._end = number; - this._runOpts = runOpts; - this._curr = 0; - } - - _read() { - setImmediate(() => { - const res = this._hasardInstance.runOnce(this._runOpts); - const obj = Object.assign({}, res, {index: this._curr}); - this.push(obj); - this._curr++; - if (this._curr === this._end) { - this.push(null); - } - }); - } -} - -module.exports = HasardReadableStream; - -}).call(this,require("timers").setImmediate) -},{"stream":31,"timers":32}],78:[function(require,module,exports){ -const recursiveEach = function (array, inShape, fn, index = 0) { - if (Array.isArray(array) && inShape.length > 0) { - const size = array.length; - array.forEach((item, indexLocal) => { - recursiveEach(item, inShape.slice(1), fn, (index * size) + indexLocal); - }); - } else { - fn(array, index); - } -}; - -module.exports = recursiveEach; - -},{}],79:[function(require,module,exports){ -const recursiveEach = require('./recursive-each'); - -module.exports = function (arr, inShape, outShape) { - const newArr = []; - const reverseShape = outShape.concat([]).reverse(); - recursiveEach(arr, inShape, (item, index) => { - let remIndex = index; - const indexes = []; - - reverseShape.forEach(s => { - const previousRem = remIndex; - remIndex = Math.floor(remIndex / s); - indexes.unshift(previousRem - (remIndex * s)); - }); - let current = newArr; - indexes.slice(0, -1).forEach(index => { - if (!current[index]) { - current[index] = []; - } - - current = current[index]; - }); - current[indexes[indexes.length - 1]] = item; - }); - return newArr; -}; - -},{"./recursive-each":78}],80:[function(require,module,exports){ -const Hfunction = require('./hasard/function'); - -module.exports = function (hasardContext) { - const fn = Hfunction.build.bind(Hfunction, hasardContext); - return { - multiply: fn((...args) => args.reduce((a, b) => a * b, 1)), - divide: fn((a, b) => a / b), - add: fn((...args) => args.reduce((a, b) => a + b)), - substract: fn((a, b) => a - b), - if: fn((condition, iftrue, iffalse) => condition ? iftrue : iffalse), - round: fn(n => Math.round(n)), - ceil: fn(n => Math.ceil(n)), - floor: fn(n => Math.floor(n)), - concat: fn((a, b) => a.concat(b)), - getProperty: fn((key, obj) => obj[key]) - }; -}; - -},{"./hasard/function":69}],81:[function(require,module,exports){ -var Sylvester = {} - -Sylvester.Matrix = function() {} - -Sylvester.Matrix.create = function(elements) { - var M = new Sylvester.Matrix() - return M.setElements(elements) -} - -Sylvester.Matrix.I = function(n) { - var els = [], - i = n, - j - while (i--) { - j = n - els[i] = [] - while (j--) { - els[i][j] = i === j ? 1 : 0 - } - } - return Sylvester.Matrix.create(els) -} - -Sylvester.Matrix.prototype = { - dup: function() { - return Sylvester.Matrix.create(this.elements) - }, - - isSquare: function() { - var cols = this.elements.length === 0 ? 0 : this.elements[0].length - return this.elements.length === cols - }, - - toRightTriangular: function() { - if (this.elements.length === 0) return Sylvester.Matrix.create([]) - var M = this.dup(), - els - var n = this.elements.length, - i, - j, - np = this.elements[0].length, - p - for (i = 0; i < n; i++) { - if (M.elements[i][i] === 0) { - for (j = i + 1; j < n; j++) { - if (M.elements[j][i] !== 0) { - els = [] - for (p = 0; p < np; p++) { - els.push(M.elements[i][p] + M.elements[j][p]) - } - M.elements[i] = els - break - } - } - } - if (M.elements[i][i] !== 0) { - for (j = i + 1; j < n; j++) { - var multiplier = M.elements[j][i] / M.elements[i][i] - els = [] - for (p = 0; p < np; p++) { - // Elements with column numbers up to an including the number of the - // row that we're subtracting can safely be set straight to zero, - // since that's the point of this routine and it avoids having to - // loop over and correct rounding errors later - els.push( - p <= i ? 0 : M.elements[j][p] - M.elements[i][p] * multiplier - ) - } - M.elements[j] = els - } - } - } - return M - }, - - determinant: function() { - if (this.elements.length === 0) { - return 1 - } - if (!this.isSquare()) { - return null - } - var M = this.toRightTriangular() - var det = M.elements[0][0], - n = M.elements.length - for (var i = 1; i < n; i++) { - det = det * M.elements[i][i] - } - return det - }, - - isSingular: function() { - return this.isSquare() && this.determinant() === 0 - }, - - augment: function(matrix) { - if (this.elements.length === 0) { - return this.dup() - } - var M = matrix.elements || matrix - if (typeof M[0][0] === 'undefined') { - M = Sylvester.Matrix.create(M).elements - } - var T = this.dup(), - cols = T.elements[0].length - var i = T.elements.length, - nj = M[0].length, - j - if (i !== M.length) { - return null - } - while (i--) { - j = nj - while (j--) { - T.elements[i][cols + j] = M[i][j] - } - } - return T - }, - - inverse: function() { - if (this.elements.length === 0) { - return null - } - if (!this.isSquare() || this.isSingular()) { - return null - } - var n = this.elements.length, - i = n, - j - var M = this.augment(Sylvester.Matrix.I(n)).toRightTriangular() - var np = M.elements[0].length, - p, - els, - divisor - var inverse_elements = [], - new_element - // Sylvester.Matrix is non-singular so there will be no zeros on the - // diagonal. Cycle through rows from last to first. - while (i--) { - // First, normalise diagonal elements to 1 - els = [] - inverse_elements[i] = [] - divisor = M.elements[i][i] - for (p = 0; p < np; p++) { - new_element = M.elements[i][p] / divisor - els.push(new_element) - // Shuffle off the current row of the right hand side into the results - // array as it will not be modified by later runs through this loop - if (p >= n) { - inverse_elements[i].push(new_element) - } - } - M.elements[i] = els - // Then, subtract this row from those above it to give the identity matrix - // on the left hand side - j = i - while (j--) { - els = [] - for (p = 0; p < np; p++) { - els.push(M.elements[j][p] - M.elements[i][p] * M.elements[j][i]) - } - M.elements[j] = els - } - } - return Sylvester.Matrix.create(inverse_elements) - }, - - setElements: function(els) { - var i, - j, - elements = els.elements || els - if (elements[0] && typeof elements[0][0] !== 'undefined') { - i = elements.length - this.elements = [] - while (i--) { - j = elements[i].length - this.elements[i] = [] - while (j--) { - this.elements[i][j] = elements[i][j] - } - } - return this - } - var n = elements.length - this.elements = [] - for (i = 0; i < n; i++) { - this.elements.push([elements[i]]) - } - return this - }, -} - -module.exports = function(elements) { - return Sylvester.Matrix.create(elements).inverse().elements -} - -},{}],"KalmanFilter":[function(require,module,exports){ -const CoreKalmanFilter = require('./core-kalman-filter.js'); - -const arrayToMatrix = require('../lib/utils/array-to-matrix.js'); -const setDimensions = require('../lib/setup/set-dimensions.js'); -const checkDimensions = require('../lib/setup/check-dimensions.js'); -const buildStateProjection = require('../lib/setup/build-state-projection.js'); -const extendDynamicInit = require('../lib/setup/extend-dynamic-init.js'); -const modelCollection = require('./model-collection.js'); -const toFunction = require('../lib/utils/to-function.js'); -const deepAssign = require('../lib/utils/deep-assign.js'); -const polymorphMatrix = require('../lib/utils/polymorph-matrix.js'); -const State = require('./state.js'); -const distanceMat = require('../lib/linalgebra/distance-mat.js'); - -/** -*This function fills the given options by successively checking if it uses a registered model, -* it builds and checks the dynamic and observation dimensions, build the stateProjection if only observedProjection -*is given, and initialize dynamic.init -*@param {DynamicConfig} options.dynamic -*@param {ObservationConfig} options.observation -*/ - -const setupModelsParameters = function ({observation, dynamic}) { - if (typeof (observation.name) === 'string') { - observation = modelCollection.buildObservation(observation); - } - - if (typeof (dynamic.name) === 'string') { - dynamic = modelCollection.buildDynamic(dynamic, observation); - } - - const withDimensionOptions = setDimensions({observation, dynamic}); - const checkedDimensionOptions = checkDimensions(withDimensionOptions); - const buildStateProjectionOptions = buildStateProjection(checkedDimensionOptions); - return extendDynamicInit(buildStateProjectionOptions); -}; - -/** -*Returns the corresponding model without arrays as values but only functions -*@param {ObservationConfig} observation -*@param {DynamicConfig} dynamic -*@returns {ObservationConfig, DynamicConfig} model with respect of the Core Kalman Filter properties -*/ -const modelsParametersToCoreOptions = function (modelToBeChanged) { - const {observation, dynamic} = modelToBeChanged; - return deepAssign(modelToBeChanged, { - observation: { - stateProjection: toFunction(polymorphMatrix(observation.stateProjection)), - covariance: toFunction(polymorphMatrix(observation.covariance, {dimension: observation.dimension})) - }, - dynamic: { - transition: toFunction(polymorphMatrix(dynamic.transition)), - covariance: toFunction(polymorphMatrix(dynamic.covariance, {dimension: dynamic.dimension})) - } - }); -}; - -class KalmanFilter extends CoreKalmanFilter { - /** - * @param {DynamicConfig} options.dynamic - * @param {ObservationConfig} options.observation the system's observation model - */ - constructor(options) { - const modelsParameters = setupModelsParameters(options); - const coreOptions = modelsParametersToCoreOptions(modelsParameters); - - super(Object.assign({}, options, coreOptions)); - } - - correct({predicted, observation}) { - const coreObservation = arrayToMatrix({observation, dimension: this.observation.dimension}); - return super.correct({predicted, observation: coreObservation}); - } - - /** - *Performs the prediction and the correction steps - *@param {State} previousCorrected - *@param {>} observation - *@returns {Array.} the mean of the corrections - */ - - filter({previousCorrected, observation}) { - const predicted = super.predict({previousCorrected}); - return this.correct({predicted, observation}); - } - - /** -*Filters all the observations -*@param {Array.>} observations -*@returns {Array.} the mean of the corrections -*/ - filterAll(observations) { - const {mean: meanInit, covariance: covarianceInit, index: indexInit} = this.dynamic.init; - let previousCorrected = new State({ - mean: meanInit, - covariance: covarianceInit, - index: indexInit}); - const results = []; - for (const observation of observations) { - const predicted = this.predict({previousCorrected}); - previousCorrected = this.correct({ - predicted, - observation - }); - results.push(previousCorrected.mean); - } - - return results; - } - - /** - * Returns an estimation of the asymptotic state covariance as explained in https://en.wikipedia.org/wiki/Kalman_filter#Asymptotic_form - * in practice this can be used as a init.covariance value but is very costful calculation (that's why this is not made by default) - * @param {Number} [tolerance=1e-6] returns when the last values differences are less than tolerance - * @return {>>} covariance - */ - asymptoticStateCovariance(limitIterations = 1e2, tolerance = 1e-6) { - let previousCorrected = super.getInitState(); - let predicted; - const results = []; - for (let i = 0; i < limitIterations; i++) { - let count = 0; - predicted = new State({covariance: super.getPredictedCovariance({previousCorrected})}); - previousCorrected = new State({covariance: super.getCorrectedCovariance({predicted})}); - results.push(previousCorrected.covariance); - for (let j = 1; j < 4; j++) { - if (distanceMat(previousCorrected.covariance, results[i - j]) < tolerance) { - count += 1; - } - } - - if (count === 3) { - return results[i]; - } - } - - throw (new Error('The state covariance does not converge asymptotically')); - } - - /** - * Returns an estimation of the asymptotic gain, as explained in https://en.wikipedia.org/wiki/Kalman_filter#Asymptotic_form - * @param {Number} [tolerance=1e-6] returns when the last values differences are less than tolerance - * @return {>>} gain - */ - asymptoticGain(tolerance = 1e-6) { - const asymptoticState = new State({covariance: this.asymptoticStateCovariance(tolerance)}); - return super.getGain({previousCorrected: asymptoticState}); - } -} - -module.exports = KalmanFilter; - -},{"../lib/linalgebra/distance-mat.js":41,"../lib/setup/build-state-projection.js":54,"../lib/setup/check-dimensions.js":55,"../lib/setup/extend-dynamic-init.js":56,"../lib/setup/set-dimensions.js":57,"../lib/utils/array-to-matrix.js":59,"../lib/utils/deep-assign.js":60,"../lib/utils/polymorph-matrix.js":62,"../lib/utils/to-function.js":63,"./core-kalman-filter.js":35,"./model-collection.js":52,"./state.js":58}],"calculateObservationCovariance":[function(require,module,exports){ -const generateNoisyObservation = require('./generate-noisy-observation.js'); -const getCovariance = require('../../lib/utils/get-covariance.js'); - -const calculateObservationCovariance = function ({groundTruths, rangeNoise = 10, numberRun = 1}) { - const noisyMatrixes = generateNoisyObservation({groundTruths, rangeNoise, numberRun}); - return noisyMatrixes.map(noisyMatrix => getCovariance({measures: noisyMatrix, averages: groundTruths})); -}; - -module.exports = calculateObservationCovariance; - -},{"../../lib/utils/get-covariance.js":61,"./generate-noisy-observation.js":"generateNoisyObservation"}],"generateNoisyObservation":[function(require,module,exports){ -const h = require('hasard'); -const elemWise = require('../../lib/linalgebra/elem-wise.js'); - -const generateNoisyObservation = function ({groundTruths, rangeNoise = 10, numberRun = 1}) { - const hasardNoise = h.matrix({ - shape: [groundTruths.length, groundTruths[0].length], - value: h.integer(-rangeNoise, rangeNoise) - }); - const combinedMatrix = h.fn((noise, gT) => { - return elemWise([noise, gT], ([n, gTCell]) => n + gTCell); - })(hasardNoise, groundTruths); - return combinedMatrix.run(numberRun); -}; - -module.exports = generateNoisyObservation; -// Console.log('Noisy observation', generateNoiseMatrix({groundTruths: demoGroundTruths})) - -},{"../../lib/linalgebra/elem-wise.js":42,"hasard":65}],"url":[function(require,module,exports){ -// Copyright Joyent, Inc. and other Node contributors. -// -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and associated documentation files (the -// "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, -// distribute, sublicense, and/or sell copies of the Software, and to permit -// persons to whom the Software is furnished to do so, subject to the -// following conditions: -// -// The above copyright notice and this permission notice shall be included -// in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN -// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE -// USE OR OTHER DEALINGS IN THE SOFTWARE. - -'use strict'; - -var punycode = require('punycode'); -var util = require('./util'); - -exports.parse = urlParse; -exports.resolve = urlResolve; -exports.resolveObject = urlResolveObject; -exports.format = urlFormat; - -exports.Url = Url; - -function Url() { - this.protocol = null; - this.slashes = null; - this.auth = null; - this.host = null; - this.port = null; - this.hostname = null; - this.hash = null; - this.search = null; - this.query = null; - this.pathname = null; - this.path = null; - this.href = null; -} - -// Reference: RFC 3986, RFC 1808, RFC 2396 - -// define these here so at least they only have to be -// compiled once on the first module load. -var protocolPattern = /^([a-z0-9.+-]+:)/i, - portPattern = /:[0-9]*$/, - - // Special case for a simple path URL - simplePathPattern = /^(\/\/?(?!\/)[^\?\s]*)(\?[^\s]*)?$/, - - // RFC 2396: characters reserved for delimiting URLs. - // We actually just auto-escape these. - delims = ['<', '>', '"', '`', ' ', '\r', '\n', '\t'], - - // RFC 2396: characters not allowed for various reasons. - unwise = ['{', '}', '|', '\\', '^', '`'].concat(delims), - - // Allowed by RFCs, but cause of XSS attacks. Always escape these. - autoEscape = ['\''].concat(unwise), - // Characters that are never ever allowed in a hostname. - // Note that any invalid chars are also handled, but these - // are the ones that are *expected* to be seen, so we fast-path - // them. - nonHostChars = ['%', '/', '?', ';', '#'].concat(autoEscape), - hostEndingChars = ['/', '?', '#'], - hostnameMaxLen = 255, - hostnamePartPattern = /^[+a-z0-9A-Z_-]{0,63}$/, - hostnamePartStart = /^([+a-z0-9A-Z_-]{0,63})(.*)$/, - // protocols that can allow "unsafe" and "unwise" chars. - unsafeProtocol = { - 'javascript': true, - 'javascript:': true - }, - // protocols that never have a hostname. - hostlessProtocol = { - 'javascript': true, - 'javascript:': true - }, - // protocols that always contain a // bit. - slashedProtocol = { - 'http': true, - 'https': true, - 'ftp': true, - 'gopher': true, - 'file': true, - 'http:': true, - 'https:': true, - 'ftp:': true, - 'gopher:': true, - 'file:': true - }, - querystring = require('querystring'); - -function urlParse(url, parseQueryString, slashesDenoteHost) { - if (url && util.isObject(url) && url instanceof Url) return url; - - var u = new Url; - u.parse(url, parseQueryString, slashesDenoteHost); - return u; -} - -Url.prototype.parse = function(url, parseQueryString, slashesDenoteHost) { - if (!util.isString(url)) { - throw new TypeError("Parameter 'url' must be a string, not " + typeof url); - } - - // Copy chrome, IE, opera backslash-handling behavior. - // Back slashes before the query string get converted to forward slashes - // See: https://code.google.com/p/chromium/issues/detail?id=25916 - var queryIndex = url.indexOf('?'), - splitter = - (queryIndex !== -1 && queryIndex < url.indexOf('#')) ? '?' : '#', - uSplit = url.split(splitter), - slashRegex = /\\/g; - uSplit[0] = uSplit[0].replace(slashRegex, '/'); - url = uSplit.join(splitter); - - var rest = url; - - // trim before proceeding. - // This is to support parse stuff like " http://foo.com \n" - rest = rest.trim(); - - if (!slashesDenoteHost && url.split('#').length === 1) { - // Try fast path regexp - var simplePath = simplePathPattern.exec(rest); - if (simplePath) { - this.path = rest; - this.href = rest; - this.pathname = simplePath[1]; - if (simplePath[2]) { - this.search = simplePath[2]; - if (parseQueryString) { - this.query = querystring.parse(this.search.substr(1)); - } else { - this.query = this.search.substr(1); - } - } else if (parseQueryString) { - this.search = ''; - this.query = {}; - } - return this; - } - } - - var proto = protocolPattern.exec(rest); - if (proto) { - proto = proto[0]; - var lowerProto = proto.toLowerCase(); - this.protocol = lowerProto; - rest = rest.substr(proto.length); - } - - // figure out if it's got a host - // user@server is *always* interpreted as a hostname, and url - // resolution will treat //foo/bar as host=foo,path=bar because that's - // how the browser resolves relative URLs. - if (slashesDenoteHost || proto || rest.match(/^\/\/[^@\/]+@[^@\/]+/)) { - var slashes = rest.substr(0, 2) === '//'; - if (slashes && !(proto && hostlessProtocol[proto])) { - rest = rest.substr(2); - this.slashes = true; - } - } - - if (!hostlessProtocol[proto] && - (slashes || (proto && !slashedProtocol[proto]))) { - - // there's a hostname. - // the first instance of /, ?, ;, or # ends the host. - // - // If there is an @ in the hostname, then non-host chars *are* allowed - // to the left of the last @ sign, unless some host-ending character - // comes *before* the @-sign. - // URLs are obnoxious. - // - // ex: - // http://a@b@c/ => user:a@b host:c - // http://a@b?@c => user:a host:c path:/?@c - - // v0.12 TODO(isaacs): This is not quite how Chrome does things. - // Review our test case against browsers more comprehensively. - - // find the first instance of any hostEndingChars - var hostEnd = -1; - for (var i = 0; i < hostEndingChars.length; i++) { - var hec = rest.indexOf(hostEndingChars[i]); - if (hec !== -1 && (hostEnd === -1 || hec < hostEnd)) - hostEnd = hec; - } - - // at this point, either we have an explicit point where the - // auth portion cannot go past, or the last @ char is the decider. - var auth, atSign; - if (hostEnd === -1) { - // atSign can be anywhere. - atSign = rest.lastIndexOf('@'); - } else { - // atSign must be in auth portion. - // http://a@b/c@d => host:b auth:a path:/c@d - atSign = rest.lastIndexOf('@', hostEnd); - } - - // Now we have a portion which is definitely the auth. - // Pull that off. - if (atSign !== -1) { - auth = rest.slice(0, atSign); - rest = rest.slice(atSign + 1); - this.auth = decodeURIComponent(auth); - } - - // the host is the remaining to the left of the first non-host char - hostEnd = -1; - for (var i = 0; i < nonHostChars.length; i++) { - var hec = rest.indexOf(nonHostChars[i]); - if (hec !== -1 && (hostEnd === -1 || hec < hostEnd)) - hostEnd = hec; - } - // if we still have not hit it, then the entire thing is a host. - if (hostEnd === -1) - hostEnd = rest.length; - - this.host = rest.slice(0, hostEnd); - rest = rest.slice(hostEnd); - - // pull out port. - this.parseHost(); - - // we've indicated that there is a hostname, - // so even if it's empty, it has to be present. - this.hostname = this.hostname || ''; - - // if hostname begins with [ and ends with ] - // assume that it's an IPv6 address. - var ipv6Hostname = this.hostname[0] === '[' && - this.hostname[this.hostname.length - 1] === ']'; - - // validate a little. - if (!ipv6Hostname) { - var hostparts = this.hostname.split(/\./); - for (var i = 0, l = hostparts.length; i < l; i++) { - var part = hostparts[i]; - if (!part) continue; - if (!part.match(hostnamePartPattern)) { - var newpart = ''; - for (var j = 0, k = part.length; j < k; j++) { - if (part.charCodeAt(j) > 127) { - // we replace non-ASCII char with a temporary placeholder - // we need this to make sure size of hostname is not - // broken by replacing non-ASCII by nothing - newpart += 'x'; - } else { - newpart += part[j]; - } - } - // we test again with ASCII char only - if (!newpart.match(hostnamePartPattern)) { - var validParts = hostparts.slice(0, i); - var notHost = hostparts.slice(i + 1); - var bit = part.match(hostnamePartStart); - if (bit) { - validParts.push(bit[1]); - notHost.unshift(bit[2]); - } - if (notHost.length) { - rest = '/' + notHost.join('.') + rest; - } - this.hostname = validParts.join('.'); - break; - } - } - } - } - - if (this.hostname.length > hostnameMaxLen) { - this.hostname = ''; - } else { - // hostnames are always lower case. - this.hostname = this.hostname.toLowerCase(); - } - - if (!ipv6Hostname) { - // IDNA Support: Returns a punycoded representation of "domain". - // It only converts parts of the domain name that - // have non-ASCII characters, i.e. it doesn't matter if - // you call it with a domain that already is ASCII-only. - this.hostname = punycode.toASCII(this.hostname); - } - - var p = this.port ? ':' + this.port : ''; - var h = this.hostname || ''; - this.host = h + p; - this.href += this.host; - - // strip [ and ] from the hostname - // the host field still retains them, though - if (ipv6Hostname) { - this.hostname = this.hostname.substr(1, this.hostname.length - 2); - if (rest[0] !== '/') { - rest = '/' + rest; - } - } - } - - // now rest is set to the post-host stuff. - // chop off any delim chars. - if (!unsafeProtocol[lowerProto]) { - - // First, make 100% sure that any "autoEscape" chars get - // escaped, even if encodeURIComponent doesn't think they - // need to be. - for (var i = 0, l = autoEscape.length; i < l; i++) { - var ae = autoEscape[i]; - if (rest.indexOf(ae) === -1) - continue; - var esc = encodeURIComponent(ae); - if (esc === ae) { - esc = escape(ae); - } - rest = rest.split(ae).join(esc); - } - } - - - // chop off from the tail first. - var hash = rest.indexOf('#'); - if (hash !== -1) { - // got a fragment string. - this.hash = rest.substr(hash); - rest = rest.slice(0, hash); - } - var qm = rest.indexOf('?'); - if (qm !== -1) { - this.search = rest.substr(qm); - this.query = rest.substr(qm + 1); - if (parseQueryString) { - this.query = querystring.parse(this.query); - } - rest = rest.slice(0, qm); - } else if (parseQueryString) { - // no query string, but parseQueryString still requested - this.search = ''; - this.query = {}; - } - if (rest) this.pathname = rest; - if (slashedProtocol[lowerProto] && - this.hostname && !this.pathname) { - this.pathname = '/'; - } - - //to support http.request - if (this.pathname || this.search) { - var p = this.pathname || ''; - var s = this.search || ''; - this.path = p + s; - } - - // finally, reconstruct the href based on what has been validated. - this.href = this.format(); - return this; -}; - -// format a parsed object into a url string -function urlFormat(obj) { - // ensure it's an object, and not a string url. - // If it's an obj, this is a no-op. - // this way, you can call url_format() on strings - // to clean up potentially wonky urls. - if (util.isString(obj)) obj = urlParse(obj); - if (!(obj instanceof Url)) return Url.prototype.format.call(obj); - return obj.format(); -} - -Url.prototype.format = function() { - var auth = this.auth || ''; - if (auth) { - auth = encodeURIComponent(auth); - auth = auth.replace(/%3A/i, ':'); - auth += '@'; - } - - var protocol = this.protocol || '', - pathname = this.pathname || '', - hash = this.hash || '', - host = false, - query = ''; - - if (this.host) { - host = auth + this.host; - } else if (this.hostname) { - host = auth + (this.hostname.indexOf(':') === -1 ? - this.hostname : - '[' + this.hostname + ']'); - if (this.port) { - host += ':' + this.port; - } - } - - if (this.query && - util.isObject(this.query) && - Object.keys(this.query).length) { - query = querystring.stringify(this.query); - } - - var search = this.search || (query && ('?' + query)) || ''; - - if (protocol && protocol.substr(-1) !== ':') protocol += ':'; - - // only the slashedProtocols get the //. Not mailto:, xmpp:, etc. - // unless they had them to begin with. - if (this.slashes || - (!protocol || slashedProtocol[protocol]) && host !== false) { - host = '//' + (host || ''); - if (pathname && pathname.charAt(0) !== '/') pathname = '/' + pathname; - } else if (!host) { - host = ''; - } - - if (hash && hash.charAt(0) !== '#') hash = '#' + hash; - if (search && search.charAt(0) !== '?') search = '?' + search; - - pathname = pathname.replace(/[?#]/g, function(match) { - return encodeURIComponent(match); - }); - search = search.replace('#', '%23'); - - return protocol + host + pathname + search + hash; -}; - -function urlResolve(source, relative) { - return urlParse(source, false, true).resolve(relative); -} - -Url.prototype.resolve = function(relative) { - return this.resolveObject(urlParse(relative, false, true)).format(); -}; - -function urlResolveObject(source, relative) { - if (!source) return relative; - return urlParse(source, false, true).resolveObject(relative); -} - -Url.prototype.resolveObject = function(relative) { - if (util.isString(relative)) { - var rel = new Url(); - rel.parse(relative, false, true); - relative = rel; - } - - var result = new Url(); - var tkeys = Object.keys(this); - for (var tk = 0; tk < tkeys.length; tk++) { - var tkey = tkeys[tk]; - result[tkey] = this[tkey]; - } - - // hash is always overridden, no matter what. - // even href="" will remove it. - result.hash = relative.hash; - - // if the relative url is empty, then there's nothing left to do here. - if (relative.href === '') { - result.href = result.format(); - return result; - } - - // hrefs like //foo/bar always cut to the protocol. - if (relative.slashes && !relative.protocol) { - // take everything except the protocol from relative - var rkeys = Object.keys(relative); - for (var rk = 0; rk < rkeys.length; rk++) { - var rkey = rkeys[rk]; - if (rkey !== 'protocol') - result[rkey] = relative[rkey]; - } - - //urlParse appends trailing / to urls like http://www.example.com - if (slashedProtocol[result.protocol] && - result.hostname && !result.pathname) { - result.path = result.pathname = '/'; - } - - result.href = result.format(); - return result; - } - - if (relative.protocol && relative.protocol !== result.protocol) { - // if it's a known url protocol, then changing - // the protocol does weird things - // first, if it's not file:, then we MUST have a host, - // and if there was a path - // to begin with, then we MUST have a path. - // if it is file:, then the host is dropped, - // because that's known to be hostless. - // anything else is assumed to be absolute. - if (!slashedProtocol[relative.protocol]) { - var keys = Object.keys(relative); - for (var v = 0; v < keys.length; v++) { - var k = keys[v]; - result[k] = relative[k]; - } - result.href = result.format(); - return result; - } - - result.protocol = relative.protocol; - if (!relative.host && !hostlessProtocol[relative.protocol]) { - var relPath = (relative.pathname || '').split('/'); - while (relPath.length && !(relative.host = relPath.shift())); - if (!relative.host) relative.host = ''; - if (!relative.hostname) relative.hostname = ''; - if (relPath[0] !== '') relPath.unshift(''); - if (relPath.length < 2) relPath.unshift(''); - result.pathname = relPath.join('/'); - } else { - result.pathname = relative.pathname; - } - result.search = relative.search; - result.query = relative.query; - result.host = relative.host || ''; - result.auth = relative.auth; - result.hostname = relative.hostname || relative.host; - result.port = relative.port; - // to support http.request - if (result.pathname || result.search) { - var p = result.pathname || ''; - var s = result.search || ''; - result.path = p + s; - } - result.slashes = result.slashes || relative.slashes; - result.href = result.format(); - return result; - } - - var isSourceAbs = (result.pathname && result.pathname.charAt(0) === '/'), - isRelAbs = ( - relative.host || - relative.pathname && relative.pathname.charAt(0) === '/' - ), - mustEndAbs = (isRelAbs || isSourceAbs || - (result.host && relative.pathname)), - removeAllDots = mustEndAbs, - srcPath = result.pathname && result.pathname.split('/') || [], - relPath = relative.pathname && relative.pathname.split('/') || [], - psychotic = result.protocol && !slashedProtocol[result.protocol]; - - // if the url is a non-slashed url, then relative - // links like ../.. should be able - // to crawl up to the hostname, as well. This is strange. - // result.protocol has already been set by now. - // Later on, put the first path part into the host field. - if (psychotic) { - result.hostname = ''; - result.port = null; - if (result.host) { - if (srcPath[0] === '') srcPath[0] = result.host; - else srcPath.unshift(result.host); - } - result.host = ''; - if (relative.protocol) { - relative.hostname = null; - relative.port = null; - if (relative.host) { - if (relPath[0] === '') relPath[0] = relative.host; - else relPath.unshift(relative.host); - } - relative.host = null; - } - mustEndAbs = mustEndAbs && (relPath[0] === '' || srcPath[0] === ''); - } - - if (isRelAbs) { - // it's absolute. - result.host = (relative.host || relative.host === '') ? - relative.host : result.host; - result.hostname = (relative.hostname || relative.hostname === '') ? - relative.hostname : result.hostname; - result.search = relative.search; - result.query = relative.query; - srcPath = relPath; - // fall through to the dot-handling below. - } else if (relPath.length) { - // it's relative - // throw away the existing file, and take the new path instead. - if (!srcPath) srcPath = []; - srcPath.pop(); - srcPath = srcPath.concat(relPath); - result.search = relative.search; - result.query = relative.query; - } else if (!util.isNullOrUndefined(relative.search)) { - // just pull out the search. - // like href='?foo'. - // Put this after the other two cases because it simplifies the booleans - if (psychotic) { - result.hostname = result.host = srcPath.shift(); - //occationaly the auth can get stuck only in host - //this especially happens in cases like - //url.resolveObject('mailto:local1@domain1', 'local2@domain2') - var authInHost = result.host && result.host.indexOf('@') > 0 ? - result.host.split('@') : false; - if (authInHost) { - result.auth = authInHost.shift(); - result.host = result.hostname = authInHost.shift(); - } - } - result.search = relative.search; - result.query = relative.query; - //to support http.request - if (!util.isNull(result.pathname) || !util.isNull(result.search)) { - result.path = (result.pathname ? result.pathname : '') + - (result.search ? result.search : ''); - } - result.href = result.format(); - return result; - } - - if (!srcPath.length) { - // no path at all. easy. - // we've already handled the other stuff above. - result.pathname = null; - //to support http.request - if (result.search) { - result.path = '/' + result.search; - } else { - result.path = null; - } - result.href = result.format(); - return result; - } - - // if a url ENDs in . or .., then it must get a trailing slash. - // however, if it ends in anything else non-slashy, - // then it must NOT get a trailing slash. - var last = srcPath.slice(-1)[0]; - var hasTrailingSlash = ( - (result.host || relative.host || srcPath.length > 1) && - (last === '.' || last === '..') || last === ''); - - // strip single dots, resolve double dots to parent dir - // if the path tries to go above the root, `up` ends up > 0 - var up = 0; - for (var i = srcPath.length; i >= 0; i--) { - last = srcPath[i]; - if (last === '.') { - srcPath.splice(i, 1); - } else if (last === '..') { - srcPath.splice(i, 1); - up++; - } else if (up) { - srcPath.splice(i, 1); - up--; - } - } - - // if the path is allowed to go above the root, restore leading ..s - if (!mustEndAbs && !removeAllDots) { - for (; up--; up) { - srcPath.unshift('..'); - } - } - - if (mustEndAbs && srcPath[0] !== '' && - (!srcPath[0] || srcPath[0].charAt(0) !== '/')) { - srcPath.unshift(''); - } - - if (hasTrailingSlash && (srcPath.join('/').substr(-1) !== '/')) { - srcPath.push(''); - } - - var isAbsolute = srcPath[0] === '' || - (srcPath[0] && srcPath[0].charAt(0) === '/'); - - // put the host back - if (psychotic) { - result.hostname = result.host = isAbsolute ? '' : - srcPath.length ? srcPath.shift() : ''; - //occationaly the auth can get stuck only in host - //this especially happens in cases like - //url.resolveObject('mailto:local1@domain1', 'local2@domain2') - var authInHost = result.host && result.host.indexOf('@') > 0 ? - result.host.split('@') : false; - if (authInHost) { - result.auth = authInHost.shift(); - result.host = result.hostname = authInHost.shift(); - } - } - - mustEndAbs = mustEndAbs || (result.host && srcPath.length); - - if (mustEndAbs && !isAbsolute) { - srcPath.unshift(''); - } - - if (!srcPath.length) { - result.pathname = null; - result.path = null; - } else { - result.pathname = srcPath.join('/'); - } - - //to support request.http - if (!util.isNull(result.pathname) || !util.isNull(result.search)) { - result.path = (result.pathname ? result.pathname : '') + - (result.search ? result.search : ''); - } - result.auth = relative.auth || result.auth; - result.slashes = result.slashes || relative.slashes; - result.href = result.format(); - return result; -}; - -Url.prototype.parseHost = function() { - var host = this.host; - var port = portPattern.exec(host); - if (port) { - port = port[0]; - if (port !== ':') { - this.port = port.substr(1); - } - host = host.substr(0, host.length - port.length); - } - if (host) this.hostname = host; -}; - -},{"./util":33,"punycode":12,"querystring":15}]},{},[]); diff --git a/demo/src/main.js b/demo/src/main.js index d0b8e40..a2047f4 100644 --- a/demo/src/main.js +++ b/demo/src/main.js @@ -1,6 +1,6 @@ const KalmanFilter = require('../../lib/kalman-filter'); -const noisyObservations = require('./observation.json'); +const noisyObservations = require('./observations.json').observations; const kfOptions = require('./kf-options.js'); const createElement = require('./views/create-element'); const createGroupBoxes = require('./views/create-group-boxes'); @@ -11,45 +11,50 @@ let predicted = kf.predict(); const img = document.querySelector('#bikes');// eslint-disable-line no-undef // Create all the elements of the prediction or correction phase -const delay = 1000; +const delay = 100; let promise = Promise.resolve(); let previousCorrected = null; const delayPromise = delay => new Promise(resolve => setTimeout(resolve, delay)); -noisyObservations.forEach((box, index) => { - promise = promise - .then(() => { - predicted = kf.predict({previousCorrected}); - const {mean, covariance} = predicted; - - createGroupBoxes({mean, covariance, parent: img, className: 'predicted', color: 'blue'}); - - return delayPromise(delay); - }) - .then((b => { - createElement({ - className: 'observation', - bbox: [ - b[0] + (b[2] / 2), - b[1] + (b[3] / 2), - b[2], - b[3] - ], - parent: img, - color: 'white', - lineStyle: 'solid' - }); - - return delayPromise(delay); - }).bind(null, box, index)) - .then((b => { - previousCorrected = kf.correct({predicted, observation: b}); - const {mean, covariance} = previousCorrected; - - createGroupBoxes({mean, covariance, parent: img, className: 'corrected', color: 'red'}); - - return delayPromise(delay); - }).bind(null, box, index)); -}); +module.exports = { + run() { + noisyObservations.forEach((box, index) => { + promise = promise + .then(() => { + predicted = kf.predict({previousCorrected}); + const {mean, covariance} = predicted; + + createGroupBoxes({mean, covariance, parent: img, className: 'predicted', color: 'blue'}); + + return delayPromise(delay); + }) + .then((b => { + createElement({ + className: 'observation', + bbox: [ + b[0] + (b[2] / 2), + b[1] + (b[3] / 2), + b[2], + b[3] + ], + parent: img, + color: 'white', + lineStyle: 'solid' + }); + + return delayPromise(delay); + }).bind(null, box, index)) + .then((b => { + previousCorrected = kf.correct({predicted, observation: b}); + const {mean, covariance} = previousCorrected; + + createGroupBoxes({mean, covariance, parent: img, className: 'corrected', color: 'red'}); + + return delayPromise(delay); + }).bind(null, box, index)); + }); + } +}; + diff --git a/demo/src/observation-covariance.json b/demo/src/observation-covariance.json new file mode 100644 index 0000000..6d6736e --- /dev/null +++ b/demo/src/observation-covariance.json @@ -0,0 +1 @@ +[[34.31428571428572,-8.114285714285714,-9.185714285714285,3.0428571428571427],[-8.114285714285714,39.08571428571429,1.1857142857142857,-5.5285714285714285],[-9.185714285714285,1.1857142857142857,34.628571428571426,0.7857142857142857],[3.0428571428571427,-5.5285714285714285,0.7857142857142857,39.857142857142854]] \ No newline at end of file diff --git a/demo/src/observations.json b/demo/src/observations.json index e0cdb66..abae056 100644 --- a/demo/src/observations.json +++ b/demo/src/observations.json @@ -1 +1 @@ -{"observations":[[845,290,89,84],[699,181,95,92],[570,104,111,119],[437,93,86,101],[285,129,82,96],[149,205,85,78],[15,295,73,91]]} \ No newline at end of file +{"observations":[[842,286,82,81],[714,184,92,80],[560,107,112,116],[418,94,96,110],[277,141,89,89],[146,200,88,72],[22,306,77,82]]} \ No newline at end of file diff --git a/demo/src/views/create-group-boxes.js b/demo/src/views/create-group-boxes.js index 9509cb2..5c7e3fe 100644 --- a/demo/src/views/create-group-boxes.js +++ b/demo/src/views/create-group-boxes.js @@ -82,6 +82,5 @@ module.exports = function ({mean, covariance, color, parent, className, tag = 'd scale: arrowScale, color }); - container.style.display = 'none'; parent.append(container); }; diff --git a/demo/style.css b/demo/style.css new file mode 100644 index 0000000..eb747f1 --- /dev/null +++ b/demo/style.css @@ -0,0 +1,98 @@ + .img{ + position: relative; + display: inline-block; /* Make the width of box same as image */ + overflow: hidden; + } + .img .box{ + position: absolute; + z-index: 999; + margin: 0 auto; + border: 1px solid white; + } + .img .observation{ + position: absolute; + z-index: 999; + margin: 0 auto; + border: 1px solid white; + } + .img .dashedLine{ + position: absolute; + z-index: 999; + margin: 0 auto; + } + .top-right { + position: absolute; + top: 20px; + right: 20px; + background-color: grey; + color: white; + padding-left: 20px; + padding-right: 20px; + } + .img .point{ + position: absolute; + z-index: 999; + margin: 0 auto; + border: 2px solid red; + + } + .img .ellipse { + position: absolute; + z-index: 999; + margin: 0 auto; + border-radius: 50%; + } + .img .arrow { + position: absolute; + border-width: 4px; + border-style: solid; + border-bottom-color: transparent; + border-left-color: transparent; + display: inline-block; + vertical-align: middle; + box-sizing: border-box; + } + + .img.observation .observation, .img.predicted .predicted,.img.corrected .corrected { + display: block; + } + + .img.not-observation .observation { + display: none; + } + .img.not-predicted .predicted { + display: none; + } + .img.not-corrected .corrected { + display: none; + } + .img.not-covariances .dashedLine { + display: none; + } + .img.not-variances .stdDev { + display: none; + } + .img.not-speedVectors .arrow { + display: none; + } + .img .arrow:before{ + right: 0; + top: -3px; + position: absolute; + height: 3px; + box-shadow: inset 0 0 0 32px; + transform: rotate(-45deg); + width: 15px; + transform-origin: right top; + content: ""; + box-sizing: border-box; + } + div.img .stdDev{ + border-style: dotted; + } + .img .predicted .box,.img .predicted .ellipse, .img .predicted .point{ + border-color: blue; + } + .img .corrected .box,.img .corrected .ellipse, .img .corrected .point{ + border-color: red; + } \ No newline at end of file diff --git a/lib/core-kalman-filter.js b/lib/core-kalman-filter.js index 3d837bd..49d2315 100644 --- a/lib/core-kalman-filter.js +++ b/lib/core-kalman-filter.js @@ -116,9 +116,8 @@ class CoreKalmanFilter { let index; if (typeof (previousCorrected.index) === 'number') { index = previousCorrected.index + 1; - } - else { - index = 'Index key is not defined' + } else { + index = null; } const predicted = new State({mean, covariance, index}); @@ -192,6 +191,9 @@ class CoreKalmanFilter { predicted.mean, matMul(optimalKalmanGain, innovation) ); + if (Number.isNaN(mean[0][0])) { + throw (new TypeError('Mean is NaN after correction')); + } const covariance = this.getCorrectedCovariance({predicted}); const corrected = new State({mean, covariance, index: predicted.index}); diff --git a/package.json b/package.json index 3ca70af..07b5e90 100644 --- a/package.json +++ b/package.json @@ -4,7 +4,8 @@ "description": "Kalman filter (and Extended Kalman Filter) Multi-dimensional implementation in Javascript", "main": "index.js", "scripts": { - "test": "xo && ava test/unit/kalman-filter/*" + "test": "xo && ava test/unit/kalman-filter/*", + "build-demo": "browserify -d -r ./demo/src/main.js:main > demo/dist/demo.js" }, "repository": { "type": "git", @@ -59,6 +60,7 @@ "matrix-inverse": "^1.0.1" }, "xo": { + "ignores": ["./demo/dist/**"], "rules": { "no-multi-assign": 0, "unicorn/no-reduce": 0, diff --git a/script/demo/helpers/calculate-observation-covariance.js b/script/demo/helpers/calculate-observation-covariance.js index 3c1f3f8..3ff732c 100644 --- a/script/demo/helpers/calculate-observation-covariance.js +++ b/script/demo/helpers/calculate-observation-covariance.js @@ -1,9 +1,18 @@ const generateNoisyObservation = require('./generate-noisy-observation.js'); -const getCovariance = require('../../lib/utils/get-covariance.js'); +const getCovariance = require('../../../lib/utils/get-covariance.js'); const calculateObservationCovariance = function ({groundTruths, rangeNoise = 10, numberRun = 1}) { const noisyMatrixes = generateNoisyObservation({groundTruths, rangeNoise, numberRun}); - return noisyMatrixes.map(noisyMatrix => getCovariance({measures: noisyMatrix, averages: groundTruths})); + const measures = noisyMatrixes.reduce((a, b) => a.concat(b)); + + const averages = new Array(numberRun).fill(0).map(() => groundTruths).reduce((a, b) => a.concat(b)); + const covariance = getCovariance({ + measures, + averages + }); + // Console.log(measures, averages, measures.length, averages.length,covariance); + + return covariance; }; module.exports = calculateObservationCovariance; diff --git a/script/demo/helpers/generate-noisy-observation.js b/script/demo/helpers/generate-noisy-observation.js index 996fc0a..be5c0af 100644 --- a/script/demo/helpers/generate-noisy-observation.js +++ b/script/demo/helpers/generate-noisy-observation.js @@ -1,7 +1,7 @@ const h = require('hasard'); const elemWise = require('../../../lib/linalgebra/elem-wise.js'); -const generateNoisyObservation = function ({groundTruths, rangeNoise = 10}) { +const generateNoisyObservation = function ({groundTruths, rangeNoise = 10, numberRun = 1}) { const hasardNoise = h.matrix({ shape: [groundTruths.length, groundTruths[0].length], value: h.integer(-rangeNoise, rangeNoise) @@ -9,7 +9,7 @@ const generateNoisyObservation = function ({groundTruths, rangeNoise = 10}) { const combinedMatrix = h.fn((noise, gT) => { return elemWise([noise, gT], ([n, gTCell]) => n + gTCell); })(hasardNoise, groundTruths); - return combinedMatrix.runOnce(); + return combinedMatrix.run(numberRun); }; module.exports = generateNoisyObservation; diff --git a/script/demo/update-input-data.js b/script/demo/update-input-data.js index 41bca89..d94f5bd 100644 --- a/script/demo/update-input-data.js +++ b/script/demo/update-input-data.js @@ -1,4 +1,5 @@ -var generateNoisyObservation = require('./helpers/generate-noisy-observation'); +const generateNoisyObservation = require('./helpers/generate-noisy-observation'); +const calculateObservationCovariance = require('./helpers/calculate-observation-covariance'); const fs = require('fs'); const boxes = [ @@ -25,5 +26,9 @@ const boxes = [ ] ]; -const noisyObservations = generateNoisyObservation({groundTruths: boxes}); -fs.writeFileSync('./demo/observations.json', JSON.stringify({observations: noisyObservations})); \ No newline at end of file +const noisyObservations = generateNoisyObservation({groundTruths: boxes})[0]; +fs.writeFileSync('./demo/src/observations.json', JSON.stringify({observations: noisyObservations})); + +const observationCovariance = calculateObservationCovariance({groundTruths: boxes, numberRun: 10}); + +fs.writeFileSync('./demo/src/observation-covariance.json', JSON.stringify(observationCovariance)); diff --git a/test/api/basic.js b/test/api/basic.js index c7eba0f..647b19c 100644 --- a/test/api/basic.js +++ b/test/api/basic.js @@ -4,8 +4,7 @@ const test = require('ava'); const KalmanFilter = require('../../lib/kalman-filter.js'); const State = require('../../lib/state.js'); -// const getCovariance = require('../../lib/utils/get-covariance.js'); -const identity = require('../../lib/linalgebra/identity.js') +// Const getCovariance = require('../../lib/utils/get-covariance.js'); const observations = [[0, 2], [0.1, 4], [0.5, 9], [0.2, 12]]; test('Constant-position on 2D Data', t => { @@ -177,97 +176,38 @@ test('Simple Batch Usage', t => { t.is(results.length, 4); }); -// test('getCovariance', t => { -// -// // Ground truth values in the dynamic model hidden state -// const groundTruthStates = [ // Here this is (x, vx) -// [[0, 1.1], [1.1, 1], [2.1, 0.9], [3, 1], [4, 1.2]], // Example 1 -// [[8, 1.1], [9.1, 1], [10.1, 0.9], [11, 1], [12, 1.2]] // Example 2 -// ]; -// -// // Observations of this values -// const measures = [ // Here this is x only -// [[0.1], [1.3], [2.4], [2.6], [3.8]], // Example 1 -// [[8.1], [9.3], [10.4], [10.6], [11.8]] // Example 2 -// ]; -// -// let kFilter = new KalmanFilter({ -// observation: { -// name: 'sensors', -// sensorDimension: 1 -// }, -// dynamic: { -// name: 'constant-speed' -// } -// }); -// const dynamicCovariance = getCovariance({ -// measures: groundTruthStates.map(ex => { -// return ex.slice(1).map((_, index) => { -// console.log('mean', ex[0]); -// console.log('covariance', identity(groundTruthStates[0][0].length)) -// const previousCorrected = new State({ -// mean: ex[index], -// covariance: identity(groundTruthStates[0][0].length) -// }); -// return kFilter.predict({previousCorrected}).mean; -// }); -// }).reduce((a, b) => a.concat(b)), -// averages: groundTruthStates.map(ex => { -// return ex.slice(1); -// }).reduce((a, b) => a.concat(b)) -// }); -// -// const observationCovariance = getCovariance({ -// measures: measures.reduce((a, b) => a.concat(b)), -// averages: groundTruthStates.map(a => a[0]).reduce((a, b) => a.concat(b)) -// }); -// -// kFilter = Object.assign({}, kFilter, { -// observation: { -// covariance: observationCovariance -// }, -// dynamic: { -// covariance: dynamicCovariance -// } -// }) -// const predicted = kFilter.predict(); -// t.is(observationCovariance.length, 1); -// t.is(dynamicCovariance.length, 2); -// t.is(predcited instanceof State); -// }); +test('Model fits ', t => { + const kFilter = new KalmanFilter({ + observation: { + sensorDimension: 2, + name: 'sensors' + }, + dynamic: { + name: 'constant-speed', // Observation.sensorDimension == dynamic.dimension + covariance: [3, 4]// Equivalent to diag([3, 4]) + } + }); + const observations = [[0, 2], [0.1, 4], [0.5, 9], [0.2, 12]]; + + // Online kalman filter + let previousCorrected = null; + const distances = []; + observations.forEach(observation => { + const predicted = kFilter.predict({ + previousCorrected + }); + + const dist = predicted.mahalanobis(observation); + + previousCorrected = kFilter.correct({ + predicted, + observation + }); -// test('Model fits ', t => { -// const kFilter = new KalmanFilter({ -// observation: { -// sensorDimension: 2, -// name: 'sensors' -// }, -// dynamic: { -// name: 'constant-speed', // Observation.sensorDimension == dynamic.dimension -// covariance: [3, 4]// Equivalent to diag([3, 4]) -// } -// }); -// const observations = [[0, 2], [0.1, 4], [0.5, 9], [0.2, 12]]; -// -// // Online kalman filter -// let previousCorrected = null; -// const distances = []; -// observations.forEach(observation => { -// const predicted = kFilter.predict({ -// previousCorrected -// }); -// -// const dist = predicted.mahalanobis(observation); -// -// previousCorrected = kFilter.correct({ -// predicted, -// observation -// }); -// -// distances.push(dist); -// }); -// -// const distance = distances.reduce((d1, d2) => d1 + d2, 0); -// -// t.true(distance > 0); -// }); + distances.push(dist); + }); + + const distance = distances.reduce((d1, d2) => d1 + d2, 0); + + t.true(distance > 0); +}); diff --git a/test/unit/kalman-filter/filter.js b/test/unit/kalman-filter/filter.js index 0d6ce31..055df17 100644 --- a/test/unit/kalman-filter/filter.js +++ b/test/unit/kalman-filter/filter.js @@ -15,7 +15,7 @@ test('Filter method', t => { name: 'sensors' } }); - const filtered = kf.filter({observation: observations[0]}); + const filtered = kf.filter({observation: observations[0]});// eslint-disable-line unicorn/no-fn-reference-in-iterator t.true(filtered instanceof State); const predicted = kf.predict(); @@ -35,7 +35,7 @@ test('FilterAll', t => { }); const allFiltered = kf.filterAll(observations); t.is(allFiltered.length, 3); - const filtered = kf.filter({observation: observations[0]}); + const filtered = kf.filter({observation: observations[0]});// eslint-disable-line unicorn/no-fn-reference-in-iterator const firstMean = filtered.mean; t.deepEqual(firstMean, allFiltered[0]); });