UNPKG

ui-widget-toolkit

Version:

UI widgets built on top of D3, Pixi.js and ag-grid-community

171 lines • 240 kB
(function webpackUniversalModuleDefinition(root, factory) {
	if(typeof exports === 'object' && typeof module === 'object')
		module.exports = factory(require("d3"));
	else if(typeof define === 'function' && define.amd)
		define("UWT", ["d3"], factory);
	else if(typeof exports === 'object')
		exports["UWT"] = factory(require("d3"));
	else
		root["UWT"] = factory(root["d3"]);
})(window, function(__WEBPACK_EXTERNAL_MODULE_d3__) {
return /******/ (function(modules) { // webpackBootstrap
/******/ 	// The module cache
/******/ 	var installedModules = {};
/******/
/******/ 	// The require function
/******/ 	function __webpack_require__(moduleId) {
/******/
/******/ 		// Check if module is in cache
/******/ 		if(installedModules[moduleId]) {
/******/ 			return installedModules[moduleId].exports;
/******/ 		}
/******/ 		// Create a new module (and put it into the cache)
/******/ 		var module = installedModules[moduleId] = {
/******/ 			i: moduleId,
/******/ 			l: false,
/******/ 			exports: {}
/******/ 		};
/******/
/******/ 		// Execute the module function
/******/ 		modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
/******/
/******/ 		// Flag the module as loaded
/******/ 		module.l = true;
/******/
/******/ 		// Return the exports of the module
/******/ 		return module.exports;
/******/ 	}
/******/
/******/
/******/ 	// expose the modules object (__webpack_modules__)
/******/ 	__webpack_require__.m = modules;
/******/
/******/ 	// expose the module cache
/******/ 	__webpack_require__.c = installedModules;
/******/
/******/ 	// define getter function for harmony exports
/******/ 	__webpack_require__.d = function(exports, name, getter) {
/******/ 		if(!__webpack_require__.o(exports, name)) {
/******/ 			Object.defineProperty(exports, name, { enumerable: true, get: getter });
/******/ 		}
/******/ 	};
/******/
/******/ 	// define __esModule on exports
/******/ 	__webpack_require__.r = function(exports) {
/******/ 		if(typeof Symbol !== 'undefined' && Symbol.toStringTag) {
/******/ 			Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
/******/ 		}
/******/ 		Object.defineProperty(exports, '__esModule', { value: true });
/******/ 	};
/******/
/******/ 	// create a fake namespace object
/******/ 	// mode & 1: value is a module id, require it
/******/ 	// mode & 2: merge all properties of value into the ns
/******/ 	// mode & 4: return value when already ns object
/******/ 	// mode & 8|1: behave like require
/******/ 	__webpack_require__.t = function(value, mode) {
/******/ 		if(mode & 1) value = __webpack_require__(value);
/******/ 		if(mode & 8) return value;
/******/ 		if((mode & 4) && typeof value === 'object' && value && value.__esModule) return value;
/******/ 		var ns = Object.create(null);
/******/ 		__webpack_require__.r(ns);
/******/ 		Object.defineProperty(ns, 'default', { enumerable: true, value: value });
/******/ 		if(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key));
/******/ 		return ns;
/******/ 	};
/******/
/******/ 	// getDefaultExport function for compatibility with non-harmony modules
/******/ 	__webpack_require__.n = function(module) {
/******/ 		var getter = module && module.__esModule ?
/******/ 			function getDefault() { return module['default']; } :
/******/ 			function getModuleExports() { return module; };
/******/ 		__webpack_require__.d(getter, 'a', getter);
/******/ 		return getter;
/******/ 	};
/******/
/******/ 	// Object.prototype.hasOwnProperty.call
/******/ 	__webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };
/******/
/******/ 	// __webpack_public_path__
/******/ 	__webpack_require__.p = "";
/******/
/******/
/******/ 	// Load entry module and return exports
/******/ 	return __webpack_require__(__webpack_require__.s = "./src/core/cartesian/decimator/worker.ts");
/******/ })
/************************************************************************/
/******/ ({

/***/ "./src/core/cartesian/decimator/decimator.ts":
/*!***************************************************!*\
  !*** ./src/core/cartesian/decimator/decimator.ts ***!
  \***************************************************/
/*! no static exports found */
/***/ (function(module, exports, __webpack_require__) {

"use strict";
eval("\nObject.defineProperty(exports, \"__esModule\", { value: true });\nconst data_1 = __webpack_require__(/*! ../../data */ \"./src/core/data.ts\");\nconst utilities_1 = __webpack_require__(/*! ../../utilities */ \"./src/core/utilities.ts\");\nexports.findFirstInsertionIdx = utilities_1.bisectBuffer(function (xy) { return xy.x; }).left;\nexports.findLastInsertionIdx = utilities_1.bisectBuffer(function (xy) { return xy.x; }).right;\nclass XYDummyDecimator {\n    constructor() {\n        this._values = [];\n    }\n    initialize(xValueToCoord, xCoordToValue, yValueToCoord) {\n    }\n    getKey() {\n        return '';\n    }\n    getName() {\n        return '';\n    }\n    /**\n     * Returns the decimated list of data\n     */\n    getValues() {\n        return this._values;\n    }\n    /**\n     * Values to be decimated\n     *\n     * @param xStart - start time of the region\n     * @param xEnd - start time of the region\n     * @param values - Values to be decimated.\n     */\n    decimateValues(xStart, xEnd, values) {\n        if (Array.isArray(values)) {\n            values.forEach((data) => {\n                this._values.push(data.getData());\n            });\n        }\n        else {\n            this._values = values.getData();\n        }\n        return this._values;\n    }\n} // interface IDecimator\nexports.XYDummyDecimator = XYDummyDecimator;\n/**\n * this class allows a decimation function to be passed in to allow for\n * generic decimation\n */\nclass CustomPointXYDecimator {\n    constructor() {\n        this._name = 'Simple Unimplemented Decimator';\n    }\n    /**\n     * construct a generic decimator using a custom user function\n     *\n     * @param xValueToCoord converts the x value to a GUI x coordinate\n     * @param yValueToCoord converts the y value to a GUI y coordinate\n     * @param decimationFunc convert a list of data to a for rendering smaller list\n     */\n    initialize(xValueToCoord, xCoordToValue, yValueToCoord) {\n        this._xValueToCoord = xValueToCoord;\n        this._xCoordToValue = xCoordToValue;\n        this._yValueToCoord = yValueToCoord;\n    }\n    /**\n     * Returns the key of this decimator\n     */\n    getKey() {\n        return this._key;\n    }\n    /**\n     * Returns the name of this decimator\n     */\n    getName() {\n        return this._name;\n    }\n    /**\n     * Returns the decimated list of buckets\n     */\n    getValues() {\n        return this._decimatedValues;\n    }\n    /**\n     * Values to be decimated\n     *\n     * @param xStart - start time of the region\n     * @param xEnd - start time of the region\n     * @param values - Values to be decimated.\n     */\n    decimateValues(xStart, xEnd, inputValues) {\n        // loop over the data samples\n        this._decimatedValues = [];\n        if (inputValues.length() === 0) {\n            return this._decimatedValues;\n        }\n        let left = exports.findFirstInsertionIdx(inputValues, xStart);\n        let right = exports.findLastInsertionIdx(inputValues, xEnd);\n        if (left > 0) {\n            --left;\n        }\n        if (right < inputValues.length()) {\n            ++right;\n        }\n        let lastX;\n        if (left < inputValues.length()) {\n            lastX = Math.floor(this._xValueToCoord(inputValues.get(left).x));\n            --lastX;\n        }\n        let xStartCoord;\n        if (xStart) {\n            xStartCoord = Math.floor(this._xValueToCoord(xStart));\n        }\n        else {\n            xStartCoord = Math.floor(this._xValueToCoord(inputValues.get(left).x));\n        }\n        let lastIdx = left;\n        let endIdx;\n        for (let index = left; index < right; ++index) {\n            let inputValue = inputValues.get(index);\n            let xEndCoord = Math.floor(this._xValueToCoord(inputValue.x));\n            endIdx = index;\n            if (xEndCoord !== lastX) {\n                this._decimatedValues = this._decimatedValues.concat(this._customFunc(inputValues, lastIdx, endIdx, this._yValueToCoord, this._xValueToCoord, this._xCoordToValue(xStartCoord), this._xCoordToValue(xEndCoord)));\n                xStartCoord = xEndCoord;\n                lastX = xEndCoord;\n                lastIdx = endIdx;\n            }\n        }\n        if (lastIdx !== inputValues.length()) {\n            this._decimatedValues = this._decimatedValues.concat(this._customFunc(inputValues, lastIdx, endIdx + 1, this._yValueToCoord, this._xValueToCoord, this._xCoordToValue(xStartCoord), Number.MAX_VALUE));\n        }\n        return this._decimatedValues;\n    }\n}\nexports.CustomPointXYDecimator = CustomPointXYDecimator;\n/** used to compute the min values for a set of data */\nclass MinPointDecimator extends CustomPointXYDecimator {\n    constructor() {\n        super();\n        this._key = MinPointDecimator.KEY;\n        this._name = 'Min';\n        this._customFunc = function (values, startIdx, endIdx, yValueToCoord) {\n            if (values.length() > 0 && startIdx !== endIdx) {\n                let minY = Number.MAX_VALUE;\n                let minValue;\n                for (let i = startIdx; i < endIdx; ++i) {\n                    let value = values.get(i);\n                    let y = value.y;\n                    if (y < minY) {\n                        minValue = value;\n                        minY = y;\n                    }\n                }\n                return [minValue];\n            }\n            return [];\n        };\n    }\n}\nexports.MinPointDecimator = MinPointDecimator;\nMinPointDecimator.KEY = 'MinPointDecimator';\n;\nfunction computeAvg(values, startIdx, endIdx, yValueToCoord) {\n    if (values.length() > 0 && startIdx !== endIdx) {\n        let total = 0;\n        for (let i = startIdx; i < endIdx; ++i) {\n            let value = values.get(i);\n            total += value.y;\n        }\n        return [new data_1.XYValue(values.get(endIdx - 1).x, total / (endIdx - startIdx))];\n    }\n    return [];\n}\n/** used to compute the avg values for a set of data */\nclass AvgPointDecimator extends CustomPointXYDecimator {\n    constructor() {\n        super();\n        this._key = AvgPointDecimator.KEY;\n        this._name = 'Avg';\n        this._customFunc = computeAvg;\n    }\n}\nexports.AvgPointDecimator = AvgPointDecimator;\nAvgPointDecimator.KEY = 'AvgPointDecimator';\n;\n/** used to compute the min values for a set of data */\nclass MaxPointDecimator extends CustomPointXYDecimator {\n    constructor() {\n        super();\n        this._key = MaxPointDecimator.KEY;\n        this._name = 'Max';\n        this._customFunc = function (values, startIdx, endIdx, yValueToCoord) {\n            if (values.length() > 0 && startIdx !== endIdx) {\n                let maxY = -Number.MAX_VALUE;\n                let maxValue;\n                for (let i = startIdx; i < endIdx; ++i) {\n                    let value = values.get(i);\n                    let y = value.y;\n                    if (y > maxY) {\n                        maxValue = value;\n                        maxY = y;\n                    }\n                }\n                return [maxValue];\n            }\n            return [];\n        };\n    }\n}\nexports.MaxPointDecimator = MaxPointDecimator;\nMaxPointDecimator.KEY = 'MaxPointDecimator';\n;\n/**\n * Data decimation to fit information to onto the graph.\n *\n * This class divides the x-Axis time range into a set of buckets.  Each\n * bucket provides the average of the values, the minimum & maximum\n * values, and the values upon entry & exit.\n * It assumes that the DB values are increase over the time.\n */\nclass XYPointDecimator extends CustomPointXYDecimator {\n    constructor() {\n        super();\n        this._key = XYPointDecimator.KEY;\n        this._name = 'XYPointDecimator';\n        this._customFunc = function (values, startIdx, endIdx, yValueToCoord) {\n            let yMap = {};\n            let reducedValues = [];\n            for (let i = startIdx; i < endIdx; ++i) {\n                let value = values.get(i);\n                let yCoord = Math.floor(yValueToCoord(value.y));\n                if (!yMap.hasOwnProperty(yCoord.toString())) {\n                    reducedValues.push(value);\n                    yMap[yCoord] = true;\n                }\n            }\n            return reducedValues;\n        };\n    }\n} // class VerticalDecimator\nexports.XYPointDecimator = XYPointDecimator;\nXYPointDecimator.KEY = 'XYPointDecimator';\n/**\n * this class allows a decimation function to be passed in to allow for\n * generic decimation\n */\nclass CustomContinuousXYDecimator {\n    constructor() {\n        this._name = 'Simple Unimplemented Decimator';\n    }\n    /**\n     * construct a generic decimator using a custom user function\n     *\n     * @param xValueToCoord converts the x value to a GUI x coordinate\n     * @param yValueToCoord converts the y value to a GUI y coordinate\n     * @param decimationFunc convert a list of data to a for rendering smaller list\n     */\n    initialize(xValueToCoord, xCoordToValue, yValueToCoord) {\n        this._xValueToCoord = xValueToCoord;\n        this._xCoordToValue = xCoordToValue;\n        this._yValueToCoord = yValueToCoord;\n    }\n    /**\n     * Returns the key of this decimator\n     */\n    getKey() {\n        return this._key;\n    }\n    /**\n     * Returns the name of this decimator\n     */\n    getName() {\n        return this._name;\n    }\n    /**\n     * Returns the decimated list of buckets\n     */\n    getValues() {\n        return this._decimatedValues;\n    }\n    /**\n     * Values to be decimated\n     *\n     * @param xStart - start time of the region\n     * @param xEnd - start time of the region\n     * @param values - Values to be decimated.\n     */\n    decimateValues(xStart, xEnd, inputValues) {\n        // loop over the data samples\n        this._decimatedValues = [];\n        if (inputValues.length() === 0) {\n            return this._decimatedValues;\n        }\n        let left = exports.findFirstInsertionIdx(inputValues, xStart);\n        let right = exports.findLastInsertionIdx(inputValues, xEnd);\n        if (left > 0) {\n            --left;\n        }\n        if (right < inputValues.length()) {\n            ++right;\n        }\n        let lastX;\n        if (left < inputValues.length()) {\n            lastX = Math.floor(this._xValueToCoord(inputValues.get(left).x));\n            --lastX;\n        }\n        let xStartCoord;\n        if (xStart) {\n            xStartCoord = this._xValueToCoord(xStart);\n        }\n        else {\n            xStartCoord = left;\n        }\n        let lastIdx = left;\n        for (let index = left; index < right; ++index) {\n            let inputValue = inputValues.get(index);\n            let xEndCoord = Math.floor(this._xValueToCoord(inputValue.x));\n            let endIdx = index + 1;\n            if (xEndCoord !== lastX) {\n                this._decimatedValues = this._decimatedValues.concat(this._customFunc(inputValues, lastIdx, endIdx, this._yValueToCoord, this._xValueToCoord, this._xCoordToValue(xStartCoord), this._xCoordToValue(xEndCoord)));\n                xStartCoord = xEndCoord;\n                lastX = xEndCoord;\n                lastIdx = endIdx;\n            }\n        }\n        if (lastIdx !== inputValues.length()) {\n            this._decimatedValues = this._decimatedValues.concat(this._customFunc(inputValues, lastIdx, lastIdx + 1, this._yValueToCoord, this._xValueToCoord, this._xCoordToValue(xStartCoord), Number.MAX_VALUE));\n        }\n        return this._decimatedValues;\n    }\n}\nexports.CustomContinuousXYDecimator = CustomContinuousXYDecimator;\n/** used to compute the avg values for a set of data */\nclass AvgContinuousDecimator extends CustomContinuousXYDecimator {\n    constructor() {\n        super();\n        this._key = AvgContinuousDecimator.KEY;\n        this._name = 'Avg';\n        this._customFunc = computeAvg;\n    }\n}\nexports.AvgContinuousDecimator = AvgContinuousDecimator;\nAvgContinuousDecimator.KEY = 'AvgContinuousDecimator';\n;\n/** this is a helper function class that computes the summed values for each\n * Y state per each X bucket\n */\nfunction sumMultiXYSeriesValues(_xValueToCoord, _xCoordToValue, _yValueToCoord, xStart, xEnd, values) {\n    let ret = [];\n    // first this is total weighted sum per x, then used to store percentage per x\n    let tempValues = [];\n    let globalStartBucket = 0;\n    let globalEndBucket = Math.ceil(_xValueToCoord(Number.MAX_VALUE));\n    if (globalEndBucket < globalStartBucket) {\n        return undefined;\n    }\n    // NOTE: I do this up here so I can cheat and use the x values here\n    // so later I don't keep calling _xCoordToValue\n    let xBucketValues = [];\n    for (let bucket = 0; bucket <= globalEndBucket + 1; ++bucket) {\n        xBucketValues.push(_xCoordToValue(bucket));\n    }\n    // for a series get the weighted sum for the number of buckets xStart to xEnd\n    for (let stateIdx = 0; stateIdx < values.length; ++stateIdx) {\n        let perStateData = values[stateIdx];\n        let value;\n        let nextValue;\n        let start = exports.findFirstInsertionIdx(values[stateIdx], xStart);\n        let end = exports.findLastInsertionIdx(values[stateIdx], xEnd);\n        if (start > 0) {\n            --start;\n        }\n        // the last element would be caught by the algorithm already\n        if (end === perStateData.length()) {\n            --end;\n        }\n        // pad endBucket + 1 so we get data past the last point in the bucket\n        // so we can graph to the first value in the next bucket\n        tempValues[stateIdx] = Array.apply(null, Array(globalEndBucket)).\n            map(Number.prototype.valueOf, 0);\n        // get weighted sum of the values for each bucket\n        for (let rawDataIdx = start; rawDataIdx < end; ++rawDataIdx) {\n            value = perStateData.get(rawDataIdx);\n            nextValue = perStateData.get(rawDataIdx + 1);\n            let startBucket = Math.floor(_xValueToCoord(value.x));\n            let endBucket = Math.floor(_xValueToCoord(nextValue.x));\n            let totalX = (nextValue.x - value.x);\n            let valuePerX = totalX === 0 ? 0 : nextValue.y / totalX;\n            if (startBucket === endBucket) {\n                if (xStart === undefined || (value.x > xStart && nextValue.x < xEnd)) {\n                    // here it's all in the existing bucket\n                    tempValues[stateIdx][startBucket] += valuePerX;\n                }\n                else {\n                    let bucketScalar = 1 / (xBucketValues[startBucket + 1] - xBucketValues[startBucket]);\n                    if (nextValue.x < xEnd) {\n                        // here the back half is in the bucket\n                        tempValues[stateIdx][startBucket] +=\n                            (nextValue.x - xBucketValues[startBucket]) * valuePerX * bucketScalar;\n                    }\n                    else {\n                        // here the front half is in the bucket\n                        tempValues[stateIdx][startBucket] +=\n                            (xBucketValues[startBucket + 1] - value.x) * valuePerX * bucketScalar;\n                    }\n                }\n            }\n            else {\n                let bucketScalar = 1 / (xBucketValues[startBucket + 1] - xBucketValues[startBucket]);\n                let startX = xStart ? Math.max(xStart, value.x) : value.x;\n                let endStartBucket = xBucketValues[startBucket + 1];\n                tempValues[stateIdx][startBucket] +=\n                    (endStartBucket - startX) * valuePerX * bucketScalar;\n                // add in all the bucket values in between\n                for (let currBucket = startBucket + 1; currBucket < endBucket; ++currBucket) {\n                    tempValues[stateIdx][currBucket] += valuePerX;\n                }\n                // add in end bucket amount\n                bucketScalar = 1 / (xBucketValues[endBucket] - xBucketValues[endBucket - 1]);\n                let endX = xEnd ? Math.min(xEnd, nextValue.x) : nextValue.x;\n                let startEndBucket = xBucketValues[endBucket];\n                tempValues[stateIdx][endBucket] +=\n                    (endX - startEndBucket) * valuePerX * bucketScalar;\n            }\n        }\n        ret[stateIdx] = [];\n        let buckets = tempValues[stateIdx];\n        for (let bucket = 0; bucket < buckets.length; ++bucket) {\n            ret[stateIdx][bucket] = {\n                x: xBucketValues[bucket],\n                y: tempValues[stateIdx][bucket]\n            };\n        }\n    }\n    return ret;\n}\nexports.sumMultiXYSeriesValues = sumMultiXYSeriesValues;\n/** class that computes the summed values for each Y state per each X bucket */\nclass SummedValueMultiXYSeriesDecimator {\n    constructor() {\n    }\n    /**\n     * construct a generic decimator using a custom user function\n     *\n     * @param xValueToCoord converts the x value to a GUI x coordinate\n     * @param yValueToCoord converts the y value to a GUI y coordinate\n     * @param decimationFunc convert a list of data to a for rendering smaller list\n     */\n    initialize(xValueToCoord, xCoordToValue, yValueToCoord) {\n        this._xValueToCoord = xValueToCoord;\n        this._xCoordToValue = xCoordToValue;\n        this._yValueToCoord = yValueToCoord;\n    }\n    /**\n     * Returns the key of this decimator\n     */\n    getKey() {\n        return SummedValueMultiXYSeriesDecimator.KEY;\n    }\n    /**\n     * Returns the decimated list of buckets\n     */\n    getName() {\n        return '';\n    }\n    /**\n     * Returns the decimated list of buckets\n     */\n    getValues() {\n        return this._decimatedValues;\n    }\n    /**\n     * Values to be decimated\n     *\n     * @param xStart - start time of the region\n     * @param xEnd - start time of the region\n     * @param values - Values to be decimated.\n     */\n    decimateValues(xStart, xEnd, values) {\n        this._decimatedValues = sumMultiXYSeriesValues(this._xValueToCoord, this._xCoordToValue, this._yValueToCoord, xStart, xEnd, values);\n        return this._decimatedValues;\n    }\n}\nexports.SummedValueMultiXYSeriesDecimator = SummedValueMultiXYSeriesDecimator;\nSummedValueMultiXYSeriesDecimator.KEY = 'SummedValueMultiXYSeriesDecimator';\n;\n/** class that computes the residency values for each Y state per each X bucket.\n * This means the sum of all values within an output bucket is 100.\n*/\nclass ResidencyDecimator extends SummedValueMultiXYSeriesDecimator {\n    constructor() {\n        super();\n    }\n    /**\n     * Returns the key of this decimator\n     */\n    getKey() {\n        return ResidencyDecimator.KEY;\n    }\n    /**\n     * Returns the decimated list of buckets\n     */\n    getName() {\n        return '';\n    }\n    /**\n     * Values to be decimated\n     *\n     * @param xStart - start time of the region\n     * @param xEnd - start time of the region\n     * @param values - Values to be decimated.\n     */\n    decimateValues(xStart, xEnd, values) {\n        this._decimatedValues = sumMultiXYSeriesValues(this._xValueToCoord, this._xCoordToValue, this._yValueToCoord, xStart, xEnd, values);\n        // normalize all values to 100%\n        for (let bucket = 0; bucket < this._decimatedValues[0].length; ++bucket) {\n            let total = 0;\n            for (let stateIdx = 0; stateIdx < this._decimatedValues.length; ++stateIdx) {\n                if (this._decimatedValues[stateIdx][bucket].y) {\n                    total += this._decimatedValues[stateIdx][bucket].y;\n                }\n            }\n            if (total > 0) {\n                let scalar = 100 / total;\n                for (let stateIdx = 0; stateIdx < values.length; ++stateIdx) {\n                    if (this._decimatedValues[stateIdx][bucket].y) {\n                        this._decimatedValues[stateIdx][bucket].y =\n                            this._decimatedValues[stateIdx][bucket].y * scalar;\n                    }\n                }\n            }\n        }\n        return this._decimatedValues;\n    }\n}\nexports.ResidencyDecimator = ResidencyDecimator;\nResidencyDecimator.KEY = 'ResidencyDecimator';\n;\n/** class that computes the summed Y value per each X bucket */\nclass SummedValueXYSeriesDecimator {\n    constructor() {\n    }\n    /**\n     * construct a generic decimator using a custom user function\n     *\n     * @param xValueToCoord converts the x value to a GUI x coordinate\n     * @param yValueToCoord converts the y value to a GUI y coordinate\n     * @param decimationFunc convert a list of data to a for rendering smaller list\n     */\n    initialize(xValueToCoord, xCoordToValue, yValueToCoord) {\n        this._xValueToCoord = xValueToCoord;\n        this._xCoordToValue = xCoordToValue;\n        this._yValueToCoord = yValueToCoord;\n    }\n    /**\n     * Returns the name of this decimator\n     */\n    getKey() {\n        return SummedValueXYSeriesDecimator.KEY;\n    }\n    /**\n     * Returns the name of this decimator\n     */\n    getName() {\n        return '';\n    }\n    /**\n     * Returns the decimated list of buckets\n     */\n    getValues() {\n        return this._decimatedValues;\n    }\n    /**\n     * Values to be decimated\n     *\n     * @param xStart - start time of the region\n     * @param xEnd - start time of the region\n     * @param values - Values to be decimated.\n     */\n    decimateValues(xStart, xEnd, values) {\n        this._decimatedValues = sumMultiXYSeriesValues(this._xValueToCoord, this._xCoordToValue, this._yValueToCoord, xStart, xEnd, [values])[0];\n        return this._decimatedValues;\n    }\n}\nexports.SummedValueXYSeriesDecimator = SummedValueXYSeriesDecimator;\nSummedValueXYSeriesDecimator.KEY = 'SummedValueXYSeriesDecimator';\n/*************************************************************\n * NEWS (Min/Max/Entry/Exit) CHART DECIMATORS\n */\n/**\n * Internally used class for the array of values\n */\nclass NEWSDecimationValue extends data_1.CandlestickValue {\n    /**\n     * Construct a DecimationValue instance\n     *\n     * @param value - an XYValue to initialize the decimation value\n     */\n    constructor(x) {\n        super(x, undefined, undefined, undefined, undefined);\n        this._bucketPts = 0;\n    } // constructor\n} // class DecimationValue\nexports.NEWSDecimationValue = NEWSDecimationValue;\n/**\n * Data decimation to fit information to onto the graph.\n *\n * This class divides the x-Axis time range into a set of buckets.  Each\n * bucket provides the average of the values, the minimum & maximum\n * values, and the values upon entry & exit.\n * It assumes that the DB values are increase over the time.\n */\nclass NEWSBaseDecimator {\n    initialize(xValueToCoord, xCoordToValue, yValueToCoord) {\n        this._xValueToCoord = xValueToCoord;\n        this._xCoordToValue = xCoordToValue;\n        this._yValueToCoord = yValueToCoord;\n    }\n    /**\n     * Returns the key of this decimator\n     */\n    getKey() {\n        return this._key;\n    }\n    getName() {\n        return '';\n    }\n    /**\n     * Get the accumulated buckets\n     *\n     * @returns the accumulated buckets\n     */\n    getValues() {\n        return this._buckets;\n    }\n    /**\n     * Bucket dumper\n     */\n    _dumpBucket(firstTimeStamp, bucket, valuesInBucket) {\n        let details = \"valuesInBucket = \" + valuesInBucket.toFixed(0) + \", \";\n        details += \"([avg]Time delta, avgValue) = (\" +\n            (bucket.x - firstTimeStamp).toFixed(2) + \", \" + bucket.y.toFixed(2) + \"), \";\n        details += \"(entry, min, max, exit) = (\" + (bucket.entry).toFixed(2) + \", \" +\n            (bucket.min).toFixed(2) + \", \" + (bucket.max).toFixed(2) + \", \" +\n            (bucket.exit).toFixed(2) + \")\";\n        return details;\n    }\n    /**\n     * Values to be decimated\n     *\n     * @param xStart - start time of the region\n     * @param xEnd - start time of the region\n     * @param values - Values to be decimated.\n     */\n    decimateValues(xStart, xEnd, inputValues) {\n        throw 'Error need to implement decimate code';\n    }\n}\nexports.NEWSBaseDecimator = NEWSBaseDecimator;\n/** this class takes a series x, y points and using for each X bucket provides\n * the Y entry/exit/min/max/average for that X bucket\n */\nclass NEWSPointDecimator extends NEWSBaseDecimator {\n    constructor() {\n        super();\n        this._key = NEWSPointDecimator.KEY;\n    }\n    createNewBucket(decimatedValue, value) {\n        decimatedValue.entry = value.y;\n        decimatedValue.exit = value.y;\n        decimatedValue.min = value.y;\n        decimatedValue.max = value.y;\n        decimatedValue.x = 0;\n        decimatedValue.y = 0;\n        decimatedValue._bucketPts = 0;\n        this.addToBucket(decimatedValue, value);\n    }\n    /**\n     * Add an x/y value pair to this value. Both the time (x) and\n     * value (y) are added to this point/bucket\n     *\n     * @param dbPoint - The x/y value pair to add to this value.\n    */\n    addToBucket(decimatedValue, value) {\n        decimatedValue.x += value.x;\n        decimatedValue.y += value.y;\n        decimatedValue.min = Math.min(decimatedValue.min, value.y);\n        decimatedValue.max = Math.max(decimatedValue.max, value.y);\n        decimatedValue.exit = value.y;\n        decimatedValue._bucketPts++;\n    }\n    finalizeBucket(decimatedValue, pointsInBucket) {\n        if (undefined !== pointsInBucket) {\n            if (pointsInBucket !== decimatedValue._bucketPts) {\n                console.log(\"AverageTime: mismatching pt calculation\");\n            }\n        }\n        if (decimatedValue._bucketPts === 0) {\n            console.log(\"AverageTime: 0 points\");\n        }\n        decimatedValue.x = decimatedValue.x / decimatedValue._bucketPts;\n        decimatedValue.y = decimatedValue.y / decimatedValue._bucketPts;\n    }\n    /**\n     * Values to be decimated\n     *\n     * @param xStart - start time of the region\n     * @param xEnd - start time of the region\n     * @param values - Values to be decimated.\n     */\n    decimateValues(xStart, xEnd, inputValues) {\n        // loop over the data samples\n        this._buckets = [];\n        if (inputValues.length() === 0) {\n            return this._buckets;\n        }\n        let currentPoint;\n        let left = exports.findFirstInsertionIdx(inputValues, xStart);\n        let right = exports.findLastInsertionIdx(inputValues, xEnd);\n        if (left > 0) {\n            --left;\n        }\n        if (right < inputValues.length()) {\n            ++right;\n        }\n        let lastX = 0;\n        if (left < inputValues.length()) {\n            lastX = Math.floor(this._xValueToCoord(inputValues.get(left).x));\n            --lastX;\n        }\n        for (let index = left; index < right; ++index) {\n            let inputValue = inputValues.get(index);\n            let xCoord = Math.floor(this._xValueToCoord(inputValue.x));\n            if (xCoord !== lastX) {\n                if (currentPoint) {\n                    this.finalizeBucket(currentPoint);\n                    this._buckets.push(currentPoint);\n                }\n                currentPoint = new NEWSDecimationValue();\n                this.createNewBucket(currentPoint, inputValue);\n                lastX = xCoord;\n            }\n            else {\n                this.addToBucket(currentPoint, inputValue);\n            }\n        }\n        if (currentPoint) {\n            this.finalizeBucket(currentPoint);\n            this._buckets.push(currentPoint);\n        }\n        return this._buckets;\n    } // decimateValues()\n} // class NEWSDecimator\nexports.NEWSPointDecimator = NEWSPointDecimator;\nNEWSPointDecimator.KEY = 'NEWSPointDecimator';\n/** this class takes a series x, y points and using for each X bucket provides\n * the Y entry/exit/min/max/average for that X bucket\n */\nclass NEWSStateDecimator extends NEWSBaseDecimator {\n    constructor(states) {\n        super();\n        this._weightedSums = {};\n        this._prevX = 0;\n        this._prevX = 0;\n        this._key = NEWSStateDecimator.KEY;\n        if (states) {\n            this._states = states;\n        }\n    }\n    createNewBucket(decimatedValue, value) {\n        this._weightedSums = {};\n        decimatedValue._bucketPts = 0;\n        let defaultValue;\n        if (!this._isYObject) {\n            defaultValue = value.y;\n            decimatedValue.x = 0;\n            decimatedValue.y = defaultValue;\n            decimatedValue.entry = defaultValue;\n            decimatedValue.exit = defaultValue;\n            decimatedValue.min = defaultValue;\n            decimatedValue.max = defaultValue;\n        }\n        this.addToBucket(decimatedValue, value);\n    }\n    ;\n    addToStateValueToBucket(state, value) {\n        if (value === 0) {\n            return;\n        }\n        if (!this._weightedSums[state]) {\n            this._weightedSums[state] = 0;\n        }\n        this._weightedSums[state] += value;\n    }\n    addToBucket(decimatedValue, value) {\n        if (this._isYObject) {\n            if (this._states) {\n                // take prevX and currentX\n                for (let stateKey in value.y) {\n                    this.addToStateValueToBucket(this._states[stateKey], (value.x - this._prevX) * value.y[stateKey]);\n                }\n            }\n            else {\n                // take prevX and currentX\n                for (let state in value.y) {\n                    this.addToStateValueToBucket(state, (value.x - this._prevX) * value.y[state]);\n                }\n            }\n        }\n        else {\n            let state;\n            if (this._states) {\n                state = this._states[value.y];\n            }\n            else {\n                state = value.y;\n            }\n            decimatedValue.exit = state;\n            this.addToStateValueToBucket(state, (value.x - this._prevX));\n        }\n        decimatedValue.x += value.x;\n        decimatedValue._bucketPts++;\n        this._prevX = value.x;\n    }\n    finalizeBucket(decimatedValue, pointsInBucket) {\n        if (undefined !== pointsInBucket) {\n            if (pointsInBucket !== decimatedValue._bucketPts) {\n                console.log(\"AverageTime: mismatching pt calculation\");\n            }\n        }\n        if (decimatedValue._bucketPts === 0) {\n            console.log(\"AverageTime: 0 points\");\n        }\n        decimatedValue.x = decimatedValue.x / decimatedValue._bucketPts;\n        // find the maximum value by weightedSums\n        var maxWeightedKey;\n        var maxWeightValue = -Number.MAX_VALUE;\n        let minState = -Number.MAX_VALUE;\n        let maxState = Number.MAX_VALUE;\n        for (let state in this._weightedSums) {\n            if (this._weightedSums[state] !== undefined) {\n                let stateWeight = this._weightedSums[state];\n                if (stateWeight > maxWeightValue) {\n                    maxWeightedKey = state;\n                    maxWeightValue = stateWeight;\n                }\n            }\n            // min is bigger since Y values increase as you go down the axis\n            let yOffset = this._yValueToCoord(state);\n            if (yOffset > minState) {\n                decimatedValue.min = state;\n                minState = yOffset;\n            }\n            if (yOffset < maxState) {\n                decimatedValue.max = state;\n                maxState = yOffset;\n            }\n        }\n        let hasValues = maxWeightedKey !== undefined;\n        if (hasValues) {\n            decimatedValue.y = maxWeightedKey;\n        }\n        else {\n            // no values so set a default a y value\n            if (!this._isYObject) {\n                decimatedValue.min = decimatedValue.y;\n                decimatedValue.max = decimatedValue.y;\n            }\n        }\n    } // finalize );\n    /**\n     * Values to be decimated\n     *\n     * @param xStart - start time of the region\n     * @param xEnd - start time of the region\n     * @param values - Values to be decimated.\n     */\n    decimateValues(xStart, xEnd, inputValues) {\n        // loop over the data samples\n        this._buckets = [];\n        if (inputValues.length() === 0) {\n            return this._buckets;\n        }\n        let currentPoint;\n        let left = exports.findFirstInsertionIdx(inputValues, xStart);\n        let right = exports.findLastInsertionIdx(inputValues, xEnd);\n        if (left > 0) {\n            --left;\n        }\n        if (right < inputValues.length()) {\n            ++right;\n        }\n        let lastX = 0;\n        if (left < inputValues.length()) {\n            this._isYObject = typeof (inputValues.get(left).y) === 'object';\n            lastX = Math.floor(this._xValueToCoord(inputValues.get(left).x));\n            --lastX;\n        }\n        for (let index = left; index < right; ++index) {\n            let inputValue = inputValues.get(index);\n            let xCoord = Math.floor(this._xValueToCoord(inputValue.x));\n            if (xCoord !== lastX) {\n                if (currentPoint) {\n                    this.finalizeBucket(currentPoint);\n                    this._buckets.push(currentPoint);\n                }\n                // add in buckets between the previous bucket and the new bucket since\n                // the state spans the whole time\n                if (lastX + 1 < xCoord) {\n                    let point = new NEWSDecimationValue();\n                    this.createNewBucket(point, inputValue);\n                    this.finalizeBucket(point);\n                    point.x = this._xCoordToValue(xCoord - 1);\n                    this._buckets.push(point);\n                    this._prevX = point.x;\n                }\n                currentPoint = new NEWSDecimationValue();\n                this.createNewBucket(currentPoint, inputValue);\n                lastX = xCoord;\n            }\n            else {\n                this.addToBucket(currentPoint, inputValue);\n            }\n        }\n        if (currentPoint) {\n            this.finalizeBucket(currentPoint);\n            this._buckets.push(currentPoint);\n        }\n        return this._buckets;\n    } // decimateValues()\n}\nexports.NEWSStateDecimator = NEWSStateDecimator;\nNEWSStateDecimator.KEY = 'NEWSStateDecimator';\n;\nclass FlameChartRectLimitDecimator {\n    initialize(xValueToCoord, xCoordToValue, yValueToCoord) {\n        this._data = [];\n        this._xValueToCoord = xValueToCoord;\n        this._xCoordToValue = xCoordToValue;\n        this._yValueToCoord = yValueToCoord;\n    }\n    /**\n     * Returns the key of this decimator\n     */\n    getKey() {\n        return FlameChartRectLimitDecimator.KEY;\n    }\n    /**\n     * the name of this decimation scheme\n     */\n    getName() {\n        return '';\n    }\n    /**\n     * Returns the decimated list of data\n     */\n    getValues() {\n        return this._data;\n    }\n    setRectLimit(rectLimit) {\n        this._rectLimit = rectLimit;\n        return this;\n    }\n    /**\n     * Values to be decimated\n     *\n     * @param xStart - start time of the region\n     * @param xEnd - start time of the region\n     * @param values - Values to be decimated.\n     */\n    decimateValues(xStart, xEnd, values) {\n        // using the whole view\n        this._data = [];\n        let rects = values.getData();\n        for (let i = 0; i < rects.length; ++i) {\n            this._data = this._data.concat(rects[i]);\n        }\n        if (this._rectLimit) {\n            this._data.sort(function (a, b) {\n                if (a.traceValue.dx > b.traceValue.dx) {\n                    return -1;\n                }\n                if (a.traceValue.dx < b.traceValue.dx) {\n                    return 1;\n                }\n                return 0;\n            });\n            this._data = this._data.splice(0, this._rectLimit);\n        }\n        return this._data;\n    }\n}\nexports.FlameChartRectLimitDecimator = FlameChartRectLimitDecimator;\nFlameChartRectLimitDecimator.KEY = 'FlameChartRectLimitDecimator';\n;\n/** this decimator merges the rectangles in a flame chart to combine\n * identical rectangles that are touching on a left/right pixel basis so\n * we can merge them for rendering\n */\nclass FlameChartMergeRectDecimator {\n    constructor() {\n        this._minRectDelta = 1;\n    }\n    initialize(xValueToCoord, xCoordToValue, yValueToCoord) {\n        this._data = [];\n        this._xValueToCoord = xValueToCoord;\n        this._xCoordToValue = xCoordToValue;\n        this._yValueToCoord = yValueToCoord;\n    }\n    /**\n     * Returns the key of this decimator\n     */\n    getKey() {\n        return FlameChartMergeRectDecimator.KEY;\n    }\n    /**\n     * the name of this decimation scheme\n     */\n    getName() {\n        return '';\n    }\n    /**\n     * Returns the decimated list of data\n     */\n    getValues() {\n        return this._data;\n    }\n    /**\n     * Set the minimum width of a rectangle.  If there is multiple trace points\n     * within the the minimum width then the data is merged together into\n     * a single rectangle.  Once all data in a rectangle is merged then we call\n     * the [setUserPixelFunction] callback so the the user can modify the value\n     * to be rendered if needed\n     *\n     * @param width the minimum width of a pixel in which data is grouped together\n     */\n    setPixelWidth(width) {\n        this._minRectDelta = width - 1;\n        return this;\n    }\n    setUserPixelFunction(cb) {\n        this._userPixelFunction = cb;\n    }\n    /**\n     * used to generate a list of all rects that could be drawn sorted by duration\n     */\n    mergeRects(values) {\n        let ret = [];\n        // get the width of a pixel\n        let buckets = Math.ceil(this._xValueToCoord(Number.MAX_VALUE)) + 1;\n        // NOTE: I do this up here so I can cheat and use the x values here\n        // so later I don't keep calling this._xCoordToValue\n        let xBucketValues = [];\n        for (let bucket = 0; bucket <= buckets; ++bucket) {\n            xBucketValues.push(this._xCoordToValue(bucket));\n        }\n        // get the width of a pixel so we can force it to be visible by\n        // making the rect width value 1 full pixel delta wide\n        let bucketValueWidth = 0;\n        if (buckets > 1) {\n            bucketValueWidth = this._xCoordToValue(1) - this._xCoordToValue(0);\n        }\n        // compute merged rects\n        for (let i = 0; i < values.length; ++i) {\n            let perLevelData = values[i];\n            if (perLevelData === undefined) {\n                continue;\n            }\n            let mergedLevelData = [];\n            let prevValue;\n            let mergeBucketEnd = -Number.MAX_VALUE;\n            let startXCoord;\n            let endXCoord;\n            // first we walk over all the data and create rects with at least\n            // the minimum width which is specified by this._minPixelWidth\n            let len = perLevelData.length;\n            for (let j = 0; j < len; j++) {\n                let value = perLevelData[j];\n                // check if you need to do a simple merge with the previous identical rectangle\n                if (prevValue && prevValue.traceValue.key === value.traceValue.key &&\n                    prevValue.traceValue.x + prevValue.traceValue.dx === value.traceValue.x) {\n                    prevValue.traceValue.dx += value.traceValue.dx;\n                    continue;\n                }\n                startXCoord = Math.floor(this._xValueToCoord(value.traceValue.x));\n                // check if we already partially counted this sample\n                if (mergeBucketEnd > startXCoord) {\n                    startXCoord = mergeBucketEnd;\n                }\n                endXCoord = Math.floor(this._xValueToCoord(value.traceValue.x + value.traceValue.dx));\n                let fcValue;\n                if (endXCoord - startXCoord > this._minRectDelta) {\n                    // if this single trace value rectangle is wide enough to be rendered by itself\n                    fcValue = {\n                        traceValue: {\n                            x: xBucketValues[startXCoord],\n                            dx: xBucketValues[endXCoord] - xBucketValues[startXCoord],\n                            key: value.traceValue.key,\n                            name: value.traceValue.name,\n                            desc: value.traceValue.desc,\n                        },\n                        decimatedValues: [value.traceValue],\n                        depth: value.depth\n                    };\n                }\n                else {\n                    // might have to merge with other rectangles\n                    let subpixelMap = {};\n                    let valueList = [];\n                    // set this so we know when to stop merging data for this rectangle\n                    mergeBucketEnd = startXCoord + this._minRectDelta;\n                    // add in the initial weight\n                    if (value.traceValue.x < xBucketValues[startXCoord]) {\n                        subpixelMap[value.traceValue.name] = value.traceValue.x + value.traceValue.dx - xBucketValues[startXCoord];\n                    }\n                    else {\n                        subpixelMap[value.traceValue.name] = value.traceValue.dx;\n                    }\n                    valueList.push(value.traceValue);\n                    // before adding the next item iterate to a point where the next\n                    // value starts in the next pixel for the given depth`\n                    for (++j; j < len; ++j) {\n                        value = perLevelData[j];\n                        let localStartXCoord = Math.floor(this._xValueToCoord(value.traceValue.x));\n                        if (localStartXCoord >= mergeBucketEnd) {\n                            // back up to the last item that broke the subpixel\n                            // iteration loop so it can be handled by the outer loop\n                            --j;\n                            break;\n                        }\n                        else {\n                            valueList.push(value.traceValue);\n                            // if we have multiple items in the end pixel add up the\n                            // the durations and find the one with the most weight\n                            if (!subpixelMap.hasOwnProperty(value.traceValue.name)) {\n                                subpixelMap[value.traceValue.name] = 0;\n                            }\n                            if (value.traceValue.x + value.traceValue.dx > xBucketValues[mergeBucketEnd]) {\n                                subpixelMap[value.traceValue.name] += xBucketValues[mergeBucketEnd] - value.traceValue.x;\n                                // back up to the last item that broke the subpixel\n                                // iteration loop so it can be handled by the outer loop\n                                --j;\n                                break;\n                            }\n                            else {\n                                subpixelMap[value.traceValue.name] += value.traceValue.dx;\n                            }\n                        }\n                    }\n                    let lastTraceValue = valueList[valueList.length - 1];\n                    if (valueList.length === 1) {\n                        // if we have just one item just add it to the trace\n                        fcValue = {\n                            traceValue: {\n                                x: xBucketValues[startXCoord],\n                                dx: xBucketValues[endXCoord] - xBucketValues[startXCoord],\n                                key: lastTraceValue.key,\n                                name: lastTraceValue.name,\n                                desc: lastTraceValue.desc,\n                            },\n                            decimatedValues: valueList,\n                            depth: value.depth\n                        };\n                    }\n                    else {\n                        // find the subpixel value with the most weight\n                        let pixelName;\n                        let max = 0;\n                        for (let name in subpixelMap) {\n                            let groupWeight = subpixelMap[name];\n                            if (groupWeight > max) {\n                                pixelName = name;\n                                max = groupWeight;\n                            }\n                        }\n                        fcValue = {\n                            traceValue: {\n                                x: xBucketValues[startXCoord],\n                                dx: mergeBucketEnd < xBucketValues.length ? xBucketValues[mergeBucketEnd] - xBucketValues[startXCoord] :\n                                    xBucketValues[startXCoord] + bucketValueWidth,\n                                key: 'merged',\n                                name: pixelName,\n                                desc: lastTraceValue.desc,\n                            },\n                            decimatedValues: valueList,\n                            depth: value.depth\n                        };\n                    }\n                }\n                mergedLevelData.push(fcValue);\n                // update the last value for this level\n                prevValue = fcValue;\n            }\n            // now that we have computed rects and their the subpixel values\n            // if applicable we actually go through and clean things up and then\n            // merge the rects for rendering performance\n            prevValue = undefined;\n            let lastTs = 0;\n            let isNewValue = true;\n            for (let j = 0; j < mergedLevelData.length; ++j) {\n                isNewValue = true;\n                let value = mergedLevelData[j];\n                if (value.traceValue.dx < bucketValueWidth) {\n                    // first make the rectangles at least 1 pixel wide\n                    value.traceValue.dx = bucketValueWidth;\n                }\n                if (this._userPixelFunction) {\n                    // let the user clean up the flame chart value if they want\n                    value = this._userPixelFunction(value);\n                }\n                // now actually merge the rects\n                if (prevValue && prevValue.traceValue.key === value.traceValue.key &&\n                    prevValue.traceValue.name === value.traceValue.name) {\n                    lastTs = prevValue.traceValue.x + prevValue.traceValue.dx;\n                    if (lastTs >= value.traceValue.x) {\n                        prevValue.traceValue.dx = value.traceValue.x + value.traceValue.dx - prevValue.traceValue.x;\n                        prevValue.decimatedValues.concat(value.decimatedValues);\n                        isNewValue = false;\n                    }\n                }\n                if (isNewValue) {\n                    ret.push(value);\n                    prevValue = value;\n                }\n            }\n        }\n        return ret;\n    }\n    /**\n     * Values to be decimated\n     *\n     * @param xStart - start time of the region\n     * @param xEnd - start time of the region\n     * @param values - Values to be decimated.\n     */\n    decimateValues(xStart, xEnd, values) {\n        // using the whole view\n        this._data = this.mergeRects(values.getData());\n        return this._data;\n    }\n}\nexports.FlameChartMergeRectDecimator = FlameChartMergeRectDecimator;\nFlameChartMergeRectDecimator.KEY = 'FlameChartMergeRectDecimator';\n;\n/**\n * Takes ITraceValue data and for each bucket returns a residency value\n * by ITracevalue.name. This means the sum of all values within an output bucket is 100.\n */\nclass TraceResidencyDecimator {\n    initialize(xValueToCoord, xCoordToValue, yValueToCoord, states) {\n        this._decimatedValues = [];\n        this._xValueToCoord = xValueToCoord;\n        this._xCoordToValue = xCoordToValue;\n        this._yValueToCoord = yValueToCoord;\n        this._states = states;\n    }\n    /**\n     * Returns the key of this decimator\n     */\n    getKey() {\n        return TraceResidencyDecimator.KEY;\n    }\n    /**\n     * the name of this decimation scheme\n     */\n    getName() {\n        return '';\n    }\n    /**\n     * Returns the decimated list of data\n     */\n    getValues() {\n        return this._decimatedValues;\n    }\n    /**\n   * Values to be decimated\n   *\n   * @param xStart - start time of the region\n   * @param xEnd - start time of the region\n   * @param values - Values to be decimated.\n   */\n    decimateValues(xStart, xEnd, values) {\n        this._decimatedValues = new Array(this._states.length).fill(0).map(() => new Array());\n        let globalStartBucket = 0;\n        let globalEndBucket = Math.ceil(this._xValueToCoord(Number.MAX_VALUE));\n        if (globalEndBucket < globalStartBucket) {\n            return undefined;\n        }\n        // this is total weighted sum for each state per x, then used to store percentage per x\n        let tempValues = {};\n        // map states to return index\n        let stateMap = {};\n        this._states.forEach((state, index) => {\n            stateMap[state] = index;\n            tempValues[state] = Array.apply(null, Array(globalEndBucket)).\n                map(Number.prototype.valueOf, 0);\n        });\n        // set up the values for iteration\n        // for a series get the weighted sum for the number of buckets xStart to xEnd\n        let value;\n        let traceEndX;\n        let start = exports.findFirstInsertionIdx(values, xStart);\n        let end = exports.findLastInsertionIdx(values, xEnd);\n        if (start > 0) {\n            --start;\n        }\n        // NOTE: I do this up here so I can cheat and use the x values here\n        // so later I don't keep calling this._xCoordToValue\n        let xBucketValues = [];\n        for (let bucket = 0; bucket <= globalEndBucket; ++bucket) {\n            xBucketValues.push(this._xCoordToValue(bucket));\n        }\n        // this is the amount of x values within a given bucket\n        let bucketScalar = 1 / (xBucketValues[globalStartBucket + 1] - xBucketValues[globalStartBucket]);\n        // get weighted sum of the values for each bucket\n        // note this is forward looking data unlike most of our data so\n        // the algorithm is a little different\n        for (let rawDataIdx = start; rawDataIdx < end; ++rawDataIdx) {\n            value = values.get(rawDataIdx);\n            traceEndX = value.x + value.dx;\n            let startBucket = Math.floor(this._xValueToCoord(value.x));\n            let endBucket = Math.floor(this._xValueToCoord(traceEndX));\n            if (startBucket === endBucket) {\n                tempValues[value.name][startBucket] += value.dx * bucketScalar;\n                // TODO consider we should/can fix this corner case\n                // Code below is technically more correct as it handles some edge cases\n                // but it's about 3x slower?\n                // if (xStart === undefined || (value.x > xStart && traceEndX < xEnd)) {\n                //     // here it's all in the existing bucket\n                //     tempValues[value.name][startBucket] += value.dx * bucketScalar;\n                // } else if (traceEndX > xStart) {\n                //     if (traceEndX < xEnd) {\n                //         // here the back half is in the bucket\n                //         tempValues[value.name][startBucket] += (traceEndX - xStart) * bucketScalar;\n                //     } else {\n                //         // here the front half is in the bucket\n                //         tempValues[value.name][startBucket] += (xEnd - value.x) * bucketScalar;\n                //     }\n                // }\n            }\n            else {\n                // add in start bucket amount\n                let startX = xStart ? Math.max(xStart, value.x) : value.x;\n                let endStartBucket = xBucketValues[startBucket + 1];\n                tempValues[value.name][startBucket] += (endStartBucket - startX) * bucketScalar;\n                // add in all the bucket values in between\n                for (let currBucket = startBucket + 1; currBucket < endBucket; ++currBucket) {\n                    tempValues[value.name][currBucket] += 1;\n                }\n                // add in end bucket amount\n                let endX = xEnd ? Math.min(xEnd, traceEndX) : traceEndX;\n                let startEndBucket = xBucketValues[endBucket];\n                tempValues[value.name][endBucket] += (endX - startEndBucket) * bucketScalar;\n            }\n        }\n        // create an array that is used when this state wasn't seen at\n        // all in the time region.\n        let emptyArray = [];\n        for (let bucket = 0; bucket < globalEndBucket; ++bucket) {\n            emptyArray[bucket] = {\n                x: xBucketValues[bucket],\n                y: 0\n            };\n        }\n        for (let stateIdx = 0; stateIdx < this._states.length; ++stateIdx) {\n            let buckets = tempValues[this._states[stateIdx]];\n            if (buckets) {\n                for (let bucket = 0; bucket < buckets.length; ++bucket) {\n                    let y = tempValues[this._states[stateIdx]][bucket] ?\n                        tempValues[this._states[stateIdx]][bucket] : 0;\n                    this._decimatedValues[stateIdx][bucket] = {\n                        x: xBucketValues[bucket],\n                        y: y * 100\n                    };\n                }\n            }\n            else {\n                this._decimatedValues[stateIdx] = emptyArray;\n            }\n        }\n        return this._decimatedValues;\n    }\n}\nexports.TraceResidencyDecimator = TraceResidencyDecimator;\nTraceResidencyDecimator.KEY = 'TraceResidencyDecimator';\n;\n/**\n* Takes ITraceValue data and for each bucket returns a sum by ITracevalue.name.\n* This means the sum of all values within an output bucket is 100.\n*/\nclass TraceStateDecimator {\n    initialize(xValueToCoord, xCoordToValue, yValueToCoord, states) {\n        this._decimatedValues = [];\n        this._xValueToCoord = xValueToCoord;\n        this._xCoordToValue = xCoordToValue;\n        this._yValueToCoord = yValueToCoord;\n        this._states = states;\n    }\n    /**\n     * Returns the key of this decimator\n     */\n    getKey() {\n        return TraceStateDecimator.KEY;\n    }\n    /**\n     * the name of this decimation scheme\n     */\n    getName() {\n        return '';\n    }\n    /**\n     * Returns the decimated list of data\n     */\n    getValues() {\n        return this._decimatedValues;\n    }\n    /**\n   * Values to be decimated\n   *\n   * @param xStart - start time of the region\n   * @param xEnd - start time of the region\n   * @param values - Values to be decimated.\n   */\n    decimateValues(xStart, xEnd, values) {\n        let globalStartBucket = 0;\n        let globalEndBucket = Math.ceil(this._xValueToCoord(Number.MAX_VALUE));\n        if (globalEndBucket < globalStartBucket) {\n            return undefined;\n        }\n        // set up the values for iteration\n        // for a series get the weighted sum for the number of buckets xStart to xEnd\n        let value;\n        let traceEndX;\n        let start = exports.findFirstInsertionIdx(values, xStart);\n        let end = exports.findLastInsertionIdx(values, xEnd);\n        if (start > 0) {\n            --start;\n        }\n        // NOTE: I do this up here so I can cheat and use the x values here\n        // so later I don't keep calling this._xCoordToValue\n        this._decimatedValues = [];\n        for (let bucket = 0; bucket <= globalEndBucket; ++bucket) {\n            this._decimatedValues[bucket] = new NEWSDecimationValue(this._xCoordToValue(bucket));\n        }\n        let states = {};\n        this._states.forEach((state, i) => {\n            states[state] = i;\n        });\n        // store the entry/exit/min/max of each bucket\n        // min and max are based on the state index\n        for (let rawDataIdx = start; rawDataIdx < end; ++rawDataIdx) {\n            value = values.get(rawDataIdx);\n            traceEndX = value.x + value.dx;\n            let startBucket = Math.floor(this._xValueToCoord(value.x));\n            let endBucket = Math.floor(this._xValueToCoord(traceEndX));\n            if (!this._decimatedValues[startBucket].entry) {\n                this._decimatedValues[startBucket].entry = states[value.name];\n                this._decimatedValues[startBucket].exit = states[value.name];\n                this._decimatedValues[startBucket].min = states[value.name];\n                this._decimatedValues[startBucket].max = states[value.name];\n            }\n            if (startBucket === endBucket) {\n                this._decimatedValues[startBucket].exit = states[value.name];\n                this._decimatedValues[startBucket].min =\n                    Math.min(this._decimatedValues[startBucket].min, states[value.name]);\n                this._decimatedValues[startBucket].max =\n                    Math.max(this._decimatedValues[startBucket].max, states[value.name]);\n            }\n            else {\n                // start bucket exit\n                this._decimatedValues[startBucket].exit = states[value.name];\n                this._decimatedValues[startBucket].min =\n                    Math.min(this._decimatedValues[startBucket].min, states[value.name]);\n                this._decimatedValues[startBucket].max =\n                    Math.max(this._decimatedValues[startBucket].max, states[value.name]);\n                // add in all the bucket values in between\n                for (let currBucket = startBucket + 1; currBucket <= endBucket; ++currBucket) {\n                    this._decimatedValues[currBucket].entry = states[value.name];\n                    this._decimatedValues[currBucket].exit = states[value.name];\n                    this._decimatedValues[currBucket].min = states[value.name];\n                    this._decimatedValues[currBucket].max = states[value.name];\n                }\n            }\n        }\n        // convert state index to actual state names for rendering\n        for (let i = 0; i < this._decimatedValues.length; ++i) {\n            let newsValue = this._decimatedValues[i];\n            let exit = newsValue.exit;\n            newsValue.entry = this._states[newsValue.entry];\n            newsValue.exit = this._states[exit];\n            newsValue.y = this._states[exit];\n            newsValue.min = this._states[newsValue.min];\n            newsValue.max = this._states[newsValue.max];\n        }\n        return this._decimatedValues;\n    }\n}\nexports.TraceStateDecimator = TraceStateDecimator;\nTraceStateDecimator.KEY = 'TraceStateDecimator';\n;\n/**\n * For a marker layer just removes markers that have the same X value\n */\nclass SimpleMarkerDecimator {\n    initialize(xValueToCoord, xCoordToValue, yValueToCoord) {\n        this._data = [];\n        this._xValueToCoord = xValueToCoord;\n        this._xCoordToValue = xCoordToValue;\n        this._yValueToCoord = yValueToCoord;\n    }\n    /**\n     * Returns the key of this decimator\n     */\n    getKey() {\n        return SimpleMarkerDecimator.KEY;\n    }\n    /**\n     * the name of this decimation scheme\n     */\n    getName() {\n        return '';\n    }\n    /**\n     * Returns the decimated list of data\n     */\n    getValues() {\n        return this._data;\n    }\n    mergeMarkers(values) {\n        let ret = [];\n        let lastCoord = -Number.MAX_VALUE;\n        for (let i = 0; i < values.length; ++i) {\n            let value = values[i];\n            let coord = this._xValueToCoord(value.x);\n            if (coord !== lastCoord) {\n                ret.push(value);\n                lastCoord = coord;\n            }\n        }\n        return ret;\n    }\n    /**\n     * Values to be decimated\n     *\n     * @param xStart - start time of the region\n     * @param xEnd - start time of the region\n     * @param values - Values to be decimated.\n     */\n    decimateValues(xStart, xEnd, values) {\n        let allData = values.getData();\n        // using the whole view\n        if (xStart !== undefined && xEnd !== undefined) {\n            let filteredData = [];\n            for (let i = 0; i < allData.length; ++i) {\n                let value = allData[i];\n                if (value.x < xEnd && value.x > xStart) {\n                    filteredData.push(value);\n                }\n                else if (value.dx && value.x + value.dx < xEnd &&\n                    value.x + value.dx > xStart) {\n                    filteredData.push(value);\n                }\n            }\n            this._data = this.mergeMarkers(filteredData);\n        }\n        else {\n            this._data = this.mergeMarkers(allData);\n        }\n        return this._data;\n    }\n}\nexports.SimpleMarkerDecimator = SimpleMarkerDecimator;\nSimpleMarkerDecimator.KEY = 'SimpleMarkerDecimator';\n;\n/** */\nclass XYHeatMapDecimator {\n    constructor() {\n    }\n    /**\n     * construct a generic decimator using a custom user function\n     *\n     * @param xValueToCoord converts the x value to a GUI x coordinate\n     * @param yValueToCoord converts the y value to a GUI y coordinate\n     * @param decimationFunc convert a list of data to a for rendering smaller list\n     */\n    initialize(xValueToCoord, xCoordToValue, yValueToCoord) {\n        this._xValueToCoord = xValueToCoord;\n        this._xCoordToValue = xCoordToValue;\n        this._yValueToCoord = yValueToCoord;\n    }\n    /**\n     * Returns the key of this decimator\n     */\n    getKey() {\n        return SummedValueMultiXYSeriesDecimator.KEY;\n    }\n    /**\n     * Returns the decimated list of buckets\n     */\n    getName() {\n        return '';\n    }\n    /**\n     * Returns the decimated list of buckets\n     */\n    getValues() {\n        return this._decimatedValues;\n    }\n    /**\n     * Values to be decimated\n     *\n     * @param xStart - start time of the region\n     * @param xEnd - start time of the region\n     * @param values - Values to be decimated.\n     */\n    decimateValues(xStart, xEnd, values) {\n        this._decimatedValues = [];\n        // first this is total weighted sum per x, then used to store percentage per x\n        let tempValues = [];\n        let globalStartBucket = 0;\n        let globalEndBucket = Math.ceil(this._xValueToCoord(Number.MAX_VALUE));\n        if (globalEndBucket < globalStartBucket) {\n            return undefined;\n        }\n        // NOTE: I do this up here so I can cheat and use the x values here\n        // so later I don't keep calling _xCoordToValue\n        let xBucketValues = [];\n        for (let bucket = 0; bucket <= globalEndBucket + 1; ++bucket) {\n            xBucketValues.push(this._xCoordToValue(bucket));\n        }\n        // for a series get the weighted sum for the number of buckets xStart to xEnd\n        for (let stateIdx = 0; stateIdx < values.length; ++stateIdx) {\n            let perStateData = values[stateIdx];\n            let value;\n            let nextValue;\n            let start = exports.findFirstInsertionIdx(values[stateIdx], xStart);\n            let end = exports.findLastInsertionIdx(values[stateIdx], xEnd);\n            if (start > 0) {\n                --start;\n            }\n            // the last element would be caught by the algorithm already\n            if (end === perStateData.length()) {\n                --end;\n            }\n            // pad endBucket + 1 so we get data past the last point in the bucket\n            // so we can graph to the first value in the next bucket\n            tempValues[stateIdx] = Array.apply(null, Array(globalEndBucket)).\n                map(Number.prototype.valueOf, 0);\n            // get weighted sum of the values for each bucket\n            for (let rawDataIdx = start; rawDataIdx < end; ++rawDataIdx) {\n                value = perStateData.get(rawDataIdx);\n                nextValue = perStateData.get(rawDataIdx + 1);\n                let startBucket = Math.floor(this._xValueToCoord(value.x));\n                let endBucket = Math.floor(this._xValueToCoord(nextValue.x));\n                let totalX = (nextValue.x - value.x);\n                let valuePerX = totalX === 0 ? 0 : nextValue.y / totalX;\n                if (startBucket === endBucket) {\n                    if (xStart === undefined || (value.x > xStart && nextValue.x < xEnd)) {\n                        // here it's all in the existing bucket\n                        tempValues[stateIdx][startBucket] += valuePerX;\n                    }\n                    else {\n                        let bucketScalar = 1 / (xBucketValues[startBucket + 1] - xBucketValues[startBucket]);\n                        if (nextValue.x < xEnd) {\n                            // here the back half is in the bucket\n                            tempValues[stateIdx][startBucket] +=\n                                (nextValue.x - xBucketValues[startBucket]) * valuePerX * bucketScalar;\n                        }\n                        else {\n                            // here the front half is in the bucket\n                            tempValues[stateIdx][startBucket] +=\n                                (xBucketValues[startBucket + 1] - value.x) * valuePerX * bucketScalar;\n                        }\n                    }\n                }\n                else {\n                    let bucketScalar = 1 / (xBucketValues[startBucket + 1] - xBucketValues[startBucket]);\n                    let startX = xStart ? Math.max(xStart, value.x) : value.x;\n                    let endStartBucket = xBucketValues[startBucket + 1];\n                    tempValues[stateIdx][startBucket] +=\n                        (endStartBucket - startX) * valuePerX * bucketScalar;\n                    // add in all the bucket values in between\n                    for (let currBucket = startBucket + 1; currBucket < endBucket; ++currBucket) {\n                        tempValues[stateIdx][currBucket] += valuePerX;\n                    }\n                    // add in end bucket amount\n                    bucketScalar = 1 / (xBucketValues[endBucket] - xBucketValues[endBucket - 1]);\n                    let endX = xEnd ? Math.min(xEnd, nextValue.x) : nextValue.x;\n                    let startEndBucket = xBucketValues[endBucket];\n                    tempValues[stateIdx][endBucket] +=\n                        (endX - startEndBucket) * valuePerX * bucketScalar;\n                }\n            }\n            this._decimatedValues[stateIdx] = [];\n            let buckets = tempValues[stateIdx];\n            for (let bucket = 0; bucket < buckets.length; ++bucket) {\n                this._decimatedValues[stateIdx][bucket] = {\n                    x: xBucketValues[bucket],\n                    y: tempValues[stateIdx][bucket] ? tempValues[stateIdx][bucket] : 0\n                };\n            }\n        }\n        return this._decimatedValues;\n    }\n}\nexports.XYHeatMapDecimator = XYHeatMapDecimator;\nXYHeatMapDecimator.KEY = 'XYHeatMapDecimator';\n;\nlet decimatorList = [\n    new ResidencyDecimator(), new MinPointDecimator(),\n    new AvgPointDecimator(), new MaxPointDecimator(), new AvgContinuousDecimator(),\n    new FlameChartMergeRectDecimator(), new FlameChartRectLimitDecimator(),\n    new NEWSPointDecimator(), new NEWSStateDecimator(), new SimpleMarkerDecimator(),\n    new XYPointDecimator(), new SummedValueXYSeriesDecimator(),\n    new SummedValueMultiXYSeriesDecimator(), new TraceResidencyDecimator()\n];\nexports.InternalDecimatorMap = {};\ndecimatorList.forEach(function (decimator) {\n    exports.InternalDecimatorMap[decimator.getKey()] = decimator;\n});\n//# sourceURL=[module]\n//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiLi9zcmMvY29yZS9jYXJ0ZXNpYW4vZGVjaW1hdG9yL2RlY2ltYXRvci50cy5qcyIsInNvdXJjZXMiOlsid2VicGFjazovL1VXVC8uL3NyYy9jb3JlL2NhcnRlc2lhbi9kZWNpbWF0b3IvZGVjaW1hdG9yLnRzPzc5MjIiXSwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHtcbiAgICBJWFlWYWx1ZSwgSUZsYW1lQ2hhcnRWYWx1ZSwgSVRyYWNlVmFsdWVcbn0gZnJvbSAnLi4vLi4vLi4vaW50ZXJmYWNlL2NoYXJ0L3Nlcmllcy1kYXRhJztcbmltcG9ydCB7XG4gICAgSURlY2ltYXRvciwgSVhZRGVjaW1hdG9yLCBJWFlTdGFja2VkRGVjaW1hdG9yLCBJRmxhbWVDaGFydERlY2ltYXRvcixcbiAgICBJVHJhY2VSZXNpZGVuY3lEZWNpbWF0b3IsIElUcmFjZVN0YXRlRGVjaW1hdG9yLCBJTkVXU0RlY2ltYXRpb25WYWx1ZVxufSBmcm9tICcuLi8uLi8uLi9pbnRlcmZhY2UvY2hhcnQvZGVjaW1hdG9yJztcblxuaW1wb3J0IHsgSUJ1ZmZlciB9IGZyb20gJy4uLy4uLy4uL2ludGVyZmFjZS91aS1iYXNlJztcbmltcG9ydCB7IFhZVmFsdWUsIENhbmRsZXN0aWNrVmFsdWUgfSBmcm9tICcuLi8uLi9kYXRhJztcbmltcG9ydCB7IGJpc2VjdEJ1ZmZlciB9IGZyb20gJy4uLy4uL3V0aWxpdGllcyc7XG5cbmV4cG9ydCB2YXIgZmluZEZpcnN0SW5zZXJ0aW9uSWR4OiAoYnVmZmVyOiBJQnVmZmVyPHsgeDogYW55IH0+LCB4OiBudW1iZXIpID0+IG51bWJlciA9XG4gICAgYmlzZWN0QnVmZmVyKGZ1bmN0aW9uICh4eTogeyB4OiBhbnkgfSkgeyByZXR1cm4geHkueCB9KS5sZWZ0O1xuZXhwb3J0IHZhciBmaW5kTGFzdEluc2VydGlvbklkeDogKGJ1ZmZlcjogSUJ1ZmZlcjx7IHg6IGFueSB9PiwgeDogbnVtYmVyKSA9PiBudW1iZXIgPVxuICAgIGJpc2VjdEJ1ZmZlcihmdW5jdGlvbiAoeHk6IHsgeDogYW55IH0pIHsgcmV0dXJuIHh5LnggfSkucmlnaHQ7XG5cbi8qKiBUaGlzIGZ1bmN0aW9uIGlzIGNyZWF0ZWQgYnkgYSB1c2VyIHRvIGRvIGEgdXNlciBkZWZpbmVkIGRlY2ltYXRpb24uXG4gKiBOb3RlIHRoYXQgdGhlIGZ1bmN0aW9uIGlzIGNhbGxlZCBvbmNlIHBlciB4IHBpeGVsIG9uIHRoZSBzY3JlZW4uICBBbHNvXG4gKiBpdCBpcyBndWFyYW50ZWVkIHRoYXQgdGhlIGlucHV0VmFsdWVzIHdpbGwgYmUgaW4gdGhlIHNhbWUgb3JkZXIgYXMgdGhleVxuICogYXJlIGluIHRoZSBvcmlnaW5hbCBhcnJheSwgc28gcnVubmluZ3Mgc3RhdGlzdGljYWwgdmFsdWVzIGNhbiBiZSBzdG9yZWRcbiAqIGluIHRoZSBmdW5jdGlvbiBpZiByZWFsbHkgbmVlZGVkLlxuICpcbiAqIHlWYWx1ZVRvQ29vcmQgd2lsbCBtYXAgdGhlIHlWYWx1ZSB0byBhbiBhY3R1YWwgcGl4ZWwuICBUaGUgbGFyZ2VyIHRoZVxuICogb3V0cHV0IG9mIHlWYWx1ZVRvQ29vcmQsIHRoZSBzbWFsbGVyIHRoZSBhY3R1YWwgdmFsdWUgaXMgYWthIHRoZXJlIGlzIGFuXG4gKiBpbnZlcnNlIHJlbGF0aW9uc2hpcCBiZXR3ZWVuIHlWYWx1ZVRvQ29vcmQgb3V0cHV0IGFuZCB0aGUgYWN0dWFsIFkgdmFsdWUuXG4gKlxuICovXG5leHBvcnQgdHlwZSBJWFlYU2ltcGxlRGVjaW1hdGlvbkZ1bmN0aW9uID0gKGlucHV0VmFsdWVzOiBJQnVmZmVyPElYWVZhbHVlPixcbiAgICBzdGFydElkeDogbnVtYmVyLCBlbmRJZHg6IG51bWJlcixcbiAgICB5VmFsdWVUb0Nvb3JkOiAodmFsdWU6IGFueSkgPT4gbnVtYmVyLFxuICAgIHhWYWx1ZVRvQ29vcmQ6ICh2YWx1ZTogYW55KSA9PiBudW1iZXIsXG4gICAgeFN0YXJ0OiBudW1iZXIsIHhFbmQ6IG51bWJlcikgPT4gSVhZVmFsdWVbXTtcblxuZXhwb3J0IGNsYXNzIFhZRHVtbXlEZWNpbWF0b3IgaW1wbGVtZW50cyBJRGVjaW1hdG9yIHtcbiAgICBwcml2YXRlIF92YWx1ZXM6IGFueVtdID0gW107XG5cbiAgICBwdWJsaWMgaW5pdGlhbGl6ZSh4VmFsdWVUb0Nvb3JkOiAodmFsdWU6IGFueSkgPT4gbnVtYmVyLFxuICAgICAgICB4Q29vcmRUb1ZhbHVlOiAodmFsdWU6IGFueSkgPT4gbnVtYmVyLFxuICAgICAgICB5VmFsdWVUb0Nvb3JkOiAodmFsdWU6IGFueSkgPT4gbnVtYmVyKTogdm9pZCB7XG4gICAgfVxuXG4gICAgcHVibGljIGdldEtleSgpOiBzdHJpbmcge1xuICAgICAgICByZXR1cm4gJyc7XG4gICAgfVxuXG4gICAgcHVibGljIGdldE5hbWUoKTogc3RyaW5nIHtcbiAgICAgICAgcmV0dXJuICcnO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIFJldHVybnMgdGhlIGRlY2ltYXRlZCBsaXN0IG9mIGRhdGFcbiAgICAgKi9cbiAgICBwdWJsaWMgZ2V0VmFsdWVzKCk6IElYWVZhbHVlW10ge1xuICAgICAgICByZXR1cm4gdGhpcy5fdmFsdWVzO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIFZhbHVlcyB0byBiZSBkZWNpbWF0ZWRcbiAgICAgKlxuICAgICAqIEBwYXJhbSB4U3RhcnQgLSBzdGFydCB0aW1lIG9mIHRoZSByZWdpb25cbiAgICAgKiBAcGFyYW0geEVuZCAtIHN0YXJ0IHRpbWUgb2YgdGhlIHJlZ2lvblxuICAgICAqIEBwYXJhbSB2YWx1ZXMgLSBWYWx1ZXMgdG8gYmUgZGVjaW1hdGVkLlxuICAgICAqL1xuICAgIHB1YmxpYyBkZWNpbWF0ZVZhbHVlcyh4U3RhcnQ6IG51bWJlciwgeEVuZDogbnVtYmVyLCB2YWx1ZXM6IElCdWZmZXI8SVhZVmFsdWU+KTogSVhZVmFsdWVbXSB7XG4gICAgICAgIGlmIChBcnJheS5pc0FycmF5KHZhbHVlcykpIHtcbiAgICAgICAgICAgIHZhbHVlcy5mb3JFYWNoKChkYXRhKSA9PiB7XG4gICAgICAgICAgICAgICAgdGhpcy5fdmFsdWVzLnB1c2goZGF0YS5nZXREYXRhKCkpO1xuICAgICAgICAgICAgfSlcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIHRoaXMuX3ZhbHVlcyA9IHZhbHVlcy5nZXREYXRhKCk7XG4gICAgICAgIH1cblxuICAgICAgICByZXR1cm4gdGhpcy5fdmFsdWVzO1xuICAgIH1cbn0gICAvLyBpbnRlcmZhY2UgSURlY2ltYXRvclxuXG4vKipcbiAqIHRoaXMgY2xhc3MgYWxsb3dzIGEgZGVjaW1hdGlvbiBmdW5jdGlvbiB0byBiZSBwYXNzZWQgaW4gdG8gYWxsb3cgZm9yXG4gKiBnZW5lcmljIGRlY2ltYXRpb25cbiAqL1xuZXhwb3J0IGNsYXNzIEN1c3RvbVBvaW50WFlEZWNpbWF0b3IgaW1wbGVtZW50cyBJWFlEZWNpbWF0b3Ige1xuICAgIC8qKiB0aGlzIGZ1bmN0aW9uIHNob3VsZCB0YWtlIGEgc2V0IG9mIGJ1Y2tldHMgYW5kIHJlZHVjZSB0aGVtXG4gICAgICogdG8gYSBkZWNpbWF0ZWQgc3Vic2V0IGZvciBhIGdpdmVuIHJhbmdlICovXG4gICAgcHJvdGVjdGVkIF9rZXk6IHN0cmluZztcblxuICAgIHByb3RlY3RlZCBfbmFtZTogc3RyaW5nO1xuXG4gICAgLyoqIHRoaXMgZnVuY3Rpb24gc2hvdWxkIHRha2UgYSBzZXQgb2YgYnVja2V0cyBhbmQgcmVkdWNlIHRoZW1cbiAgICAgKiB0byBhIGRlY2ltYXRlZCBzdWJzZXQgZm9yIGEgZ2l2ZW4gcmFuZ2UgKi9cbiAgICBwcm90ZWN0ZWQgX2N1c3RvbUZ1bmM6IElYWVhTaW1wbGVEZWNpbWF0aW9uRnVuY3Rpb247XG5cbiAgICAvKiogdGhpcyBmdW5jdGlvbiBpcyB1c2VkIHRvIG1hcCB0aGUgaW5wdXQgeHlWYWx1ZXMgdG8geCBzY2FsZWQgdmFsdWVzKi9cbiAgICBwcm90ZWN0ZWQgX3hWYWx1ZVRvQ29vcmQ6ICh2YWx1ZTogYW55KSA9PiBudW1iZXI7XG5cbiAgICAvKiogdGhpcyBmdW5jdGlvbiBpcyB1c2VkIHRvIG1hcCB0aGUgcmV2ZXJ0IHh5VmFsdWVzIGZyb20geCBzY2FsZWQgdmFsdWVzKi9cbiAgICBwcm90ZWN0ZWQgX3hDb29yZFRvVmFsdWU6ICh2YWx1ZTogYW55KSA9PiBudW1iZXI7XG5cbiAgICAvKiogdGhpcyBmdW5jdGlvbiBpcyB1c2VkIHRvIG1hcCB0aGUgaW5wdXQgeHlWYWx1ZXMgdG8geSBzY2FsZWQgdmFsdWVzKi9cbiAgICBwcm90ZWN0ZWQgX3lWYWx1ZVRvQ29vcmQ6ICh2YWx1ZTogYW55KSA9PiBudW1iZXI7XG5cbiAgICAvKiogdGhlIGxpc3Qgb2YgdmFsdWVzIGluIHRoZSBidWNrZXQgKi9cbiAgICBwcm90ZWN0ZWQgX2RlY2ltYXRlZFZhbHVlczogSVhZVmFsdWVbXTtcblxuICAgIGNvbnN0cnVjdG9yKCkge1xuICAgICAgICB0aGlzLl9uYW1lID0gJ1NpbXBsZSBVbmltcGxlbWVudGVkIERlY2ltYXRvcic7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogY29uc3RydWN0IGEgZ2VuZXJpYyBkZWNpbWF0b3IgdXNpbmcgYSBjdXN0b20gdXNlciBmdW5jdGlvblxuICAgICAqXG4gICAgICogQHBhcmFtIHhWYWx1ZVRvQ29vcmQgY29udmVydHMgdGhlIHggdmFsdWUgdG8gYSBHVUkgeCBjb29yZGluYXRlXG4gICAgICogQHBhcmFtIHlWYWx1ZVRvQ29vcmQgY29udmVydHMgdGhlIHkgdmFsdWUgdG8gYSBHVUkgeSBjb29yZGluYXRlXG4gICAgICogQHBhcmFtIGRlY2ltYXRpb25GdW5jIGNvbnZlcnQgYSBsaXN0IG9mIGRhdGEgdG8gYSBmb3IgcmVuZGVyaW5nIHNtYWxsZXIgbGlzdFxuICAgICAqL1xuICAgIGluaXRpYWxpemUoeFZhbHVlVG9Db29yZDogKHZhbHVlOiBhbnkpID0+IG51bWJlcixcbiAgICAgICAgeENvb3JkVG9WYWx1ZTogKHZhbHVlOiBhbnkpID0+IG51bWJlcixcbiAgICAgICAgeVZhbHVlVG9Db29yZDogKHZhbHVlOiBhbnkpID0+IG51bWJlcikge1xuXG4gICAgICAgIHRoaXMuX3hWYWx1ZVRvQ29vcmQgPSB4VmFsdWVUb0Nvb3JkO1xuICAgICAgICB0aGlzLl94Q29vcmRUb1ZhbHVlID0geENvb3JkVG9WYWx1ZTtcbiAgICAgICAgdGhpcy5feVZhbHVlVG9Db29yZCA9IHlWYWx1ZVRvQ29vcmQ7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogUmV0dXJucyB0aGUga2V5IG9mIHRoaXMgZGVjaW1hdG9yXG4gICAgICovXG4gICAgcHVibGljIGdldEtleSgpOiBzdHJpbmcge1xuICAgICAgICByZXR1cm4gdGhpcy5fa2V5O1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIFJldHVybnMgdGhlIG5hbWUgb2YgdGhpcyBkZWNpbWF0b3JcbiAgICAgKi9cbiAgICBwdWJsaWMgZ2V0TmFtZSgpOiBzdHJpbmcge1xuICAgICAgICByZXR1cm4gdGhpcy5fbmFtZTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBSZXR1cm5zIHRoZSBkZWNpbWF0ZWQgbGlzdCBvZiBidWNrZXRzXG4gICAgICovXG4gICAgcHVibGljIGdldFZhbHVlcygpOiBJWFlWYWx1ZVtdIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuX2RlY2ltYXRlZFZhbHVlcztcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBWYWx1ZXMgdG8gYmUgZGVjaW1hdGVkXG4gICAgICpcbiAgICAgKiBAcGFyYW0geFN0YXJ0IC0gc3RhcnQgdGltZSBvZiB0aGUgcmVnaW9uXG4gICAgICogQHBhcmFtIHhFbmQgLSBzdGFydCB0aW1lIG9mIHRoZSByZWdpb25cbiAgICAgKiBAcGFyYW0gdmFsdWVzIC0gVmFsdWVzIHRvIGJlIGRlY2ltYXRlZC5cbiAgICAgKi9cbiAgICBwdWJsaWMgZGVjaW1hdGVWYWx1ZXMoeFN0YXJ0OiBudW1iZXIsIHhFbmQ6IG51bWJlciwgaW5wdXRWYWx1ZXM6IElCdWZmZXI8SVhZVmFsdWU+KTogSVhZVmFsdWVbXSB7XG4gICAgICAgIC8vIGxvb3Agb3ZlciB0aGUgZGF0YSBzYW1wbGVzXG4gICAgICAgIHRoaXMuX2RlY2ltYXRlZFZhbHVlcyA9IFtdO1xuICAgICAgICBpZiAoaW5wdXRWYWx1ZXMubGVuZ3RoKCkgPT09IDApIHtcbiAgICAgICAgICAgIHJldHVybiB0aGlzLl9kZWNpbWF0ZWRWYWx1ZXM7XG4gICAgICAgIH1cblxuICAgICAgICBsZXQgbGVmdDogbnVtYmVyID0gZmluZEZpcnN0SW5zZXJ0aW9uSWR4KGlucHV0VmFsdWVzLCB4U3RhcnQpO1xuICAgICAgICBsZXQgcmlnaHQ6IG51bWJlciA9IGZpbmRMYXN0SW5zZXJ0aW9uSWR4KGlucHV0VmFsdWVzLCB4RW5kKTtcblxuICAgICAgICBpZiAobGVmdCA+IDApIHtcbiAgICAgICAgICAgIC0tbGVmdDtcbiAgICAgICAgfVxuICAgICAgICBpZiAocmlnaHQgPCBpbnB1dFZhbHVlcy5sZW5ndGgoKSkge1xuICAgICAgICAgICAgKytyaWdodDtcbiAgICAgICAgfVxuXG4gICAgICAgIGxldCBsYXN0WDogbnVtYmVyO1xuICAgICAgICBpZiAobGVmdCA8IGlucHV0VmFsdWVzLmxlbmd0aCgpKSB7XG4gICAgICAgICAgICBsYXN0WCA9IE1hdGguZmxvb3IodGhpcy5feFZhbHVlVG9Db29yZChpbnB1dFZhbHVlcy5nZXQobGVmdCkueCkpO1xuICAgICAgICAgICAgLS1sYXN0WDtcbiAgICAgICAgfVxuXG4gICAgICAgIGxldCB4U3RhcnRDb29yZDogbnVtYmVyO1xuICAgICAgICBpZiAoeFN0YXJ0KSB7XG4gICAgICAgICAgICB4U3RhcnRDb29yZCA9IE1hdGguZmxvb3IodGhpcy5feFZhbHVlVG9Db29yZCh4U3RhcnQpKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIHhTdGFydENvb3JkID0gTWF0aC5mbG9vcih0aGlzLl94VmFsdWVUb0Nvb3JkKGlucHV0VmFsdWVzLmdldChsZWZ0KS54KSk7XG4gICAgICAgIH1cblxuICAgICAgICBsZXQgbGFzdElkeCA9IGxlZnQ7XG4gICAgICAgIGxldCBlbmRJZHg6IG51bWJlcjtcbiAgICAgICAgZm9yIChsZXQgaW5kZXggPSBsZWZ0OyBpbmRleCA8IHJpZ2h0OyArK2luZGV4KSB7XG4gICAgICAgICAgICBsZXQgaW5wdXRWYWx1ZSA9IGlucHV0VmFsdWVzLmdldChpbmRleCk7XG4gICAgICAgICAgICBsZXQgeEVuZENvb3JkID0gTWF0aC5mbG9vcih0aGlzLl94VmFsdWVUb0Nvb3JkKGlucHV0VmFsdWUueCkpO1xuXG4gICAgICAgICAgICBlbmRJZHggPSBpbmRleDtcbiAgICAgICAgICAgIGlmICh4RW5kQ29vcmQgIT09IGxhc3RYKSB7XG4gICAgICAgICAgICAgICAgdGhpcy5fZGVjaW1hdGVkVmFsdWVzID0gdGhpcy5fZGVjaW1hdGVkVmFsdWVzLmNvbmNhdChcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5fY3VzdG9tRnVuYyhpbnB1dFZhbHVlcywgbGFzdElkeCwgZW5kSWR4LFxuICAgICAgICAgICAgICAgICAgICAgICAgdGhpcy5feVZhbHVlVG9Db29yZCwgdGhpcy5feFZhbHVlVG9Db29yZCxcbiAgICAgICAgICAgICAgICAgICAgICAgIHRoaXMuX3hDb29yZFRvVmFsdWUoeFN0YXJ0Q29vcmQpLCB0aGlzLl94Q29vcmRUb1ZhbHVlKHhFbmRDb29yZCkpKTtcblxuICAgICAgICAgICAgICAgIHhTdGFydENvb3JkID0geEVuZENvb3JkO1xuICAgICAgICAgICAgICAgIGxhc3RYID0geEVuZENvb3JkO1xuICAgICAgICAgICAgICAgIGxhc3RJZHggPSBlbmRJZHg7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgaWYgKGxhc3RJZHggIT09IGlucHV0VmFsdWVzLmxlbmd0aCgpKSB7XG4gICAgICAgICAgICB0aGlzLl9kZWNpbWF0ZWRWYWx1ZXMgPSB0aGlzLl9kZWNpbWF0ZWRWYWx1ZXMuY29uY2F0KFxuICAgICAgICAgICAgICAgIHRoaXMuX2N1c3RvbUZ1bmMoaW5wdXRWYWx1ZXMsIGxhc3RJZHgsIGVuZElkeCArIDEsXG4gICAgICAgICAgICAgICAgICAgIHRoaXMuX3lWYWx1ZVRvQ29vcmQsIHRoaXMuX3hWYWx1ZVRvQ29vcmQsXG4gICAgICAgICAgICAgICAgICAgIHRoaXMuX3hDb29yZFRvVmFsdWUoeFN0YXJ0Q29vcmQpLCBOdW1iZXIuTUFYX1ZBTFVFKSk7XG4gICAgICAgIH1cblxuICAgICAgICByZXR1cm4gdGhpcy5fZGVjaW1hdGVkVmFsdWVzO1xuICAgIH1cbn1cblxuLyoqIHVzZWQgdG8gY29tcHV0ZSB0aGUgbWluIHZhbHVlcyBmb3IgYSBzZXQgb2YgZGF0YSAqL1xuZXhwb3J0IGNsYXNzIE1pblBvaW50RGVjaW1hdG9yIGV4dGVuZHMgQ3VzdG9tUG9pbnRYWURlY2ltYXRvciB7XG4gICAgcHVibGljIHN0YXRpYyBLRVkgPSAnTWluUG9pbnREZWNpbWF0b3InO1xuICAgIGNvbnN0cnVjdG9yKCkge1xuICAgICAgICBzdXBlcigpO1xuXG4gICAgICAgIHRoaXMuX2tleSA9IE1pblBvaW50RGVjaW1hdG9yLktFWTtcbiAgICAgICAgdGhpcy5fbmFtZSA9ICdNaW4nO1xuICAgICAgICB0aGlzLl9jdXN0b21GdW5jID0gZnVuY3Rpb24gKHZhbHVlczogSUJ1ZmZlcjxJWFlWYWx1ZT4sIHN0YXJ0SWR4OiBudW1iZXIsXG4gICAgICAgICAgICBlbmRJZHg6IG51bWJlciwgeVZhbHVlVG9Db29yZDogKHZhbHVlOiBhbnkpID0+IG51bWJlcik6IElYWVZhbHVlW10ge1xuXG4gICAgICAgICAgICBpZiAodmFsdWVzLmxlbmd0aCgpID4gMCAmJiBzdGFydElkeCAhPT0gZW5kSWR4KSB7XG4gICAgICAgICAgICAgICAgbGV0IG1pblkgPSBOdW1iZXIuTUFYX1ZBTFVFO1xuICAgICAgICAgICAgICAgIGxldCBtaW5WYWx1ZTogSVhZVmFsdWU7XG4gICAgICAgICAgICAgICAgZm9yIChsZXQgaSA9IHN0YXJ0SWR4OyBpIDwgZW5kSWR4OyArK2kpIHtcbiAgICAgICAgICAgICAgICAgICAgbGV0IHZhbHVlID0gdmFsdWVzLmdldChpKTtcbiAgICAgICAgICAgICAgICAgICAgbGV0IHkgPSB2YWx1ZS55O1xuICAgICAgICAgICAgICAgICAgICBpZiAoeSA8IG1pblkpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIG1pblZhbHVlID0gdmFsdWU7XG4gICAgICAgICAgICAgICAgICAgICAgICBtaW5ZID0geTtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICByZXR1cm4gW21pblZhbHVlXTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHJldHVybiBbXTtcbiAgICAgICAgfVxuICAgIH1cbn07XG5cbmZ1bmN0aW9uIGNvbXB1dGVBdmcodmFsdWVzOiBJQnVmZmVyPElYWVZhbHVlPiwgc3RhcnRJZHg6IG51bWJlcixcbiAgICBlbmRJZHg6IG51bWJlciwgeVZhbHVlVG9Db29yZDogKHZhbHVlOiBhbnkpID0+IG51bWJlcik6IElYWVZhbHVlW10ge1xuXG4gICAgaWYgKHZhbHVlcy5sZW5ndGgoKSA+IDAgJiYgc3RhcnRJZHggIT09IGVuZElkeCkge1xuICAgICAgICBsZXQgdG90YWwgPSAwO1xuICAgICAgICBmb3IgKGxldCBpID0gc3RhcnRJZHg7IGkgPCBlbmRJZHg7ICsraSkge1xuICAgICAgICAgICAgbGV0IHZhbHVlID0gdmFsdWVzLmdldChpKTtcbiAgICAgICAgICAgIHRvdGFsICs9IHZhbHVlLnk7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIFtuZXcgWFlWYWx1ZSh2YWx1ZXMuZ2V0KGVuZElkeCAtIDEpLngsXG4gICAgICAgICAgICB0b3RhbCAvIChlbmRJZHggLSBzdGFydElkeCkpXTtcbiAgICB9XG4gICAgcmV0dXJuIFtdO1xufVxuXG4vKiogdXNlZCB0byBjb21wdXRlIHRoZSBhdmcgdmFsdWVzIGZvciBhIHNldCBvZiBkYXRhICovXG5leHBvcnQgY2xhc3MgQXZnUG9pbnREZWNpbWF0b3IgZXh0ZW5kcyBDdXN0b21Qb2ludFhZRGVjaW1hdG9yIHtcbiAgICBwdWJsaWMgc3RhdGljIEtFWSA9ICdBdmdQb2ludERlY2ltYXRvcic7XG4gICAgY29uc3RydWN0b3IoKSB7XG4gICAgICAgIHN1cGVyKCk7XG5cbiAgICAgICAgdGhpcy5fa2V5ID0gQXZnUG9pbnREZWNpbWF0b3IuS0VZO1xuICAgICAgICB0aGlzLl9uYW1lID0gJ0F2Zyc7XG4gICAgICAgIHRoaXMuX2N1c3RvbUZ1bmMgPSBjb21wdXRlQXZnO1xuICAgIH1cbn07XG5cbi8qKiB1c2VkIHRvIGNvbXB1dGUgdGhlIG1pbiB2YWx1ZXMgZm9yIGEgc2V0IG9mIGRhdGEgKi9cbmV4cG9ydCBjbGFzcyBNYXhQb2ludERlY2ltYXRvciBleHRlbmRzIEN1c3RvbVBvaW50WFlEZWNpbWF0b3Ige1xuICAgIHB1YmxpYyBzdGF0aWMgS0VZID0gJ01heFBvaW50RGVjaW1hdG9yJztcbiAgICBjb25zdHJ1Y3RvcigpIHtcbiAgICAgICAgc3VwZXIoKTtcblxuICAgICAgICB0aGlzLl9rZXkgPSBNYXhQb2ludERlY2ltYXRvci5LRVk7XG4gICAgICAgIHRoaXMuX25hbWUgPSAnTWF4JztcbiAgICAgICAgdGhpcy5fY3VzdG9tRnVuYyA9IGZ1bmN0aW9uICh2YWx1ZXM6IElCdWZmZXI8SVhZVmFsdWU+LCBzdGFydElkeDogbnVtYmVyLFxuICAgICAgICAgICAgZW5kSWR4OiBudW1iZXIsIHlWYWx1ZVRvQ29vcmQ6ICh2YWx1ZTogYW55KSA9PiBudW1iZXIpOiBJWFlWYWx1ZVtdIHtcblxuICAgICAgICAgICAgaWYgKHZhbHVlcy5sZW5ndGgoKSA+IDAgJiYgc3RhcnRJZHggIT09IGVuZElkeCkge1xuICAgICAgICAgICAgICAgIGxldCBtYXhZID0gLU51bWJlci5NQVhfVkFMVUU7XG4gICAgICAgICAgICAgICAgbGV0IG1heFZhbHVlOiBJWFlWYWx1ZTtcbiAgICAgICAgICAgICAgICBmb3IgKGxldCBpID0gc3RhcnRJZHg7IGkgPCBlbmRJZHg7ICsraSkge1xuICAgICAgICAgICAgICAgICAgICBsZXQgdmFsdWUgPSB2YWx1ZXMuZ2V0KGkpO1xuICAgICAgICAgICAgICAgICAgICBsZXQgeSA9IHZhbHVlLnk7XG4gICAgICAgICAgICAgICAgICAgIGlmICh5ID4gbWF4WSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgbWF4VmFsdWUgPSB2YWx1ZTtcbiAgICAgICAgICAgICAgICAgICAgICAgIG1heFkgPSB5O1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIHJldHVybiBbbWF4VmFsdWVdO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgcmV0dXJuIFtdO1xuICAgICAgICB9XG4gICAgfVxufTtcblxuLyoqXG4gKiBEYXRhIGRlY2ltYXRpb24gdG8gZml0IGluZm9ybWF0aW9uIHRvIG9udG8gdGhlIGdyYXBoLlxuICpcbiAqIFRoaXMgY2xhc3MgZGl2aWRlcyB0aGUgeC1BeGlzIHRpbWUgcmFuZ2UgaW50byBhIHNldCBvZiBidWNrZXRzLiAgRWFjaFxuICogYnVja2V0IHByb3ZpZGVzIHRoZSBhdmVyYWdlIG9mIHRoZSB2YWx1ZXMsIHRoZSBtaW5pbXVtICYgbWF4aW11bVxuICogdmFsdWVzLCBhbmQgdGhlIHZhbHVlcyB1cG9uIGVudHJ5ICYgZXhpdC5cbiAqIEl0IGFzc3VtZXMgdGhhdCB0aGUgREIgdmFsdWVzIGFyZSBpbmNyZWFzZSBvdmVyIHRoZSB0aW1lLlxuICovXG5leHBvcnQgY2xhc3MgWFlQb2ludERlY2ltYXRvciBleHRlbmRzIEN1c3RvbVBvaW50WFlEZWNpbWF0b3Ige1xuICAgIHB1YmxpYyBzdGF0aWMgS0VZID0gJ1hZUG9pbnREZWNpbWF0b3InO1xuICAgIGNvbnN0cnVjdG9yKCkge1xuICAgICAgICBzdXBlcigpO1xuXG4gICAgICAgIHRoaXMuX2tleSA9IFhZUG9pbnREZWNpbWF0b3IuS0VZO1xuICAgICAgICB0aGlzLl9uYW1lID0gJ1hZUG9pbnREZWNpbWF0b3InO1xuICAgICAgICB0aGlzLl9jdXN0b21GdW5jID0gZnVuY3Rpb24gKHZhbHVlczogSUJ1ZmZlcjxJWFlWYWx1ZT4sIHN0YXJ0SWR4OiBudW1iZXIsXG4gICAgICAgICAgICBlbmRJZHg6IG51bWJlciwgeVZhbHVlVG9Db29yZDogKHZhbHVlOiBhbnkpID0+IG51bWJlcik6IElYWVZhbHVlW10ge1xuXG4gICAgICAgICAgICBsZXQgeU1hcDogeyBbaW5kZXg6IG51bWJlcl06IGJvb2xlYW4gfSA9IHt9O1xuICAgICAgICAgICAgbGV0IHJlZHVjZWRWYWx1ZXM6IElYWVZhbHVlW10gPSBbXTtcblxuICAgICAgICAgICAgZm9yIChsZXQgaSA9IHN0YXJ0SWR4OyBpIDwgZW5kSWR4OyArK2kpIHtcbiAgICAgICAgICAgICAgICBsZXQgdmFsdWUgPSB2YWx1ZXMuZ2V0KGkpO1xuXG4gICAgICAgICAgICAgICAgbGV0IHlDb29yZCA9IE1hdGguZmxvb3IoeVZhbHVlVG9Db29yZCh2YWx1ZS55KSk7XG4gICAgICAgICAgICAgICAgaWYgKCF5TWFwLmhhc093blByb3BlcnR5KHlDb29yZC50b1N0cmluZygpKSkge1xuICAgICAgICAgICAgICAgICAgICByZWR1Y2VkVmFsdWVzLnB1c2godmFsdWUpO1xuICAgICAgICAgICAgICAgICAgICB5TWFwW3lDb29yZF0gPSB0cnVlO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHJldHVybiByZWR1Y2VkVmFsdWVzO1xuICAgICAgICB9XG4gICAgfVxufSAgIC8vIGNsYXNzIFZlcnRpY2FsRGVjaW1hdG9yXG5cbi8qKlxuICogdGhpcyBjbGFzcyBhbGxvd3MgYSBkZWNpbWF0aW9uIGZ1bmN0aW9uIHRvIGJlIHBhc3NlZCBpbiB0byBhbGxvdyBmb3JcbiAqIGdlbmVyaWMgZGVjaW1hdGlvblxuICovXG5leHBvcnQgY2xhc3MgQ3VzdG9tQ29udGludW91c1hZRGVjaW1hdG9yIGltcGxlbWVudHMgSVhZRGVjaW1hdG9yIHtcbiAgICAvKiogdGhpcyBmdW5jdGlvbiBzaG91bGQgdGFrZSBhIHNldCBvZiBidWNrZXRzIGFuZCByZWR1Y2UgdGhlbVxuICAgICAqIHRvIGEgZGVjaW1hdGVkIHN1YnNldCBmb3IgYSBnaXZlbiByYW5nZSAqL1xuICAgIHByb3RlY3RlZCBfa2V5OiBzdHJpbmc7XG5cbiAgICBwcm90ZWN0ZWQgX25hbWU6IHN0cmluZztcblxuICAgIC8qKiB0aGlzIGZ1bmN0aW9uIHNob3VsZCB0YWtlIGEgc2V0IG9mIGJ1Y2tldHMgYW5kIHJlZHVjZSB0aGVtXG4gICAgICogdG8gYSBkZWNpbWF0ZWQgc3Vic2V0IGZvciBhIGdpdmVuIHJhbmdlICovXG4gICAgcHJvdGVjdGVkIF9jdXN0b21GdW5jOiBJWFlYU2ltcGxlRGVjaW1hdGlvbkZ1bmN0aW9uO1xuXG4gICAgLyoqIHRoaXMgZnVuY3Rpb24gaXMgdXNlZCB0byBtYXAgdGhlIGlucHV0IHh5VmFsdWVzIHRvIHggc2NhbGVkIHZhbHVlcyovXG4gICAgcHJvdGVjdGVkIF94VmFsdWVUb0Nvb3JkOiAodmFsdWU6IGFueSkgPT4gbnVtYmVyO1xuXG4gICAgLyoqIHRoaXMgZnVuY3Rpb24gaXMgdXNlZCB0byBtYXAgdGhlIHJldmVydCB4eVZhbHVlcyBmcm9tIHggc2NhbGVkIHZhbHVlcyovXG4gICAgcHJvdGVjdGVkIF94Q29vcmRUb1ZhbHVlOiAodmFsdWU6IGFueSkgPT4gbnVtYmVyO1xuXG4gICAgLyoqIHRoaXMgZnVuY3Rpb24gaXMgdXNlZCB0byBtYXAgdGhlIGlucHV0IHh5VmFsdWVzIHRvIHkgc2NhbGVkIHZhbHVlcyovXG4gICAgcHJvdGVjdGVkIF95VmFsdWVUb0Nvb3JkOiAodmFsdWU6IGFueSkgPT4gbnVtYmVyO1xuXG4gICAgLyoqIHRoZSBsaXN0IG9mIHZhbHVlcyBpbiB0aGUgYnVja2V0ICovXG4gICAgcHJvdGVjdGVkIF9kZWNpbWF0ZWRWYWx1ZXM6IElYWVZhbHVlW107XG5cbiAgICBjb25zdHJ1Y3RvcigpIHtcbiAgICAgICAgdGhpcy5fbmFtZSA9ICdTaW1wbGUgVW5pbXBsZW1lbnRlZCBEZWNpbWF0b3InO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIGNvbnN0cnVjdCBhIGdlbmVyaWMgZGVjaW1hdG9yIHVzaW5nIGEgY3VzdG9tIHVzZXIgZnVuY3Rpb25cbiAgICAgKlxuICAgICAqIEBwYXJhbSB4VmFsdWVUb0Nvb3JkIGNvbnZlcnRzIHRoZSB4IHZhbHVlIHRvIGEgR1VJIHggY29vcmRpbmF0ZVxuICAgICAqIEBwYXJhbSB5VmFsdWVUb0Nvb3JkIGNvbnZlcnRzIHRoZSB5IHZhbHVlIHRvIGEgR1VJIHkgY29vcmRpbmF0ZVxuICAgICAqIEBwYXJhbSBkZWNpbWF0aW9uRnVuYyBjb252ZXJ0IGEgbGlzdCBvZiBkYXRhIHRvIGEgZm9yIHJlbmRlcmluZyBzbWFsbGVyIGxpc3RcbiAgICAgKi9cbiAgICBpbml0aWFsaXplKHhWYWx1ZVRvQ29vcmQ6ICh2YWx1ZTogYW55KSA9PiBudW1iZXIsXG4gICAgICAgIHhDb29yZFRvVmFsdWU6ICh2YWx1ZTogYW55KSA9PiBudW1iZXIsXG4gICAgICAgIHlWYWx1ZVRvQ29vcmQ6ICh2YWx1ZTogYW55KSA9PiBudW1iZXIpIHtcblxuICAgICAgICB0aGlzLl94VmFsdWVUb0Nvb3JkID0geFZhbHVlVG9Db29yZDtcbiAgICAgICAgdGhpcy5feENvb3JkVG9WYWx1ZSA9IHhDb29yZFRvVmFsdWU7XG4gICAgICAgIHRoaXMuX3lWYWx1ZVRvQ29vcmQgPSB5VmFsdWVUb0Nvb3JkO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIFJldHVybnMgdGhlIGtleSBvZiB0aGlzIGRlY2ltYXRvclxuICAgICAqL1xuICAgIHB1YmxpYyBnZXRLZXkoKTogc3RyaW5nIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuX2tleTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBSZXR1cm5zIHRoZSBuYW1lIG9mIHRoaXMgZGVjaW1hdG9yXG4gICAgICovXG4gICAgcHVibGljIGdldE5hbWUoKTogc3RyaW5nIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuX25hbWU7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogUmV0dXJucyB0aGUgZGVjaW1hdGVkIGxpc3Qgb2YgYnVja2V0c1xuICAgICAqL1xuICAgIHB1YmxpYyBnZXRWYWx1ZXMoKTogSVhZVmFsdWVbXSB7XG4gICAgICAgIHJldHVybiB0aGlzLl9kZWNpbWF0ZWRWYWx1ZXM7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogVmFsdWVzIHRvIGJlIGRlY2ltYXRlZFxuICAgICAqXG4gICAgICogQHBhcmFtIHhTdGFydCAtIHN0YXJ0IHRpbWUgb2YgdGhlIHJlZ2lvblxuICAgICAqIEBwYXJhbSB4RW5kIC0gc3RhcnQgdGltZSBvZiB0aGUgcmVnaW9uXG4gICAgICogQHBhcmFtIHZhbHVlcyAtIFZhbHVlcyB0byBiZSBkZWNpbWF0ZWQuXG4gICAgICovXG4gICAgcHVibGljIGRlY2ltYXRlVmFsdWVzKHhTdGFydDogbnVtYmVyLCB4RW5kOiBudW1iZXIsIGlucHV0VmFsdWVzOiBJQnVmZmVyPElYWVZhbHVlPik6IElYWVZhbHVlW10ge1xuICAgICAgICAvLyBsb29wIG92ZXIgdGhlIGRhdGEgc2FtcGxlc1xuICAgICAgICB0aGlzLl9kZWNpbWF0ZWRWYWx1ZXMgPSBbXTtcbiAgICAgICAgaWYgKGlucHV0VmFsdWVzLmxlbmd0aCgpID09PSAwKSB7XG4gICAgICAgICAgICByZXR1cm4gdGhpcy5fZGVjaW1hdGVkVmFsdWVzO1xuICAgICAgICB9XG5cbiAgICAgICAgbGV0IGxlZnQ6IG51bWJlciA9IGZpbmRGaXJzdEluc2VydGlvbklkeChpbnB1dFZhbHVlcywgeFN0YXJ0KTtcbiAgICAgICAgbGV0IHJpZ2h0OiBudW1iZXIgPSBmaW5kTGFzdEluc2VydGlvbklkeChpbnB1dFZhbHVlcywgeEVuZCk7XG5cbiAgICAgICAgaWYgKGxlZnQgPiAwKSB7XG4gICAgICAgICAgICAtLWxlZnQ7XG4gICAgICAgIH1cbiAgICAgICAgaWYgKHJpZ2h0IDwgaW5wdXRWYWx1ZXMubGVuZ3RoKCkpIHtcbiAgICAgICAgICAgICsrcmlnaHQ7XG4gICAgICAgIH1cblxuICAgICAgICBsZXQgbGFzdFg6IG51bWJlcjtcbiAgICAgICAgaWYgKGxlZnQgPCBpbnB1dFZhbHVlcy5sZW5ndGgoKSkge1xuICAgICAgICAgICAgbGFzdFggPSBNYXRoLmZsb29yKHRoaXMuX3hWYWx1ZVRvQ29vcmQoaW5wdXRWYWx1ZXMuZ2V0KGxlZnQpLngpKTtcbiAgICAgICAgICAgIC0tbGFzdFg7XG4gICAgICAgIH1cblxuICAgICAgICBsZXQgeFN0YXJ0Q29vcmQ6IG51bWJlcjtcbiAgICAgICAgaWYgKHhTdGFydCkge1xuICAgICAgICAgICAgeFN0YXJ0Q29vcmQgPSB0aGlzLl94VmFsdWVUb0Nvb3JkKHhTdGFydCk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICB4U3RhcnRDb29yZCA9IGxlZnQ7XG4gICAgICAgIH1cblxuICAgICAgICBsZXQgbGFzdElkeCA9IGxlZnQ7XG4gICAgICAgIGZvciAobGV0IGluZGV4ID0gbGVmdDsgaW5kZXggPCByaWdodDsgKytpbmRleCkge1xuICAgICAgICAgICAgbGV0IGlucHV0VmFsdWUgPSBpbnB1dFZhbHVlcy5nZXQoaW5kZXgpO1xuICAgICAgICAgICAgbGV0IHhFbmRDb29yZCA9IE1hdGguZmxvb3IodGhpcy5feFZhbHVlVG9Db29yZChpbnB1dFZhbHVlLngpKTtcblxuICAgICAgICAgICAgbGV0IGVuZElkeCA9IGluZGV4ICsgMTtcbiAgICAgICAgICAgIGlmICh4RW5kQ29vcmQgIT09IGxhc3RYKSB7XG4gICAgICAgICAgICAgICAgdGhpcy5fZGVjaW1hdGVkVmFsdWVzID0gdGhpcy5fZGVjaW1hdGVkVmFsdWVzLmNvbmNhdChcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5fY3VzdG9tRnVuYyhpbnB1dFZhbHVlcywgbGFzdElkeCwgZW5kSWR4LFxuICAgICAgICAgICAgICAgICAgICAgICAgdGhpcy5feVZhbHVlVG9Db29yZCwgdGhpcy5feFZhbHVlVG9Db29yZCxcbiAgICAgICAgICAgICAgICAgICAgICAgIHRoaXMuX3hDb29yZFRvVmFsdWUoeFN0YXJ0Q29vcmQpLCB0aGlzLl94Q29vcmRUb1ZhbHVlKHhFbmRDb29yZCkpKTtcblxuICAgICAgICAgICAgICAgIHhTdGFydENvb3JkID0geEVuZENvb3JkO1xuICAgICAgICAgICAgICAgIGxhc3RYID0geEVuZENvb3JkO1xuICAgICAgICAgICAgICAgIGxhc3RJZHggPSBlbmRJZHg7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICBpZiAobGFzdElkeCAhPT0gaW5wdXRWYWx1ZXMubGVuZ3RoKCkpIHtcbiAgICAgICAgICAgIHRoaXMuX2RlY2ltYXRlZFZhbHVlcyA9IHRoaXMuX2RlY2ltYXRlZFZhbHVlcy5jb25jYXQoXG4gICAgICAgICAgICAgICAgdGhpcy5fY3VzdG9tRnVuYyhpbnB1dFZhbHVlcywgbGFzdElkeCwgbGFzdElkeCArIDEsXG4gICAgICAgICAgICAgICAgICAgIHRoaXMuX3lWYWx1ZVRvQ29vcmQsIHRoaXMuX3hWYWx1ZVRvQ29vcmQsXG4gICAgICAgICAgICAgICAgICAgIHRoaXMuX3hDb29yZFRvVmFsdWUoeFN0YXJ0Q29vcmQpLCBOdW1iZXIuTUFYX1ZBTFVFKSk7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIHRoaXMuX2RlY2ltYXRlZFZhbHVlcztcbiAgICB9XG59XG5cbi8qKiB1c2VkIHRvIGNvbXB1dGUgdGhlIGF2ZyB2YWx1ZXMgZm9yIGEgc2V0IG9mIGRhdGEgKi9cbmV4cG9ydCBjbGFzcyBBdmdDb250aW51b3VzRGVjaW1hdG9yIGV4dGVuZHMgQ3VzdG9tQ29udGludW91c1hZRGVjaW1hdG9yIHtcbiAgICBwdWJsaWMgc3RhdGljIEtFWSA9ICdBdmdDb250aW51b3VzRGVjaW1hdG9yJ1xuICAgIGNvbnN0cnVjdG9yKCkge1xuICAgICAgICBzdXBlcigpO1xuXG4gICAgICAgIHRoaXMuX2tleSA9IEF2Z0NvbnRpbnVvdXNEZWNpbWF0b3IuS0VZO1xuICAgICAgICB0aGlzLl9uYW1lID0gJ0F2Zyc7XG4gICAgICAgIHRoaXMuX2N1c3RvbUZ1bmMgPSBjb21wdXRlQXZnO1xuICAgIH1cbn07XG5cbi8qKiB0aGlzIGlzIGEgaGVscGVyIGZ1bmN0aW9uIGNsYXNzIHRoYXQgY29tcHV0ZXMgdGhlIHN1bW1lZCB2YWx1ZXMgZm9yIGVhY2hcbiAqIFkgc3RhdGUgcGVyIGVhY2ggWCBidWNrZXRcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHN1bU11bHRpWFlTZXJpZXNWYWx1ZXMoX3hWYWx1ZVRvQ29vcmQ6ICh2YWx1ZTogYW55KSA9PiBudW1iZXIsXG4gICAgX3hDb29yZFRvVmFsdWU6ICh2YWx1ZTogYW55KSA9PiBudW1iZXIsIF95VmFsdWVUb0Nvb3JkOiAodmFsdWU6IGFueSkgPT4gbnVtYmVyLFxuICAgIHhTdGFydDogbnVtYmVyLCB4RW5kOiBudW1iZXIsIHZhbHVlczogSUJ1ZmZlcjxJWFlWYWx1ZT5bXSk6IGFueVtdW10ge1xuXG4gICAgbGV0IHJldDogYW55W10gPSBbXTtcbiAgICAvLyBmaXJzdCB0aGlzIGlzIHRvdGFsIHdlaWdodGVkIHN1bSBwZXIgeCwgdGhlbiB1c2VkIHRvIHN0b3JlIHBlcmNlbnRhZ2UgcGVyIHhcbiAgICBsZXQgdGVtcFZhbHVlczogbnVtYmVyW11bXSA9IFtdO1xuXG4gICAgbGV0IGdsb2JhbFN0YXJ0QnVja2V0ID0gMDtcbiAgICBsZXQgZ2xvYmFsRW5kQnVja2V0ID0gTWF0aC5jZWlsKF94VmFsdWVUb0Nvb3JkKE51bWJlci5NQVhfVkFMVUUpKTtcblxuICAgIGlmIChnbG9iYWxFbmRCdWNrZXQgPCBnbG9iYWxTdGFydEJ1Y2tldCkge1xuICAgICAgICByZXR1cm4gdW5kZWZpbmVkO1xuICAgIH1cblxuICAgIC8vIE5PVEU6IEkgZG8gdGhpcyB1cCBoZXJlIHNvIEkgY2FuIGNoZWF0IGFuZCB1c2UgdGhlIHggdmFsdWVzIGhlcmVcbiAgICAvLyBzbyBsYXRlciBJIGRvbid0IGtlZXAgY2FsbGluZyBfeENvb3JkVG9WYWx1ZVxuICAgIGxldCB4QnVja2V0VmFsdWVzID0gW107XG4gICAgZm9yIChsZXQgYnVja2V0ID0gMDsgYnVja2V0IDw9IGdsb2JhbEVuZEJ1Y2tldCArIDE7ICsrYnVja2V0KSB7XG4gICAgICAgIHhCdWNrZXRWYWx1ZXMucHVzaChfeENvb3JkVG9WYWx1ZShidWNrZXQpKTtcbiAgICB9XG5cbiAgICAvLyBmb3IgYSBzZXJpZXMgZ2V0IHRoZSB3ZWlnaHRlZCBzdW0gZm9yIHRoZSBudW1iZXIgb2YgYnVja2V0cyB4U3RhcnQgdG8geEVuZFxuICAgIGZvciAobGV0IHN0YXRlSWR4ID0gMDsgc3RhdGVJZHggPCB2YWx1ZXMubGVuZ3RoOyArK3N0YXRlSWR4KSB7XG4gICAgICAgIGxldCBwZXJTdGF0ZURhdGEgPSB2YWx1ZXNbc3RhdGVJZHhdO1xuICAgICAgICBsZXQgdmFsdWU6IElYWVZhbHVlO1xuICAgICAgICBsZXQgbmV4dFZhbHVlOiBJWFlWYWx1ZTtcbiAgICAgICAgbGV0IHN0YXJ0ID0gZmluZEZpcnN0SW5zZXJ0aW9uSWR4KHZhbHVlc1tzdGF0ZUlkeF0sIHhTdGFydCk7XG4gICAgICAgIGxldCBlbmQgPSBmaW5kTGFzdEluc2VydGlvbklkeCh2YWx1ZXNbc3RhdGVJZHhdLCB4RW5kKTtcblxuICAgICAgICBpZiAoc3RhcnQgPiAwKSB7XG4gICAgICAgICAgICAtLXN0YXJ0O1xuICAgICAgICB9XG4gICAgICAgIC8vIHRoZSBsYXN0IGVsZW1lbnQgd291bGQgYmUgY2F1Z2h0IGJ5IHRoZSBhbGdvcml0aG0gYWxyZWFkeVxuICAgICAgICBpZiAoZW5kID09PSBwZXJTdGF0ZURhdGEubGVuZ3RoKCkpIHtcbiAgICAgICAgICAgIC0tZW5kO1xuICAgICAgICB9XG5cbiAgICAgICAgLy8gcGFkIGVuZEJ1Y2tldCArIDEgc28gd2UgZ2V0IGRhdGEgcGFzdCB0aGUgbGFzdCBwb2ludCBpbiB0aGUgYnVja2V0XG4gICAgICAgIC8vIHNvIHdlIGNhbiBncmFwaCB0byB0aGUgZmlyc3QgdmFsdWUgaW4gdGhlIG5leHQgYnVja2V0XG4gICAgICAgIHRlbXBWYWx1ZXNbc3RhdGVJZHhdID0gQXJyYXkuYXBwbHkobnVsbCwgQXJyYXkoZ2xvYmFsRW5kQnVja2V0KSkuXG4gICAgICAgICAgICBtYXAoTnVtYmVyLnByb3RvdHlwZS52YWx1ZU9mLCAwKTtcblxuICAgICAgICAvLyBnZXQgd2VpZ2h0ZWQgc3VtIG9mIHRoZSB2YWx1ZXMgZm9yIGVhY2ggYnVja2V0XG4gICAgICAgIGZvciAobGV0IHJhd0RhdGFJZHggPSBzdGFydDsgcmF3RGF0YUlkeCA8IGVuZDsgKytyYXdEYXRhSWR4KSB7XG4gICAgICAgICAgICB2YWx1ZSA9IHBlclN0YXRlRGF0YS5nZXQocmF3RGF0YUlkeCk7XG4gICAgICAgICAgICBuZXh0VmFsdWUgPSBwZXJTdGF0ZURhdGEuZ2V0KHJhd0RhdGFJZHggKyAxKTtcblxuICAgICAgICAgICAgbGV0IHN0YXJ0QnVja2V0ID0gTWF0aC5mbG9vcihfeFZhbHVlVG9Db29yZCh2YWx1ZS54KSk7XG4gICAgICAgICAgICBsZXQgZW5kQnVja2V0ID0gTWF0aC5mbG9vcihfeFZhbHVlVG9Db29yZChuZXh0VmFsdWUueCkpO1xuXG4gICAgICAgICAgICBsZXQgdG90YWxYID0gKG5leHRWYWx1ZS54IC0gdmFsdWUueCk7XG4gICAgICAgICAgICBsZXQgdmFsdWVQZXJYID0gdG90YWxYID09PSAwID8gMCA6IG5leHRWYWx1ZS55IC8gdG90YWxYO1xuICAgICAgICAgICAgaWYgKHN0YXJ0QnVja2V0ID09PSBlbmRCdWNrZXQpIHtcbiAgICAgICAgICAgICAgICBpZiAoeFN0YXJ0ID09PSB1bmRlZmluZWQgfHwgKHZhbHVlLnggPiB4U3RhcnQgJiYgbmV4dFZhbHVlLnggPCB4RW5kKSkge1xuICAgICAgICAgICAgICAgICAgICAvLyBoZXJlIGl0J3MgYWxsIGluIHRoZSBleGlzdGluZyBidWNrZXRcbiAgICAgICAgICAgICAgICAgICAgdGVtcFZhbHVlc1tzdGF0ZUlkeF1bc3RhcnRCdWNrZXRdICs9IHZhbHVlUGVyWDtcbiAgICAgICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICBsZXQgYnVja2V0U2NhbGFyID0gMSAvICh4QnVja2V0VmFsdWVzW3N0YXJ0QnVja2V0ICsgMV0gLSB4QnVja2V0VmFsdWVzW3N0YXJ0QnVja2V0XSk7XG4gICAgICAgICAgICAgICAgICAgIGlmIChuZXh0VmFsdWUueCA8IHhFbmQpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIGhlcmUgdGhlIGJhY2sgaGFsZiBpcyBpbiB0aGUgYnVja2V0XG4gICAgICAgICAgICAgICAgICAgICAgICB0ZW1wVmFsdWVzW3N0YXRlSWR4XVtzdGFydEJ1Y2tldF0gKz1cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAobmV4dFZhbHVlLnggLSB4QnVja2V0VmFsdWVzW3N0YXJ0QnVja2V0XSkgKiB2YWx1ZVBlclggKiBidWNrZXRTY2FsYXI7XG4gICAgICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAvLyBoZXJlIHRoZSBmcm9udCBoYWxmIGlzIGluIHRoZSBidWNrZXRcbiAgICAgICAgICAgICAgICAgICAgICAgIHRlbXBWYWx1ZXNbc3RhdGVJZHhdW3N0YXJ0QnVja2V0XSArPVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICh4QnVja2V0VmFsdWVzW3N0YXJ0QnVja2V0ICsgMV0gLSB2YWx1ZS54KSAqIHZhbHVlUGVyWCAqIGJ1Y2tldFNjYWxhcjtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgbGV0IGJ1Y2tldFNjYWxhciA9IDEgLyAoeEJ1Y2tldFZhbHVlc1tzdGFydEJ1Y2tldCArIDFdIC0geEJ1Y2tldFZhbHVlc1tzdGFydEJ1Y2tldF0pO1xuICAgICAgICAgICAgICAgIGxldCBzdGFydFggPSB4U3RhcnQgPyBNYXRoLm1heCh4U3RhcnQsIHZhbHVlLngpIDogdmFsdWUueDtcbiAgICAgICAgICAgICAgICBsZXQgZW5kU3RhcnRCdWNrZXQgPSB4QnVja2V0VmFsdWVzW3N0YXJ0QnVja2V0ICsgMV07XG4gICAgICAgICAgICAgICAgdGVtcFZhbHVlc1tzdGF0ZUlkeF1bc3RhcnRCdWNrZXRdICs9XG4gICAgICAgICAgICAgICAgICAgIChlbmRTdGFydEJ1Y2tldCAtIHN0YXJ0WCkgKiB2YWx1ZVBlclggKiBidWNrZXRTY2FsYXI7XG5cbiAgICAgICAgICAgICAgICAvLyBhZGQgaW4gYWxsIHRoZSBidWNrZXQgdmFsdWVzIGluIGJldHdlZW5cbiAgICAgICAgICAgICAgICBmb3IgKGxldCBjdXJyQnVja2V0ID0gc3RhcnRCdWNrZXQgKyAxOyBjdXJyQnVja2V0IDwgZW5kQnVja2V0OyArK2N1cnJCdWNrZXQpIHtcbiAgICAgICAgICAgICAgICAgICAgdGVtcFZhbHVlc1tzdGF0ZUlkeF1bY3VyckJ1Y2tldF0gKz0gdmFsdWVQZXJYO1xuICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgIC8vIGFkZCBpbiBlbmQgYnVja2V0IGFtb3VudFxuICAgICAgICAgICAgICAgIGJ1Y2tldFNjYWxhciA9IDEgLyAoeEJ1Y2tldFZhbHVlc1tlbmRCdWNrZXRdIC0geEJ1Y2tldFZhbHVlc1tlbmRCdWNrZXQgLSAxXSk7XG4gICAgICAgICAgICAgICAgbGV0IGVuZFggPSB4RW5kID8gTWF0aC5taW4oeEVuZCwgbmV4dFZhbHVlLngpIDogbmV4dFZhbHVlLng7XG4gICAgICAgICAgICAgICAgbGV0IHN0YXJ0RW5kQnVja2V0ID0geEJ1Y2tldFZhbHVlc1tlbmRCdWNrZXRdO1xuICAgICAgICAgICAgICAgIHRlbXBWYWx1ZXNbc3RhdGVJZHhdW2VuZEJ1Y2tldF0gKz1cbiAgICAgICAgICAgICAgICAgICAgKGVuZFggLSBzdGFydEVuZEJ1Y2tldCkgKiB2YWx1ZVBlclggKiBidWNrZXRTY2FsYXI7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICByZXRbc3RhdGVJZHhdID0gW107XG5cbiAgICAgICAgbGV0IGJ1Y2tldHMgPSB0ZW1wVmFsdWVzW3N0YXRlSWR4XTtcbiAgICAgICAgZm9yIChsZXQgYnVja2V0ID0gMDsgYnVja2V0IDwgYnVja2V0cy5sZW5ndGg7ICsrYnVja2V0KSB7XG4gICAgICAgICAgICByZXRbc3RhdGVJZHhdW2J1Y2tldF0gPSB7XG4gICAgICAgICAgICAgICAgeDogeEJ1Y2tldFZhbHVlc1tidWNrZXRdLFxuICAgICAgICAgICAgICAgIHk6IHRlbXBWYWx1ZXNbc3RhdGVJZHhdW2J1Y2tldF1cbiAgICAgICAgICAgIH07XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICByZXR1cm4gcmV0O1xufVxuXG4vKiogY2xhc3MgdGhhdCBjb21wdXRlcyB0aGUgc3VtbWVkIHZhbHVlcyBmb3IgZWFjaCBZIHN0YXRlIHBlciBlYWNoIFggYnVja2V0ICovXG5leHBvcnQgY2xhc3MgU3VtbWVkVmFsdWVNdWx0aVhZU2VyaWVzRGVjaW1hdG9yIGltcGxlbWVudHMgSVhZU3RhY2tlZERlY2ltYXRvciB7XG4gICAgcHVibGljIHN0YXRpYyBLRVkgPSAnU3VtbWVkVmFsdWVNdWx0aVhZU2VyaWVzRGVjaW1hdG9yJztcblxuICAgIC8qKiB0aGlzIGZ1bmN0aW9uIGlzIHVzZWQgdG8gbWFwIHRoZSBpbnB1dCB4eVZhbHVlcyB0byB4IHNjYWxlZCB2YWx1ZXMqL1xuICAgIHByb3RlY3RlZCBfeFZhbHVlVG9Db29yZDogKHZhbHVlOiBhbnkpID0+IG51bWJlcjtcblxuICAgIC8qKiB0aGlzIGZ1bmN0aW9uIGlzIHVzZWQgdG8gbWFwIHRoZSByZXZlcnQgeHlWYWx1ZXMgZnJvbSB4IHNjYWxlZCB2YWx1ZXMqL1xuICAgIHByb3RlY3RlZCBfeENvb3JkVG9WYWx1ZTogKHZhbHVlOiBhbnkpID0+IG51bWJlcjtcblxuICAgIC8qKiB0aGlzIGZ1bmN0aW9uIGlzIHVzZWQgdG8gbWFwIHRoZSBpbnB1dCB4eVZhbHVlcyB0byB5IHNjYWxlZCB2YWx1ZXMqL1xuICAgIHByb3RlY3RlZCBfeVZhbHVlVG9Db29yZDogKHZhbHVlOiBhbnkpID0+IG51bWJlcjtcblxuICAgIC8qKiB0aGUgbGlzdCBvZiB2YWx1ZXMgaW4gdGhlIGJ1Y2tldCAqL1xuICAgIHByb3RlY3RlZCBfZGVjaW1hdGVkVmFsdWVzOiBJWFlWYWx1ZVtdW107XG5cbiAgICBjb25zdHJ1Y3RvcigpIHtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBjb25zdHJ1Y3QgYSBnZW5lcmljIGRlY2ltYXRvciB1c2luZyBhIGN1c3RvbSB1c2VyIGZ1bmN0aW9uXG4gICAgICpcbiAgICAgKiBAcGFyYW0geFZhbHVlVG9Db29yZCBjb252ZXJ0cyB0aGUgeCB2YWx1ZSB0byBhIEdVSSB4IGNvb3JkaW5hdGVcbiAgICAgKiBAcGFyYW0geVZhbHVlVG9Db29yZCBjb252ZXJ0cyB0aGUgeSB2YWx1ZSB0byBhIEdVSSB5IGNvb3JkaW5hdGVcbiAgICAgKiBAcGFyYW0gZGVjaW1hdGlvbkZ1bmMgY29udmVydCBhIGxpc3Qgb2YgZGF0YSB0byBhIGZvciByZW5kZXJpbmcgc21hbGxlciBsaXN0XG4gICAgICovXG4gICAgaW5pdGlhbGl6ZSh4VmFsdWVUb0Nvb3JkOiAodmFsdWU6IGFueSkgPT4gbnVtYmVyLFxuICAgICAgICB4Q29vcmRUb1ZhbHVlOiAodmFsdWU6IGFueSkgPT4gbnVtYmVyLFxuICAgICAgICB5VmFsdWVUb0Nvb3JkOiAodmFsdWU6IGFueSkgPT4gbnVtYmVyKSB7XG5cbiAgICAgICAgdGhpcy5feFZhbHVlVG9Db29yZCA9IHhWYWx1ZVRvQ29vcmQ7XG4gICAgICAgIHRoaXMuX3hDb29yZFRvVmFsdWUgPSB4Q29vcmRUb1ZhbHVlO1xuICAgICAgICB0aGlzLl95VmFsdWVUb0Nvb3JkID0geVZhbHVlVG9Db29yZDtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBSZXR1cm5zIHRoZSBrZXkgb2YgdGhpcyBkZWNpbWF0b3JcbiAgICAgKi9cbiAgICBwdWJsaWMgZ2V0S2V5KCk6IHN0cmluZyB7XG4gICAgICAgIHJldHVybiBTdW1tZWRWYWx1ZU11bHRpWFlTZXJpZXNEZWNpbWF0b3IuS0VZO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIFJldHVybnMgdGhlIGRlY2ltYXRlZCBsaXN0IG9mIGJ1Y2tldHNcbiAgICAgKi9cbiAgICBwdWJsaWMgZ2V0TmFtZSgpOiBzdHJpbmcge1xuICAgICAgICByZXR1cm4gJyc7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogUmV0dXJucyB0aGUgZGVjaW1hdGVkIGxpc3Qgb2YgYnVja2V0c1xuICAgICAqL1xuICAgIHB1YmxpYyBnZXRWYWx1ZXMoKTogSVhZVmFsdWVbXVtdIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuX2RlY2ltYXRlZFZhbHVlcztcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBWYWx1ZXMgdG8gYmUgZGVjaW1hdGVkXG4gICAgICpcbiAgICAgKiBAcGFyYW0geFN0YXJ0IC0gc3RhcnQgdGltZSBvZiB0aGUgcmVnaW9uXG4gICAgICogQHBhcmFtIHhFbmQgLSBzdGFydCB0aW1lIG9mIHRoZSByZWdpb25cbiAgICAgKiBAcGFyYW0gdmFsdWVzIC0gVmFsdWVzIHRvIGJlIGRlY2ltYXRlZC5cbiAgICAgKi9cbiAgICBwdWJsaWMgZGVjaW1hdGVWYWx1ZXMoeFN0YXJ0OiBudW1iZXIsIHhFbmQ6IG51bWJlciwgdmFsdWVzOiBJQnVmZmVyPElYWVZhbHVlPltdKTogSVhZVmFsdWVbXVtdIHtcblxuICAgICAgICB0aGlzLl9kZWNpbWF0ZWRWYWx1ZXMgPSBzdW1NdWx0aVhZU2VyaWVzVmFsdWVzKHRoaXMuX3hWYWx1ZVRvQ29vcmQsXG4gICAgICAgICAgICB0aGlzLl94Q29vcmRUb1ZhbHVlLCB0aGlzLl95VmFsdWVUb0Nvb3JkLCB4U3RhcnQsIHhFbmQsIHZhbHVlcyk7XG4gICAgICAgIHJldHVybiB0aGlzLl9kZWNpbWF0ZWRWYWx1ZXM7XG4gICAgfVxufTtcblxuLyoqIGNsYXNzIHRoYXQgY29tcHV0ZXMgdGhlIHJlc2lkZW5jeSB2YWx1ZXMgZm9yIGVhY2ggWSBzdGF0ZSBwZXIgZWFjaCBYIGJ1Y2tldC5cbiAqIFRoaXMgbWVhbnMgdGhlIHN1bSBvZiBhbGwgdmFsdWVzIHdpdGhpbiBhbiBvdXRwdXQgYnVja2V0IGlzIDEwMC5cbiovXG5leHBvcnQgY2xhc3MgUmVzaWRlbmN5RGVjaW1hdG9yIGV4dGVuZHMgU3VtbWVkVmFsdWVNdWx0aVhZU2VyaWVzRGVjaW1hdG9yIHtcbiAgICBwdWJsaWMgc3RhdGljIEtFWSA9ICdSZXNpZGVuY3lEZWNpbWF0b3InO1xuXG4gICAgY29uc3RydWN0b3IoKSB7XG4gICAgICAgIHN1cGVyKCk7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogUmV0dXJucyB0aGUga2V5IG9mIHRoaXMgZGVjaW1hdG9yXG4gICAgICovXG4gICAgcHVibGljIGdldEtleSgpOiBzdHJpbmcge1xuICAgICAgICByZXR1cm4gUmVzaWRlbmN5RGVjaW1hdG9yLktFWTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBSZXR1cm5zIHRoZSBkZWNpbWF0ZWQgbGlzdCBvZiBidWNrZXRzXG4gICAgICovXG4gICAgcHVibGljIGdldE5hbWUoKTogc3RyaW5nIHtcbiAgICAgICAgcmV0dXJuICcnO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIFZhbHVlcyB0byBiZSBkZWNpbWF0ZWRcbiAgICAgKlxuICAgICAqIEBwYXJhbSB4U3RhcnQgLSBzdGFydCB0aW1lIG9mIHRoZSByZWdpb25cbiAgICAgKiBAcGFyYW0geEVuZCAtIHN0YXJ0IHRpbWUgb2YgdGhlIHJlZ2lvblxuICAgICAqIEBwYXJhbSB2YWx1ZXMgLSBWYWx1ZXMgdG8gYmUgZGVjaW1hdGVkLlxuICAgICAqL1xuICAgIHB1YmxpYyBkZWNpbWF0ZVZhbHVlcyh4U3RhcnQ6IG51bWJlciwgeEVuZDogbnVtYmVyLCB2YWx1ZXM6IElCdWZmZXI8SVhZVmFsdWU+W10pOiBJWFlWYWx1ZVtdW10ge1xuXG4gICAgICAgIHRoaXMuX2RlY2ltYXRlZFZhbHVlcyA9IHN1bU11bHRpWFlTZXJpZXNWYWx1ZXModGhpcy5feFZhbHVlVG9Db29yZCxcbiAgICAgICAgICAgIHRoaXMuX3hDb29yZFRvVmFsdWUsIHRoaXMuX3lWYWx1ZVRvQ29vcmQsIHhTdGFydCwgeEVuZCwgdmFsdWVzKTtcblxuICAgICAgICAvLyBub3JtYWxpemUgYWxsIHZhbHVlcyB0byAxMDAlXG4gICAgICAgIGZvciAobGV0IGJ1Y2tldCA9IDA7IGJ1Y2tldCA8IHRoaXMuX2RlY2ltYXRlZFZhbHVlc1swXS5sZW5ndGg7ICsrYnVja2V0KSB7XG4gICAgICAgICAgICBsZXQgdG90YWwgPSAwO1xuICAgICAgICAgICAgZm9yIChsZXQgc3RhdGVJZHggPSAwOyBzdGF0ZUlkeCA8IHRoaXMuX2RlY2ltYXRlZFZhbHVlcy5sZW5ndGg7ICsrc3RhdGVJZHgpIHtcbiAgICAgICAgICAgICAgICBpZiAodGhpcy5fZGVjaW1hdGVkVmFsdWVzW3N0YXRlSWR4XVtidWNrZXRdLnkpIHtcbiAgICAgICAgICAgICAgICAgICAgdG90YWwgKz0gdGhpcy5fZGVjaW1hdGVkVmFsdWVzW3N0YXRlSWR4XVtidWNrZXRdLnk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICAgICAgaWYgKHRvdGFsID4gMCkge1xuICAgICAgICAgICAgICAgIGxldCBzY2FsYXIgPSAxMDAgLyB0b3RhbDtcbiAgICAgICAgICAgICAgICBmb3IgKGxldCBzdGF0ZUlkeCA9IDA7IHN0YXRlSWR4IDwgdmFsdWVzLmxlbmd0aDsgKytzdGF0ZUlkeCkge1xuICAgICAgICAgICAgICAgICAgICBpZiAodGhpcy5fZGVjaW1hdGVkVmFsdWVzW3N0YXRlSWR4XVtidWNrZXRdLnkpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHRoaXMuX2RlY2ltYXRlZFZhbHVlc1tzdGF0ZUlkeF1bYnVja2V0XS55ID1cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aGlzLl9kZWNpbWF0ZWRWYWx1ZXNbc3RhdGVJZHhdW2J1Y2tldF0ueSAqIHNjYWxhcjtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuXG4gICAgICAgIHJldHVybiB0aGlzLl9kZWNpbWF0ZWRWYWx1ZXM7XG4gICAgfVxufTtcblxuLyoqIGNsYXNzIHRoYXQgY29tcHV0ZXMgdGhlIHN1bW1lZCBZIHZhbHVlIHBlciBlYWNoIFggYnVja2V0ICovXG5leHBvcnQgY2xhc3MgU3VtbWVkVmFsdWVYWVNlcmllc0RlY2ltYXRvciBpbXBsZW1lbnRzIElYWURlY2ltYXRvciB7XG4gICAgcHVibGljIHN0YXRpYyBLRVkgPSAnU3VtbWVkVmFsdWVYWVNlcmllc0RlY2ltYXRvcic7XG5cbiAgICAvKiogdGhpcyBmdW5jdGlvbiBpcyB1c2VkIHRvIG1hcCB0aGUgaW5wdXQgeHlWYWx1ZXMgdG8geCBzY2FsZWQgdmFsdWVzKi9cbiAgICBwcm90ZWN0ZWQgX3hWYWx1ZVRvQ29vcmQ6ICh2YWx1ZTogYW55KSA9PiBudW1iZXI7XG5cbiAgICAvKiogdGhpcyBmdW5jdGlvbiBpcyB1c2VkIHRvIG1hcCB0aGUgcmV2ZXJ0IHh5VmFsdWVzIGZyb20geCBzY2FsZWQgdmFsdWVzKi9cbiAgICBwcm90ZWN0ZWQgX3hDb29yZFRvVmFsdWU6ICh2YWx1ZTogYW55KSA9PiBudW1iZXI7XG5cbiAgICAvKiogdGhpcyBmdW5jdGlvbiBpcyB1c2VkIHRvIG1hcCB0aGUgaW5wdXQgeHlWYWx1ZXMgdG8geSBzY2FsZWQgdmFsdWVzKi9cbiAgICBwcm90ZWN0ZWQgX3lWYWx1ZVRvQ29vcmQ6ICh2YWx1ZTogYW55KSA9PiBudW1iZXI7XG5cbiAgICAvKiogdGhlIGxpc3Qgb2YgdmFsdWVzIGluIHRoZSBidWNrZXQgKi9cbiAgICBwcm90ZWN0ZWQgX2RlY2ltYXRlZFZhbHVlczogSVhZVmFsdWVbXTtcblxuICAgIGNvbnN0cnVjdG9yKCkge1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIGNvbnN0cnVjdCBhIGdlbmVyaWMgZGVjaW1hdG9yIHVzaW5nIGEgY3VzdG9tIHVzZXIgZnVuY3Rpb25cbiAgICAgKlxuICAgICAqIEBwYXJhbSB4VmFsdWVUb0Nvb3JkIGNvbnZlcnRzIHRoZSB4IHZhbHVlIHRvIGEgR1VJIHggY29vcmRpbmF0ZVxuICAgICAqIEBwYXJhbSB5VmFsdWVUb0Nvb3JkIGNvbnZlcnRzIHRoZSB5IHZhbHVlIHRvIGEgR1VJIHkgY29vcmRpbmF0ZVxuICAgICAqIEBwYXJhbSBkZWNpbWF0aW9uRnVuYyBjb252ZXJ0IGEgbGlzdCBvZiBkYXRhIHRvIGEgZm9yIHJlbmRlcmluZyBzbWFsbGVyIGxpc3RcbiAgICAgKi9cbiAgICBpbml0aWFsaXplKHhWYWx1ZVRvQ29vcmQ6ICh2YWx1ZTogYW55KSA9PiBudW1iZXIsXG4gICAgICAgIHhDb29yZFRvVmFsdWU6ICh2YWx1ZTogYW55KSA9PiBudW1iZXIsXG4gICAgICAgIHlWYWx1ZVRvQ29vcmQ6ICh2YWx1ZTogYW55KSA9PiBudW1iZXIpIHtcblxuICAgICAgICB0aGlzLl94VmFsdWVUb0Nvb3JkID0geFZhbHVlVG9Db29yZDtcbiAgICAgICAgdGhpcy5feENvb3JkVG9WYWx1ZSA9IHhDb29yZFRvVmFsdWU7XG4gICAgICAgIHRoaXMuX3lWYWx1ZVRvQ29vcmQgPSB5VmFsdWVUb0Nvb3JkO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIFJldHVybnMgdGhlIG5hbWUgb2YgdGhpcyBkZWNpbWF0b3JcbiAgICAgKi9cbiAgICBwdWJsaWMgZ2V0S2V5KCk6IHN0cmluZyB7XG4gICAgICAgIHJldHVybiBTdW1tZWRWYWx1ZVhZU2VyaWVzRGVjaW1hdG9yLktFWTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBSZXR1cm5zIHRoZSBuYW1lIG9mIHRoaXMgZGVjaW1hdG9yXG4gICAgICovXG4gICAgcHVibGljIGdldE5hbWUoKTogc3RyaW5nIHtcbiAgICAgICAgcmV0dXJuICcnO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIFJldHVybnMgdGhlIGRlY2ltYXRlZCBsaXN0IG9mIGJ1Y2tldHNcbiAgICAgKi9cbiAgICBwdWJsaWMgZ2V0VmFsdWVzKCk6IElYWVZhbHVlW10ge1xuICAgICAgICByZXR1cm4gdGhpcy5fZGVjaW1hdGVkVmFsdWVzO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIFZhbHVlcyB0byBiZSBkZWNpbWF0ZWRcbiAgICAgKlxuICAgICAqIEBwYXJhbSB4U3RhcnQgLSBzdGFydCB0aW1lIG9mIHRoZSByZWdpb25cbiAgICAgKiBAcGFyYW0geEVuZCAtIHN0YXJ0IHRpbWUgb2YgdGhlIHJlZ2lvblxuICAgICAqIEBwYXJhbSB2YWx1ZXMgLSBWYWx1ZXMgdG8gYmUgZGVjaW1hdGVkLlxuICAgICAqL1xuICAgIHB1YmxpYyBkZWNpbWF0ZVZhbHVlcyh4U3RhcnQ6IG51bWJlciwgeEVuZDogbnVtYmVyLCB2YWx1ZXM6IElCdWZmZXI8SVhZVmFsdWU+KTogSVhZVmFsdWVbXSB7XG5cbiAgICAgICAgdGhpcy5fZGVjaW1hdGVkVmFsdWVzID0gc3VtTXVsdGlYWVNlcmllc1ZhbHVlcyh0aGlzLl94VmFsdWVUb0Nvb3JkLFxuICAgICAgICAgICAgdGhpcy5feENvb3JkVG9WYWx1ZSwgdGhpcy5feVZhbHVlVG9Db29yZCwgeFN0YXJ0LCB4RW5kLCBbdmFsdWVzXSlbMF07XG4gICAgICAgIHJldHVybiB0aGlzLl9kZWNpbWF0ZWRWYWx1ZXM7XG4gICAgfVxufVxuXG4vKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxuICogTkVXUyAoTWluL01heC9FbnRyeS9FeGl0KSBDSEFSVCBERUNJTUFUT1JTXG4gKi9cbi8qKlxuICogSW50ZXJuYWxseSB1c2VkIGNsYXNzIGZvciB0aGUgYXJyYXkgb2YgdmFsdWVzXG4gKi9cbmV4cG9ydCBjbGFzcyBORVdTRGVjaW1hdGlvblZhbHVlIGV4dGVuZHMgQ2FuZGxlc3RpY2tWYWx1ZSBpbXBsZW1lbnRzIElORVdTRGVjaW1hdGlvblZhbHVlIHtcbiAgICBwdWJsaWMgeTogYW55O1xuXG4gICAgLyoqIG51bWJlciBvZiBzYW1wbGVzIHRoYXQgY29udHJpYnV0ZWQgdG8gdGhpcyBidWNrZXQgKi9cbiAgICBwdWJsaWMgX2J1Y2tldFB0czogbnVtYmVyO1xuXG4gICAgLyoqXG4gICAgICogQ29uc3RydWN0IGEgRGVjaW1hdGlvblZhbHVlIGluc3RhbmNlXG4gICAgICpcbiAgICAgKiBAcGFyYW0gdmFsdWUgLSBhbiBYWVZhbHVlIHRvIGluaXRpYWxpemUgdGhlIGRlY2ltYXRpb24gdmFsdWVcbiAgICAgKi9cbiAgICBjb25zdHJ1Y3Rvcih4PzogYW55KSB7XG4gICAgICAgIHN1cGVyKHgsIHVuZGVmaW5lZCwgdW5kZWZpbmVkLCB1bmRlZmluZWQsIHVuZGVmaW5lZCk7XG4gICAgICAgIHRoaXMuX2J1Y2tldFB0cyA9IDA7XG4gICAgfSAvLyBjb25zdHJ1Y3RvclxufSAvLyBjbGFzcyBEZWNpbWF0aW9uVmFsdWVcblxuLyoqXG4gKiBEYXRhIGRlY2ltYXRpb24gdG8gZml0IGluZm9ybWF0aW9uIHRvIG9udG8gdGhlIGdyYXBoLlxuICpcbiAqIFRoaXMgY2xhc3MgZGl2aWRlcyB0aGUgeC1BeGlzIHRpbWUgcmFuZ2UgaW50byBhIHNldCBvZiBidWNrZXRzLiAgRWFjaFxuICogYnVja2V0IHByb3ZpZGVzIHRoZSBhdmVyYWdlIG9mIHRoZSB2YWx1ZXMsIHRoZSBtaW5pbXVtICYgbWF4aW11bVxuICogdmFsdWVzLCBhbmQgdGhlIHZhbHVlcyB1cG9uIGVudHJ5ICYgZXhpdC5cbiAqIEl0IGFzc3VtZXMgdGhhdCB0aGUgREIgdmFsdWVzIGFyZSBpbmNyZWFzZSBvdmVyIHRoZSB0aW1lLlxuICovXG5leHBvcnQgY2xhc3MgTkVXU0Jhc2VEZWNpbWF0b3IgaW1wbGVtZW50cyBJRGVjaW1hdG9yIHtcbiAgICAvKiogYW4gdW5pcXVlIGlkZW50aWZpZXIgZm9yIHRoaXMgZGVjaW1hdG9yICovXG4gICAgcHJvdGVjdGVkIF9rZXk6IHN0cmluZztcblxuICAgIC8qKiBUaGUgYnVja2V0cyB3ZSdyZSBhY2N1bWxhdGluZyAqL1xuICAgIHByb3RlY3RlZCBfYnVja2V0czogTkVXU0RlY2ltYXRpb25WYWx1ZVtdO1xuXG4gICAgLyoqIHRoaXMgZnVuY3Rpb24gaXMgdXNlZCB0byBtYXAgdGhlIGlucHV0IHh5VmFsdWVzIHRvIHggc2NhbGVkIHZhbHVlcyovXG4gICAgcHJvdGVjdGVkIF94VmFsdWVUb0Nvb3JkOiAodmFsdWU6IGFueSkgPT4gbnVtYmVyO1xuXG4gICAgLyoqIHRoaXMgZnVuY3Rpb24gaXMgdXNlZCB0byBtYXAgdGhlIHJldmVydCB4eVZhbHVlcyBmcm9tIHggc2NhbGVkIHZhbHVlcyovXG4gICAgcHJvdGVjdGVkIF94Q29vcmRUb1ZhbHVlOiAodmFsdWU6IGFueSkgPT4gbnVtYmVyO1xuXG4gICAgLyoqIHRoaXMgZnVuY3Rpb24gaXMgdXNlZCB0byBtYXAgdGhlIGlucHV0IHh5VmFsdWVzIHRvIHkgc2NhbGVkIHZhbHVlcyovXG4gICAgcHJvdGVjdGVkIF95VmFsdWVUb0Nvb3JkOiAodmFsdWU6IGFueSkgPT4gbnVtYmVyO1xuXG4gICAgcHVibGljIGluaXRpYWxpemUoeFZhbHVlVG9Db29yZDogKHZhbHVlOiBhbnkpID0+IG51bWJlcixcbiAgICAgICAgeENvb3JkVG9WYWx1ZTogKHZhbHVlOiBhbnkpID0+IG51bWJlcixcbiAgICAgICAgeVZhbHVlVG9Db29yZDogKHZhbHVlOiBhbnkpID0+IG51bWJlcikge1xuICAgICAgICB0aGlzLl94VmFsdWVUb0Nvb3JkID0geFZhbHVlVG9Db29yZDtcbiAgICAgICAgdGhpcy5feENvb3JkVG9WYWx1ZSA9IHhDb29yZFRvVmFsdWU7XG4gICAgICAgIHRoaXMuX3lWYWx1ZVRvQ29vcmQgPSB5VmFsdWVUb0Nvb3JkO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIFJldHVybnMgdGhlIGtleSBvZiB0aGlzIGRlY2ltYXRvclxuICAgICAqL1xuICAgIHB1YmxpYyBnZXRLZXkoKTogc3RyaW5nIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuX2tleTtcbiAgICB9XG5cbiAgICBwdWJsaWMgZ2V0TmFtZSgpOiBzdHJpbmcge1xuICAgICAgICByZXR1cm4gJyc7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogR2V0IHRoZSBhY2N1bXVsYXRlZCBidWNrZXRzXG4gICAgICpcbiAgICAgKiBAcmV0dXJucyB0aGUgYWNjdW11bGF0ZWQgYnVja2V0c1xuICAgICAqL1xuICAgIHB1YmxpYyBnZXRWYWx1ZXMoKTogTkVXU0RlY2ltYXRpb25WYWx1ZVtdIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuX2J1Y2tldHM7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogQnVja2V0IGR1bXBlclxuICAgICAqL1xuICAgIHB1YmxpYyBfZHVtcEJ1Y2tldChmaXJzdFRpbWVTdGFtcDogbnVtYmVyLCBidWNrZXQ6IE5FV1NEZWNpbWF0aW9uVmFsdWUsIHZhbHVlc0luQnVja2V0OiBudW1iZXIpOiBzdHJpbmcge1xuICAgICAgICBsZXQgZGV0YWlsczogc3RyaW5nID0gXCJ2YWx1ZXNJbkJ1Y2tldCA9IFwiICsgdmFsdWVzSW5CdWNrZXQudG9GaXhlZCgwKSArIFwiLCBcIjtcblxuICAgICAgICBkZXRhaWxzICs9IFwiKFthdmddVGltZSBkZWx0YSwgYXZnVmFsdWUpID0gKFwiICtcbiAgICAgICAgICAgIChidWNrZXQueCAtIGZpcnN0VGltZVN0YW1wKS50b0ZpeGVkKDIpICsgXCIsIFwiICsgYnVja2V0LnkudG9GaXhlZCgyKSArIFwiKSwgXCI7XG4gICAgICAgIGRldGFpbHMgKz0gXCIoZW50cnksIG1pbiwgbWF4LCBleGl0KSA9IChcIiArIChidWNrZXQuZW50cnkpLnRvRml4ZWQoMikgKyBcIiwgXCIgK1xuICAgICAgICAgICAgKGJ1Y2tldC5taW4pLnRvRml4ZWQoMikgKyBcIiwgXCIgKyAoYnVja2V0Lm1heCkudG9GaXhlZCgyKSArIFwiLCBcIiArXG4gICAgICAgICAgICAoYnVja2V0LmV4aXQpLnRvRml4ZWQoMikgKyBcIilcIjtcblxuICAgICAgICByZXR1cm4gZGV0YWlscztcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBWYWx1ZXMgdG8gYmUgZGVjaW1hdGVkXG4gICAgICpcbiAgICAgKiBAcGFyYW0geFN0YXJ0IC0gc3RhcnQgdGltZSBvZiB0aGUgcmVnaW9uXG4gICAgICogQHBhcmFtIHhFbmQgLSBzdGFydCB0aW1lIG9mIHRoZSByZWdpb25cbiAgICAgKiBAcGFyYW0gdmFsdWVzIC0gVmFsdWVzIHRvIGJlIGRlY2ltYXRlZC5cbiAgICAgKi9cbiAgICBwdWJsaWMgZGVjaW1hdGVWYWx1ZXMoeFN0YXJ0OiBudW1iZXIsIHhFbmQ6IG51bWJlciwgaW5wdXRWYWx1ZXM6IElCdWZmZXI8SVhZVmFsdWU+KTogTkVXU0RlY2ltYXRpb25WYWx1ZVtdIHtcbiAgICAgICAgdGhyb3cgJ0Vycm9yIG5lZWQgdG8gaW1wbGVtZW50IGRlY2ltYXRlIGNvZGUnXG4gICAgfVxufVxuXG4vKiogdGhpcyBjbGFzcyB0YWtlcyBhIHNlcmllcyB4LCB5IHBvaW50cyBhbmQgdXNpbmcgZm9yIGVhY2ggWCBidWNrZXQgcHJvdmlkZXNcbiAqIHRoZSBZIGVudHJ5L2V4aXQvbWluL21heC9hdmVyYWdlIGZvciB0aGF0IFggYnVja2V0XG4gKi9cbmV4cG9ydCBjbGFzcyBORVdTUG9pbnREZWNpbWF0b3IgZXh0ZW5kcyBORVdTQmFzZURlY2ltYXRvciB7XG4gICAgcHVibGljIHN0YXRpYyBLRVkgPSAnTkVXU1BvaW50RGVjaW1hdG9yJztcbiAgICBjb25zdHJ1Y3RvcigpIHtcbiAgICAgICAgc3VwZXIoKTtcbiAgICAgICAgdGhpcy5fa2V5ID0gTkVXU1BvaW50RGVjaW1hdG9yLktFWTtcbiAgICB9XG5cbiAgICBwcm90ZWN0ZWQgY3JlYXRlTmV3QnVja2V0KGRlY2ltYXRlZFZhbHVlOiBORVdTRGVjaW1hdGlvblZhbHVlLCB2YWx1ZTogSVhZVmFsdWUpOiB2b2lkIHtcbiAgICAgICAgZGVjaW1hdGVkVmFsdWUuZW50cnkgPSB2YWx1ZS55O1xuICAgICAgICBkZWNpbWF0ZWRWYWx1ZS5leGl0ID0gdmFsdWUueTtcbiAgICAgICAgZGVjaW1hdGVkVmFsdWUubWluID0gdmFsdWUueTtcbiAgICAgICAgZGVjaW1hdGVkVmFsdWUubWF4ID0gdmFsdWUueTtcbiAgICAgICAgZGVjaW1hdGVkVmFsdWUueCA9IDA7XG4gICAgICAgIGRlY2ltYXRlZFZhbHVlLnkgPSAwO1xuICAgICAgICBkZWNpbWF0ZWRWYWx1ZS5fYnVja2V0UHRzID0gMDtcbiAgICAgICAgdGhpcy5hZGRUb0J1Y2tldChkZWNpbWF0ZWRWYWx1ZSwgdmFsdWUpO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIEFkZCBhbiB4L3kgdmFsdWUgcGFpciB0byB0aGlzIHZhbHVlLiBCb3RoIHRoZSB0aW1lICh4KSBhbmRcbiAgICAgKiB2YWx1ZSAoeSkgYXJlIGFkZGVkIHRvIHRoaXMgcG9pbnQvYnVja2V0XG4gICAgICpcbiAgICAgKiBAcGFyYW0gZGJQb2ludCAtIFRoZSB4L3kgdmFsdWUgcGFpciB0byBhZGQgdG8gdGhpcyB2YWx1ZS5cbiAgICAqL1xuXG4gICAgcHJvdGVjdGVkIGFkZFRvQnVja2V0KGRlY2ltYXRlZFZhbHVlOiBORVdTRGVjaW1hdGlvblZhbHVlLCB2YWx1ZTogSVhZVmFsdWUpOiB2b2lkIHtcbiAgICAgICAgZGVjaW1hdGVkVmFsdWUueCArPSB2YWx1ZS54O1xuICAgICAgICBkZWNpbWF0ZWRWYWx1ZS55ICs9IHZhbHVlLnk7XG4gICAgICAgIGRlY2ltYXRlZFZhbHVlLm1pbiA9IE1hdGgubWluKGRlY2ltYXRlZFZhbHVlLm1pbiwgdmFsdWUueSk7XG4gICAgICAgIGRlY2ltYXRlZFZhbHVlLm1heCA9IE1hdGgubWF4KGRlY2ltYXRlZFZhbHVlLm1heCwgdmFsdWUueSk7XG4gICAgICAgIGRlY2ltYXRlZFZhbHVlLmV4aXQgPSB2YWx1ZS55O1xuXG4gICAgICAgIGRlY2ltYXRlZFZhbHVlLl9idWNrZXRQdHMrKztcbiAgICB9XG5cbiAgICBwcm90ZWN0ZWQgZmluYWxpemVCdWNrZXQoZGVjaW1hdGVkVmFsdWU6IE5FV1NEZWNpbWF0aW9uVmFsdWUsIHBvaW50c0luQnVja2V0PzogbnVtYmVyKSB7XG4gICAgICAgIGlmICh1bmRlZmluZWQgIT09IHBvaW50c0luQnVja2V0KSB7XG4gICAgICAgICAgICBpZiAocG9pbnRzSW5CdWNrZXQgIT09IGRlY2ltYXRlZFZhbHVlLl9idWNrZXRQdHMpIHtcbiAgICAgICAgICAgICAgICBjb25zb2xlLmxvZyhcIkF2ZXJhZ2VUaW1lOiBtaXNtYXRjaGluZyBwdCBjYWxjdWxhdGlvblwiKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICBpZiAoZGVjaW1hdGVkVmFsdWUuX2J1Y2tldFB0cyA9PT0gMCkge1xuICAgICAgICAgICAgY29uc29sZS5sb2coXCJBdmVyYWdlVGltZTogMCBwb2ludHNcIik7XG4gICAgICAgIH1cbiAgICAgICAgZGVjaW1hdGVkVmFsdWUueCA9IGRlY2ltYXRlZFZhbHVlLnggLyBkZWNpbWF0ZWRWYWx1ZS5fYnVja2V0UHRzO1xuICAgICAgICBkZWNpbWF0ZWRWYWx1ZS55ID0gZGVjaW1hdGVkVmFsdWUueSAvIGRlY2ltYXRlZFZhbHVlLl9idWNrZXRQdHM7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogVmFsdWVzIHRvIGJlIGRlY2ltYXRlZFxuICAgICAqXG4gICAgICogQHBhcmFtIHhTdGFydCAtIHN0YXJ0IHRpbWUgb2YgdGhlIHJlZ2lvblxuICAgICAqIEBwYXJhbSB4RW5kIC0gc3RhcnQgdGltZSBvZiB0aGUgcmVnaW9uXG4gICAgICogQHBhcmFtIHZhbHVlcyAtIFZhbHVlcyB0byBiZSBkZWNpbWF0ZWQuXG4gICAgICovXG4gICAgcHVibGljIGRlY2ltYXRlVmFsdWVzKHhTdGFydDogbnVtYmVyLCB4RW5kOiBudW1iZXIsIGlucHV0VmFsdWVzOiBJQnVmZmVyPElYWVZhbHVlPik6IE5FV1NEZWNpbWF0aW9uVmFsdWVbXSB7XG4gICAgICAgIC8vIGxvb3Agb3ZlciB0aGUgZGF0YSBzYW1wbGVzXG4gICAgICAgIHRoaXMuX2J1Y2tldHMgPSBbXTtcbiAgICAgICAgaWYgKGlucHV0VmFsdWVzLmxlbmd0aCgpID09PSAwKSB7XG4gICAgICAgICAgICByZXR1cm4gdGhpcy5fYnVja2V0cztcbiAgICAgICAgfVxuICAgICAgICBsZXQgY3VycmVudFBvaW50OiBORVdTRGVjaW1hdGlvblZhbHVlO1xuXG4gICAgICAgIGxldCBsZWZ0OiBudW1iZXIgPSBmaW5kRmlyc3RJbnNlcnRpb25JZHgoaW5wdXRWYWx1ZXMsIHhTdGFydCk7XG4gICAgICAgIGxldCByaWdodDogbnVtYmVyID0gZmluZExhc3RJbnNlcnRpb25JZHgoaW5wdXRWYWx1ZXMsIHhFbmQpO1xuXG4gICAgICAgIGlmIChsZWZ0ID4gMCkge1xuICAgICAgICAgICAgLS1sZWZ0O1xuICAgICAgICB9XG4gICAgICAgIGlmIChyaWdodCA8IGlucHV0VmFsdWVzLmxlbmd0aCgpKSB7XG4gICAgICAgICAgICArK3JpZ2h0O1xuICAgICAgICB9XG5cbiAgICAgICAgbGV0IGxhc3RYOiBudW1iZXIgPSAwO1xuICAgICAgICBpZiAobGVmdCA8IGlucHV0VmFsdWVzLmxlbmd0aCgpKSB7XG4gICAgICAgICAgICBsYXN0WCA9IE1hdGguZmxvb3IodGhpcy5feFZhbHVlVG9Db29yZChpbnB1dFZhbHVlcy5nZXQobGVmdCkueCkpO1xuICAgICAgICAgICAgLS1sYXN0WDtcbiAgICAgICAgfVxuXG4gICAgICAgIGZvciAobGV0IGluZGV4OiBudW1iZXIgPSBsZWZ0OyBpbmRleCA8IHJpZ2h0OyArK2luZGV4KSB7XG4gICAgICAgICAgICBsZXQgaW5wdXRWYWx1ZSA9IGlucHV0VmFsdWVzLmdldChpbmRleCk7XG4gICAgICAgICAgICBsZXQgeENvb3JkID0gTWF0aC5mbG9vcih0aGlzLl94VmFsdWVUb0Nvb3JkKGlucHV0VmFsdWUueCkpO1xuXG4gICAgICAgICAgICBpZiAoeENvb3JkICE9PSBsYXN0WCkge1xuICAgICAgICAgICAgICAgIGlmIChjdXJyZW50UG9pbnQpIHtcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5maW5hbGl6ZUJ1Y2tldChjdXJyZW50UG9pbnQpO1xuICAgICAgICAgICAgICAgICAgICB0aGlzLl9idWNrZXRzLnB1c2goY3VycmVudFBvaW50KTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgY3VycmVudFBvaW50ID0gbmV3IE5FV1NEZWNpbWF0aW9uVmFsdWUoKTtcbiAgICAgICAgICAgICAgICB0aGlzLmNyZWF0ZU5ld0J1Y2tldChjdXJyZW50UG9pbnQsIGlucHV0VmFsdWUpO1xuXG4gICAgICAgICAgICAgICAgbGFzdFggPSB4Q29vcmQ7XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgIHRoaXMuYWRkVG9CdWNrZXQoY3VycmVudFBvaW50LCBpbnB1dFZhbHVlKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuXG4gICAgICAgIGlmIChjdXJyZW50UG9pbnQpIHtcbiAgICAgICAgICAgIHRoaXMuZmluYWxpemVCdWNrZXQoY3VycmVudFBvaW50KTtcbiAgICAgICAgICAgIHRoaXMuX2J1Y2tldHMucHVzaChjdXJyZW50UG9pbnQpO1xuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIHRoaXMuX2J1Y2tldHM7XG4gICAgfSAgLy8gZGVjaW1hdGVWYWx1ZXMoKVxufSAgIC8vIGNsYXNzIE5FV1NEZWNpbWF0b3JcblxuLyoqIHRoaXMgY2xhc3MgdGFrZXMgYSBzZXJpZXMgeCwgeSBwb2ludHMgYW5kIHVzaW5nIGZvciBlYWNoIFggYnVja2V0IHByb3ZpZGVzXG4gKiB0aGUgWSBlbnRyeS9leGl0L21pbi9tYXgvYXZlcmFnZSBmb3IgdGhhdCBYIGJ1Y2tldFxuICovXG5leHBvcnQgY2xhc3MgTkVXU1N0YXRlRGVjaW1hdG9yIGV4dGVuZHMgTkVXU0Jhc2VEZWNpbWF0b3Ige1xuICAgIHB1YmxpYyBzdGF0aWMgS0VZID0gJ05FV1NTdGF0ZURlY2ltYXRvcic7XG4gICAgcHJvdGVjdGVkIF93ZWlnaHRlZFN1bXM6IHsgW2luZGV4OiBzdHJpbmddOiBudW1iZXIgfSA9IHt9O1xuICAgIHByb3RlY3RlZCBfcHJldlggPSAwO1xuICAgIHByb3RlY3RlZCBfaXNZT2JqZWN0OiBib29sZWFuO1xuICAgIHByb3RlY3RlZCBfc3RhdGVzOiBzdHJpbmdbXTtcblxuICAgIGNvbnN0cnVjdG9yKHN0YXRlcz86IHN0cmluZ1tdKSB7XG4gICAgICAgIHN1cGVyKCk7XG4gICAgICAgIHRoaXMuX3ByZXZYID0gMDtcbiAgICAgICAgdGhpcy5fa2V5ID0gTkVXU1N0YXRlRGVjaW1hdG9yLktFWTtcblxuICAgICAgICBpZiAoc3RhdGVzKSB7XG4gICAgICAgICAgICB0aGlzLl9zdGF0ZXMgPSBzdGF0ZXM7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICBwcm90ZWN0ZWQgY3JlYXRlTmV3QnVja2V0KGRlY2ltYXRlZFZhbHVlOiBORVdTRGVjaW1hdGlvblZhbHVlLCB2YWx1ZTogSVhZVmFsdWUpIHtcbiAgICAgICAgdGhpcy5fd2VpZ2h0ZWRTdW1zID0ge307XG4gICAgICAgIGRlY2ltYXRlZFZhbHVlLl9idWNrZXRQdHMgPSAwO1xuXG4gICAgICAgIGxldCBkZWZhdWx0VmFsdWU6IGFueTtcbiAgICAgICAgaWYgKCF0aGlzLl9pc1lPYmplY3QpIHtcbiAgICAgICAgICAgIGRlZmF1bHRWYWx1ZSA9IHZhbHVlLnk7XG4gICAgICAgICAgICBkZWNpbWF0ZWRWYWx1ZS54ID0gMDtcbiAgICAgICAgICAgIGRlY2ltYXRlZFZhbHVlLnkgPSBkZWZhdWx0VmFsdWU7XG4gICAgICAgICAgICBkZWNpbWF0ZWRWYWx1ZS5lbnRyeSA9IGRlZmF1bHRWYWx1ZTtcbiAgICAgICAgICAgIGRlY2ltYXRlZFZhbHVlLmV4aXQgPSBkZWZhdWx0VmFsdWU7XG4gICAgICAgICAgICBkZWNpbWF0ZWRWYWx1ZS5taW4gPSBkZWZhdWx0VmFsdWU7XG4gICAgICAgICAgICBkZWNpbWF0ZWRWYWx1ZS5tYXggPSBkZWZhdWx0VmFsdWU7XG4gICAgICAgIH1cblxuICAgICAgICB0aGlzLmFkZFRvQnVja2V0KGRlY2ltYXRlZFZhbHVlLCB2YWx1ZSk7XG4gICAgfTtcblxuICAgIHByb3RlY3RlZCBhZGRUb1N0YXRlVmFsdWVUb0J1Y2tldChzdGF0ZTogc3RyaW5nLCB2YWx1ZTogbnVtYmVyKSB7XG4gICAgICAgIGlmICh2YWx1ZSA9PT0gMCkge1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG4gICAgICAgIGlmICghdGhpcy5fd2VpZ2h0ZWRTdW1zW3N0YXRlXSkge1xuICAgICAgICAgICAgdGhpcy5fd2VpZ2h0ZWRTdW1zW3N0YXRlXSA9IDA7XG4gICAgICAgIH1cbiAgICAgICAgdGhpcy5fd2VpZ2h0ZWRTdW1zW3N0YXRlXSArPSB2YWx1ZTtcbiAgICB9XG5cbiAgICBwcm90ZWN0ZWQgYWRkVG9CdWNrZXQoZGVjaW1hdGVkVmFsdWU6IE5FV1NEZWNpbWF0aW9uVmFsdWUsIHZhbHVlOiBJWFlWYWx1ZSk6IHZvaWQge1xuXG4gICAgICAgIGlmICh0aGlzLl9pc1lPYmplY3QpIHtcbiAgICAgICAgICAgIGlmICh0aGlzLl9zdGF0ZXMpIHtcbiAgICAgICAgICAgICAgICAvLyB0YWtlIHByZXZYIGFuZCBjdXJyZW50WFxuICAgICAgICAgICAgICAgIGZvciAobGV0IHN0YXRlS2V5IGluIHZhbHVlLnkgYXMgeyBbaW5kZXg6IG51bWJlcl06IG51bWJlciB9KSB7XG4gICAgICAgICAgICAgICAgICAgIHRoaXMuYWRkVG9TdGF0ZVZhbHVlVG9CdWNrZXQodGhpcy5fc3RhdGVzW3N0YXRlS2V5XSxcbiAgICAgICAgICAgICAgICAgICAgICAgICh2YWx1ZS54IC0gdGhpcy5fcHJldlgpICogdmFsdWUueVtzdGF0ZUtleV0pO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgLy8gdGFrZSBwcmV2WCBhbmQgY3VycmVudFhcbiAgICAgICAgICAgICAgICBmb3IgKGxldCBzdGF0ZSBpbiB2YWx1ZS55KSB7XG4gICAgICAgICAgICAgICAgICAgIHRoaXMuYWRkVG9TdGF0ZVZhbHVlVG9CdWNrZXQoc3RhdGUsXG4gICAgICAgICAgICAgICAgICAgICAgICAodmFsdWUueCAtIHRoaXMuX3ByZXZYKSAqIHZhbHVlLnlbc3RhdGVdKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICBsZXQgc3RhdGU6IGFueTtcbiAgICAgICAgICAgIGlmICh0aGlzLl9zdGF0ZXMpIHtcbiAgICAgICAgICAgICAgICBzdGF0ZSA9IHRoaXMuX3N0YXRlc1t2YWx1ZS55XTtcbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgc3RhdGUgPSB2YWx1ZS55O1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgZGVjaW1hdGVkVmFsdWUuZXhpdCA9IHN0YXRlO1xuICAgICAgICAgICAgdGhpcy5hZGRUb1N0YXRlVmFsdWVUb0J1Y2tldChzdGF0ZSwgKHZhbHVlLnggLSB0aGlzLl9wcmV2WCkpO1xuICAgICAgICB9XG5cbiAgICAgICAgZGVjaW1hdGVkVmFsdWUueCArPSB2YWx1ZS54O1xuICAgICAgICBkZWNpbWF0ZWRWYWx1ZS5fYnVja2V0UHRzKys7XG5cbiAgICAgICAgdGhpcy5fcHJldlggPSB2YWx1ZS54O1xuICAgIH1cblxuICAgIHByb3RlY3RlZCBmaW5hbGl6ZUJ1Y2tldChkZWNpbWF0ZWRWYWx1ZTogTkVXU0RlY2ltYXRpb25WYWx1ZSxcbiAgICAgICAgcG9pbnRzSW5CdWNrZXQ/OiBudW1iZXIpOiB2b2lkIHtcbiAgICAgICAgaWYgKHVuZGVmaW5lZCAhPT0gcG9pbnRzSW5CdWNrZXQpIHtcbiAgICAgICAgICAgIGlmIChwb2ludHNJbkJ1Y2tldCAhPT0gZGVjaW1hdGVkVmFsdWUuX2J1Y2tldFB0cykge1xuICAgICAgICAgICAgICAgIGNvbnNvbGUubG9nKFwiQXZlcmFnZVRpbWU6IG1pc21hdGNoaW5nIHB0IGNhbGN1bGF0aW9uXCIpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgIGlmIChkZWNpbWF0ZWRWYWx1ZS5fYnVja2V0UHRzID09PSAwKSB7XG4gICAgICAgICAgICBjb25zb2xlLmxvZyhcIkF2ZXJhZ2VUaW1lOiAwIHBvaW50c1wiKTtcbiAgICAgICAgfVxuICAgICAgICBkZWNpbWF0ZWRWYWx1ZS54ID0gZGVjaW1hdGVkVmFsdWUueCAvIGRlY2ltYXRlZFZhbHVlLl9idWNrZXRQdHM7XG5cbiAgICAgICAgLy8gZmluZCB0aGUgbWF4aW11bSB2YWx1ZSBieSB3ZWlnaHRlZFN1bXNcbiAgICAgICAgdmFyIG1heFdlaWdodGVkS2V5OiBhbnk7XG4gICAgICAgIHZhciBtYXhXZWlnaHRWYWx1ZSA9IC1OdW1iZXIuTUFYX1ZBTFVFO1xuICAgICAgICBsZXQgbWluU3RhdGUgPSAtTnVtYmVyLk1BWF9WQUxVRTtcbiAgICAgICAgbGV0IG1heFN0YXRlID0gTnVtYmVyLk1BWF9WQUxVRTtcblxuICAgICAgICBmb3IgKGxldCBzdGF0ZSBpbiB0aGlzLl93ZWlnaHRlZFN1bXMpIHtcbiAgICAgICAgICAgIGlmICh0aGlzLl93ZWlnaHRlZFN1bXNbc3RhdGVdICE9PSB1bmRlZmluZWQpIHtcbiAgICAgICAgICAgICAgICBsZXQgc3RhdGVXZWlnaHQgPSB0aGlzLl93ZWlnaHRlZFN1bXNbc3RhdGVdO1xuICAgICAgICAgICAgICAgIGlmIChzdGF0ZVdlaWdodCA+IG1heFdlaWdodFZhbHVlKSB7XG4gICAgICAgICAgICAgICAgICAgIG1heFdlaWdodGVkS2V5ID0gc3RhdGU7XG4gICAgICAgICAgICAgICAgICAgIG1heFdlaWdodFZhbHVlID0gc3RhdGVXZWlnaHQ7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICAgICAgLy8gbWluIGlzIGJpZ2dlciBzaW5jZSBZIHZhbHVlcyBpbmNyZWFzZSBhcyB5b3UgZ28gZG93biB0aGUgYXhpc1xuICAgICAgICAgICAgbGV0IHlPZmZzZXQgPSB0aGlzLl95VmFsdWVUb0Nvb3JkKHN0YXRlKTtcbiAgICAgICAgICAgIGlmICh5T2Zmc2V0ID4gbWluU3RhdGUpIHtcbiAgICAgICAgICAgICAgICBkZWNpbWF0ZWRWYWx1ZS5taW4gPSBzdGF0ZTtcbiAgICAgICAgICAgICAgICBtaW5TdGF0ZSA9IHlPZmZzZXQ7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBpZiAoeU9mZnNldCA8IG1heFN0YXRlKSB7XG4gICAgICAgICAgICAgICAgZGVjaW1hdGVkVmFsdWUubWF4ID0gc3RhdGU7XG4gICAgICAgICAgICAgICAgbWF4U3RhdGUgPSB5T2Zmc2V0O1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG5cbiAgICAgICAgbGV0IGhhc1ZhbHVlcyA9IG1heFdlaWdodGVkS2V5ICE9PSB1bmRlZmluZWQ7XG4gICAgICAgIGlmIChoYXNWYWx1ZXMpIHtcbiAgICAgICAgICAgIGRlY2ltYXRlZFZhbHVlLnkgPSBtYXhXZWlnaHRlZEtleTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIC8vIG5vIHZhbHVlcyBzbyBzZXQgYSBkZWZhdWx0IGEgeSB2YWx1ZVxuICAgICAgICAgICAgaWYgKCF0aGlzLl9pc1lPYmplY3QpIHtcbiAgICAgICAgICAgICAgICBkZWNpbWF0ZWRWYWx1ZS5taW4gPSBkZWNpbWF0ZWRWYWx1ZS55O1xuICAgICAgICAgICAgICAgIGRlY2ltYXRlZFZhbHVlLm1heCA9IGRlY2ltYXRlZFZhbHVlLnk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgIH0gLy8gZmluYWxpemUgKTtcblxuICAgIC8qKlxuICAgICAqIFZhbHVlcyB0byBiZSBkZWNpbWF0ZWRcbiAgICAgKlxuICAgICAqIEBwYXJhbSB4U3RhcnQgLSBzdGFydCB0aW1lIG9mIHRoZSByZWdpb25cbiAgICAgKiBAcGFyYW0geEVuZCAtIHN0YXJ0IHRpbWUgb2YgdGhlIHJlZ2lvblxuICAgICAqIEBwYXJhbSB2YWx1ZXMgLSBWYWx1ZXMgdG8gYmUgZGVjaW1hdGVkLlxuICAgICAqL1xuICAgIHB1YmxpYyBkZWNpbWF0ZVZhbHVlcyh4U3RhcnQ6IG51bWJlciwgeEVuZDogbnVtYmVyLFxuICAgICAgICBpbnB1dFZhbHVlczogSUJ1ZmZlcjxJWFlWYWx1ZT4pOiBORVdTRGVjaW1hdGlvblZhbHVlW10ge1xuICAgICAgICAvLyBsb29wIG92ZXIgdGhlIGRhdGEgc2FtcGxlc1xuICAgICAgICB0aGlzLl9idWNrZXRzID0gW107XG4gICAgICAgIGlmIChpbnB1dFZhbHVlcy5sZW5ndGgoKSA9PT0gMCkge1xuICAgICAgICAgICAgcmV0dXJuIHRoaXMuX2J1Y2tldHM7XG4gICAgICAgIH1cbiAgICAgICAgbGV0IGN1cnJlbnRQb2ludDogTkVXU0RlY2ltYXRpb25WYWx1ZTtcblxuICAgICAgICBsZXQgbGVmdDogbnVtYmVyID0gZmluZEZpcnN0SW5zZXJ0aW9uSWR4KGlucHV0VmFsdWVzLCB4U3RhcnQpO1xuICAgICAgICBsZXQgcmlnaHQ6IG51bWJlciA9IGZpbmRMYXN0SW5zZXJ0aW9uSWR4KGlucHV0VmFsdWVzLCB4RW5kKTtcblxuICAgICAgICBpZiAobGVmdCA+IDApIHtcbiAgICAgICAgICAgIC0tbGVmdDtcbiAgICAgICAgfVxuICAgICAgICBpZiAocmlnaHQgPCBpbnB1dFZhbHVlcy5sZW5ndGgoKSkge1xuICAgICAgICAgICAgKytyaWdodDtcbiAgICAgICAgfVxuXG4gICAgICAgIGxldCBsYXN0WDogbnVtYmVyID0gMDtcbiAgICAgICAgaWYgKGxlZnQgPCBpbnB1dFZhbHVlcy5sZW5ndGgoKSkge1xuICAgICAgICAgICAgdGhpcy5faXNZT2JqZWN0ID0gdHlwZW9mIChpbnB1dFZhbHVlcy5nZXQobGVmdCkueSkgPT09ICdvYmplY3QnO1xuICAgICAgICAgICAgbGFzdFggPSBNYXRoLmZsb29yKHRoaXMuX3hWYWx1ZVRvQ29vcmQoaW5wdXRWYWx1ZXMuZ2V0KGxlZnQpLngpKTtcbiAgICAgICAgICAgIC0tbGFzdFg7XG4gICAgICAgIH1cblxuICAgICAgICBmb3IgKGxldCBpbmRleDogbnVtYmVyID0gbGVmdDsgaW5kZXggPCByaWdodDsgKytpbmRleCkge1xuICAgICAgICAgICAgbGV0IGlucHV0VmFsdWUgPSBpbnB1dFZhbHVlcy5nZXQoaW5kZXgpO1xuICAgICAgICAgICAgbGV0IHhDb29yZCA9IE1hdGguZmxvb3IodGhpcy5feFZhbHVlVG9Db29yZChpbnB1dFZhbHVlLngpKTtcblxuICAgICAgICAgICAgaWYgKHhDb29yZCAhPT0gbGFzdFgpIHtcbiAgICAgICAgICAgICAgICBpZiAoY3VycmVudFBvaW50KSB7XG4gICAgICAgICAgICAgICAgICAgIHRoaXMuZmluYWxpemVCdWNrZXQoY3VycmVudFBvaW50KTtcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5fYnVja2V0cy5wdXNoKGN1cnJlbnRQb2ludCk7XG4gICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgLy8gYWRkIGluIGJ1Y2tldHMgYmV0d2VlbiB0aGUgcHJldmlvdXMgYnVja2V0IGFuZCB0aGUgbmV3IGJ1Y2tldCBzaW5jZVxuICAgICAgICAgICAgICAgIC8vIHRoZSBzdGF0ZSBzcGFucyB0aGUgd2hvbGUgdGltZVxuICAgICAgICAgICAgICAgIGlmIChsYXN0WCArIDEgPCB4Q29vcmQpIHtcbiAgICAgICAgICAgICAgICAgICAgbGV0IHBvaW50ID0gbmV3IE5FV1NEZWNpbWF0aW9uVmFsdWUoKTtcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5jcmVhdGVOZXdCdWNrZXQocG9pbnQsIGlucHV0VmFsdWUpO1xuICAgICAgICAgICAgICAgICAgICB0aGlzLmZpbmFsaXplQnVja2V0KHBvaW50KTtcbiAgICAgICAgICAgICAgICAgICAgcG9pbnQueCA9IHRoaXMuX3hDb29yZFRvVmFsdWUoeENvb3JkIC0gMSk7XG4gICAgICAgICAgICAgICAgICAgIHRoaXMuX2J1Y2tldHMucHVzaChwb2ludCk7XG4gICAgICAgICAgICAgICAgICAgIHRoaXMuX3ByZXZYID0gcG9pbnQueDtcbiAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICBjdXJyZW50UG9pbnQgPSBuZXcgTkVXU0RlY2ltYXRpb25WYWx1ZSgpO1xuICAgICAgICAgICAgICAgIHRoaXMuY3JlYXRlTmV3QnVja2V0KGN1cnJlbnRQb2ludCwgaW5wdXRWYWx1ZSk7XG5cbiAgICAgICAgICAgICAgICBsYXN0WCA9IHhDb29yZDtcbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgdGhpcy5hZGRUb0J1Y2tldChjdXJyZW50UG9pbnQsIGlucHV0VmFsdWUpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgIGlmIChjdXJyZW50UG9pbnQpIHtcbiAgICAgICAgICAgIHRoaXMuZmluYWxpemVCdWNrZXQoY3VycmVudFBvaW50KTtcbiAgICAgICAgICAgIHRoaXMuX2J1Y2tldHMucHVzaChjdXJyZW50UG9pbnQpO1xuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIHRoaXMuX2J1Y2tldHM7XG4gICAgfSAgLy8gZGVjaW1hdGVWYWx1ZXMoKVxufTtcblxuZXhwb3J0IGNsYXNzIEZsYW1lQ2hhcnRSZWN0TGltaXREZWNpbWF0b3IgaW1wbGVtZW50cyBJRmxhbWVDaGFydERlY2ltYXRvciB7XG4gICAgcHVibGljIHN0YXRpYyBLRVkgPSAnRmxhbWVDaGFydFJlY3RMaW1pdERlY2ltYXRvcic7XG4gICAgcHJvdGVjdGVkIF9kYXRhOiBJRmxhbWVDaGFydFZhbHVlW107XG4gICAgcHJvdGVjdGVkIF9yZWN0TGltaXQ6IG51bWJlcjtcblxuICAgIC8qKiB0aGlzIGZ1bmN0aW9uIGlzIHVzZWQgdG8gbWFwIHRoZSBpbnB1dCB4eVZhbHVlcyB0byB4IHNjYWxlZCB2YWx1ZXMqL1xuICAgIHByb3RlY3RlZCBfeFZhbHVlVG9Db29yZDogKHZhbHVlOiBhbnkpID0+IG51bWJlcjtcblxuICAgIC8qKiB0aGlzIGZ1bmN0aW9uIGlzIHVzZWQgdG8gbWFwIHRoZSByZXZlcnQgeHlWYWx1ZXMgZnJvbSB4IHNjYWxlZCB2YWx1ZXMqL1xuICAgIHByb3RlY3RlZCBfeENvb3JkVG9WYWx1ZTogKHZhbHVlOiBhbnkpID0+IG51bWJlcjtcblxuICAgIC8qKiB0aGlzIGZ1bmN0aW9uIGlzIHVzZWQgdG8gbWFwIHRoZSBpbnB1dCB4eVZhbHVlcyB0byB5IHNjYWxlZCB2YWx1ZXMqL1xuICAgIHByb3RlY3RlZCBfeVZhbHVlVG9Db29yZDogKHZhbHVlOiBhbnkpID0+IG51bWJlcjtcblxuICAgIHB1YmxpYyBpbml0aWFsaXplKHhWYWx1ZVRvQ29vcmQ6ICh2YWx1ZTogYW55KSA9PiBudW1iZXIsXG4gICAgICAgIHhDb29yZFRvVmFsdWU6ICh2YWx1ZTogYW55KSA9PiBudW1iZXIsXG4gICAgICAgIHlWYWx1ZVRvQ29vcmQ6ICh2YWx1ZTogYW55KSA9PiBudW1iZXIpIHtcbiAgICAgICAgdGhpcy5fZGF0YSA9IFtdO1xuXG4gICAgICAgIHRoaXMuX3hWYWx1ZVRvQ29vcmQgPSB4VmFsdWVUb0Nvb3JkO1xuICAgICAgICB0aGlzLl94Q29vcmRUb1ZhbHVlID0geENvb3JkVG9WYWx1ZTtcbiAgICAgICAgdGhpcy5feVZhbHVlVG9Db29yZCA9IHlWYWx1ZVRvQ29vcmQ7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogUmV0dXJucyB0aGUga2V5IG9mIHRoaXMgZGVjaW1hdG9yXG4gICAgICovXG4gICAgcHVibGljIGdldEtleSgpOiBzdHJpbmcge1xuICAgICAgICByZXR1cm4gRmxhbWVDaGFydFJlY3RMaW1pdERlY2ltYXRvci5LRVk7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogdGhlIG5hbWUgb2YgdGhpcyBkZWNpbWF0aW9uIHNjaGVtZVxuICAgICAqL1xuICAgIHB1YmxpYyBnZXROYW1lKCk6IHN0cmluZyB7XG4gICAgICAgIHJldHVybiAnJztcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBSZXR1cm5zIHRoZSBkZWNpbWF0ZWQgbGlzdCBvZiBkYXRhXG4gICAgICovXG4gICAgcHVibGljIGdldFZhbHVlcygpOiBJRmxhbWVDaGFydFZhbHVlW10ge1xuICAgICAgICByZXR1cm4gdGhpcy5fZGF0YTtcbiAgICB9XG5cbiAgICBwdWJsaWMgc2V0UmVjdExpbWl0KHJlY3RMaW1pdDogbnVtYmVyKTogSUZsYW1lQ2hhcnREZWNpbWF0b3Ige1xuICAgICAgICB0aGlzLl9yZWN0TGltaXQgPSByZWN0TGltaXQ7XG4gICAgICAgIHJldHVybiB0aGlzO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIFZhbHVlcyB0byBiZSBkZWNpbWF0ZWRcbiAgICAgKlxuICAgICAqIEBwYXJhbSB4U3RhcnQgLSBzdGFydCB0aW1lIG9mIHRoZSByZWdpb25cbiAgICAgKiBAcGFyYW0geEVuZCAtIHN0YXJ0IHRpbWUgb2YgdGhlIHJlZ2lvblxuICAgICAqIEBwYXJhbSB2YWx1ZXMgLSBWYWx1ZXMgdG8gYmUgZGVjaW1hdGVkLlxuICAgICAqL1xuICAgIHB1YmxpYyBkZWNpbWF0ZVZhbHVlcyh4U3RhcnQ6IG51bWJlciwgeEVuZDogbnVtYmVyLCB2YWx1ZXM6IElCdWZmZXI8SUZsYW1lQ2hhcnRWYWx1ZVtdPik6XG4gICAgICAgIElGbGFtZUNoYXJ0VmFsdWVbXSB7XG5cbiAgICAgICAgLy8gdXNpbmcgdGhlIHdob2xlIHZpZXdcbiAgICAgICAgdGhpcy5fZGF0YSA9IFtdO1xuICAgICAgICBsZXQgcmVjdHMgPSB2YWx1ZXMuZ2V0RGF0YSgpO1xuICAgICAgICBmb3IgKGxldCBpID0gMDsgaSA8IHJlY3RzLmxlbmd0aDsgKytpKSB7XG4gICAgICAgICAgICB0aGlzLl9kYXRhID0gdGhpcy5fZGF0YS5jb25jYXQocmVjdHNbaV0pO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKHRoaXMuX3JlY3RMaW1pdCkge1xuICAgICAgICAgICAgdGhpcy5fZGF0YS5zb3J0KGZ1bmN0aW9uIChhOiBJRmxhbWVDaGFydFZhbHVlLCBiOiBJRmxhbWVDaGFydFZhbHVlKTogbnVtYmVyIHtcbiAgICAgICAgICAgICAgICBpZiAoYS50cmFjZVZhbHVlLmR4ID4gYi50cmFjZVZhbHVlLmR4KSB7XG4gICAgICAgICAgICAgICAgICAgIHJldHVybiAtMTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgaWYgKGEudHJhY2VWYWx1ZS5keCA8IGIudHJhY2VWYWx1ZS5keCkge1xuICAgICAgICAgICAgICAgICAgICByZXR1cm4gMTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgcmV0dXJuIDA7XG4gICAgICAgICAgICB9KTtcblxuICAgICAgICAgICAgdGhpcy5fZGF0YSA9IHRoaXMuX2RhdGEuc3BsaWNlKDAsIHRoaXMuX3JlY3RMaW1pdCk7XG4gICAgICAgIH1cblxuICAgICAgICByZXR1cm4gdGhpcy5fZGF0YTtcbiAgICB9XG59O1xuXG4vKiogdGhpcyBkZWNpbWF0b3IgbWVyZ2VzIHRoZSByZWN0YW5nbGVzIGluIGEgZmxhbWUgY2hhcnQgdG8gY29tYmluZVxuICogaWRlbnRpY2FsIHJlY3RhbmdsZXMgdGhhdCBhcmUgdG91Y2hpbmcgb24gYSBsZWZ0L3JpZ2h0IHBpeGVsIGJhc2lzIHNvXG4gKiB3ZSBjYW4gbWVyZ2UgdGhlbSBmb3IgcmVuZGVyaW5nXG4gKi9cbmV4cG9ydCBjbGFzcyBGbGFtZUNoYXJ0TWVyZ2VSZWN0RGVjaW1hdG9yIGltcGxlbWVudHMgSUZsYW1lQ2hhcnREZWNpbWF0b3Ige1xuICAgIHB1YmxpYyBzdGF0aWMgS0VZID0gJ0ZsYW1lQ2hhcnRNZXJnZVJlY3REZWNpbWF0b3InO1xuICAgIHByb3RlY3RlZCBfZGF0YTogSUZsYW1lQ2hhcnRWYWx1ZVtdO1xuICAgIHByb3RlY3RlZCBfcmVjdExpbWl0OiBudW1iZXI7XG4gICAgcHJvdGVjdGVkIF9taW5SZWN0RGVsdGEgPSAxO1xuICAgIHByb3RlY3RlZCBfdXNlclBpeGVsRnVuY3Rpb246IChJRmxhbWVDaGFydFZhbHVlKSA9PiBJRmxhbWVDaGFydFZhbHVlO1xuXG4gICAgLyoqIHRoaXMgZnVuY3Rpb24gaXMgdXNlZCB0byBtYXAgdGhlIGlucHV0IHh5VmFsdWVzIHRvIHggc2NhbGVkIHZhbHVlcyovXG4gICAgcHJvdGVjdGVkIF94VmFsdWVUb0Nvb3JkOiAodmFsdWU6IGFueSkgPT4gbnVtYmVyO1xuXG4gICAgLyoqIHRoaXMgZnVuY3Rpb24gaXMgdXNlZCB0byBtYXAgdGhlIHJldmVydCB4eVZhbHVlcyBmcm9tIHggc2NhbGVkIHZhbHVlcyovXG4gICAgcHJvdGVjdGVkIF94Q29vcmRUb1ZhbHVlOiAodmFsdWU6IGFueSkgPT4gbnVtYmVyO1xuXG4gICAgLyoqIHRoaXMgZnVuY3Rpb24gaXMgdXNlZCB0byBtYXAgdGhlIGlucHV0IHh5VmFsdWVzIHRvIHkgc2NhbGVkIHZhbHVlcyovXG4gICAgcHJvdGVjdGVkIF95VmFsdWVUb0Nvb3JkOiAodmFsdWU6IGFueSkgPT4gbnVtYmVyO1xuXG4gICAgcHVibGljIGluaXRpYWxpemUoeFZhbHVlVG9Db29yZDogKHZhbHVlOiBhbnkpID0+IG51bWJlcixcbiAgICAgICAgeENvb3JkVG9WYWx1ZTogKHZhbHVlOiBhbnkpID0+IG51bWJlcixcbiAgICAgICAgeVZhbHVlVG9Db29yZDogKHZhbHVlOiBhbnkpID0+IG51bWJlcikge1xuICAgICAgICB0aGlzLl9kYXRhID0gW11cbiAgICAgICAgdGhpcy5feFZhbHVlVG9Db29yZCA9IHhWYWx1ZVRvQ29vcmQ7XG4gICAgICAgIHRoaXMuX3hDb29yZFRvVmFsdWUgPSB4Q29vcmRUb1ZhbHVlO1xuICAgICAgICB0aGlzLl95VmFsdWVUb0Nvb3JkID0geVZhbHVlVG9Db29yZDtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBSZXR1cm5zIHRoZSBrZXkgb2YgdGhpcyBkZWNpbWF0b3JcbiAgICAgKi9cbiAgICBwdWJsaWMgZ2V0S2V5KCk6IHN0cmluZyB7XG4gICAgICAgIHJldHVybiBGbGFtZUNoYXJ0TWVyZ2VSZWN0RGVjaW1hdG9yLktFWTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiB0aGUgbmFtZSBvZiB0aGlzIGRlY2ltYXRpb24gc2NoZW1lXG4gICAgICovXG4gICAgcHVibGljIGdldE5hbWUoKTogc3RyaW5nIHtcbiAgICAgICAgcmV0dXJuICcnO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIFJldHVybnMgdGhlIGRlY2ltYXRlZCBsaXN0IG9mIGRhdGFcbiAgICAgKi9cbiAgICBwdWJsaWMgZ2V0VmFsdWVzKCk6IElGbGFtZUNoYXJ0VmFsdWVbXSB7XG4gICAgICAgIHJldHVybiB0aGlzLl9kYXRhO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIFNldCB0aGUgbWluaW11bSB3aWR0aCBvZiBhIHJlY3RhbmdsZS4gIElmIHRoZXJlIGlzIG11bHRpcGxlIHRyYWNlIHBvaW50c1xuICAgICAqIHdpdGhpbiB0aGUgdGhlIG1pbmltdW0gd2lkdGggdGhlbiB0aGUgZGF0YSBpcyBtZXJnZWQgdG9nZXRoZXIgaW50b1xuICAgICAqIGEgc2luZ2xlIHJlY3RhbmdsZS4gIE9uY2UgYWxsIGRhdGEgaW4gYSByZWN0YW5nbGUgaXMgbWVyZ2VkIHRoZW4gd2UgY2FsbFxuICAgICAqIHRoZSBbc2V0VXNlclBpeGVsRnVuY3Rpb25dIGNhbGxiYWNrIHNvIHRoZSB0aGUgdXNlciBjYW4gbW9kaWZ5IHRoZSB2YWx1ZVxuICAgICAqIHRvIGJlIHJlbmRlcmVkIGlmIG5lZWRlZFxuICAgICAqXG4gICAgICogQHBhcmFtIHdpZHRoIHRoZSBtaW5pbXVtIHdpZHRoIG9mIGEgcGl4ZWwgaW4gd2hpY2ggZGF0YSBpcyBncm91cGVkIHRvZ2V0aGVyXG4gICAgICovXG4gICAgcHVibGljIHNldFBpeGVsV2lkdGgod2lkdGg6IG51bWJlcik6IEZsYW1lQ2hhcnRNZXJnZVJlY3REZWNpbWF0b3Ige1xuICAgICAgICB0aGlzLl9taW5SZWN0RGVsdGEgPSB3aWR0aCAtIDE7XG4gICAgICAgIHJldHVybiB0aGlzO1xuICAgIH1cblxuICAgIHB1YmxpYyBzZXRVc2VyUGl4ZWxGdW5jdGlvbihjYjogKElGbGFtZUNoYXJ0VmFsdWUpID0+IElGbGFtZUNoYXJ0VmFsdWUpIHtcbiAgICAgICAgdGhpcy5fdXNlclBpeGVsRnVuY3Rpb24gPSBjYjtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiB1c2VkIHRvIGdlbmVyYXRlIGEgbGlzdCBvZiBhbGwgcmVjdHMgdGhhdCBjb3VsZCBiZSBkcmF3biBzb3J0ZWQgYnkgZHVyYXRpb25cbiAgICAgKi9cbiAgICBwcm90ZWN0ZWQgbWVyZ2VSZWN0cyh2YWx1ZXM6IElGbGFtZUNoYXJ0VmFsdWVbXVtdKTogSUZsYW1lQ2hhcnRWYWx1ZVtdIHtcbiAgICAgICAgbGV0IHJldCA9IFtdO1xuXG4gICAgICAgIC8vIGdldCB0aGUgd2lkdGggb2YgYSBwaXhlbFxuICAgICAgICBsZXQgYnVja2V0czogbnVtYmVyID0gTWF0aC5jZWlsKHRoaXMuX3hWYWx1ZVRvQ29vcmQoTnVtYmVyLk1BWF9WQUxVRSkpICsgMTtcblxuICAgICAgICAvLyBOT1RFOiBJIGRvIHRoaXMgdXAgaGVyZSBzbyBJIGNhbiBjaGVhdCBhbmQgdXNlIHRoZSB4IHZhbHVlcyBoZXJlXG4gICAgICAgIC8vIHNvIGxhdGVyIEkgZG9uJ3Qga2VlcCBjYWxsaW5nIHRoaXMuX3hDb29yZFRvVmFsdWVcbiAgICAgICAgbGV0IHhCdWNrZXRWYWx1ZXMgPSBbXTtcbiAgICAgICAgZm9yIChsZXQgYnVja2V0ID0gMDsgYnVja2V0IDw9IGJ1Y2tldHM7ICsrYnVja2V0KSB7XG4gICAgICAgICAgICB4QnVja2V0VmFsdWVzLnB1c2godGhpcy5feENvb3JkVG9WYWx1ZShidWNrZXQpKTtcbiAgICAgICAgfVxuXG4gICAgICAgIC8vIGdldCB0aGUgd2lkdGggb2YgYSBwaXhlbCBzbyB3ZSBjYW4gZm9yY2UgaXQgdG8gYmUgdmlzaWJsZSBieVxuICAgICAgICAvLyBtYWtpbmcgdGhlIHJlY3Qgd2lkdGggdmFsdWUgMSBmdWxsIHBpeGVsIGRlbHRhIHdpZGVcbiAgICAgICAgbGV0IGJ1Y2tldFZhbHVlV2lkdGg6IG51bWJlciA9IDA7XG4gICAgICAgIGlmIChidWNrZXRzID4gMSkge1xuICAgICAgICAgICAgYnVja2V0VmFsdWVXaWR0aCA9IHRoaXMuX3hDb29yZFRvVmFsdWUoMSkgLSB0aGlzLl94Q29vcmRUb1ZhbHVlKDApO1xuICAgICAgICB9XG5cbiAgICAgICAgLy8gY29tcHV0ZSBtZXJnZWQgcmVjdHNcbiAgICAgICAgZm9yIChsZXQgaSA9IDA7IGkgPCB2YWx1ZXMubGVuZ3RoOyArK2kpIHtcbiAgICAgICAgICAgIGxldCBwZXJMZXZlbERhdGEgPSB2YWx1ZXNbaV07XG4gICAgICAgICAgICBpZiAocGVyTGV2ZWxEYXRhID09PSB1bmRlZmluZWQpIHtcbiAgICAgICAgICAgICAgICBjb250aW51ZTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgbGV0IG1lcmdlZExldmVsRGF0YTogSUZsYW1lQ2hhcnRWYWx1ZVtdID0gW107XG5cbiAgICAgICAgICAgIGxldCBwcmV2VmFsdWU6IElGbGFtZUNoYXJ0VmFsdWU7XG4gICAgICAgICAgICBsZXQgbWVyZ2VCdWNrZXRFbmQ6IG51bWJlciA9IC1OdW1iZXIuTUFYX1ZBTFVFO1xuICAgICAgICAgICAgbGV0IHN0YXJ0WENvb3JkOiBudW1iZXI7XG4gICAgICAgICAgICBsZXQgZW5kWENvb3JkOiBudW1iZXI7XG5cbiAgICAgICAgICAgIC8vIGZpcnN0IHdlIHdhbGsgb3ZlciBhbGwgdGhlIGRhdGEgYW5kIGNyZWF0ZSByZWN0cyB3aXRoIGF0IGxlYXN0XG4gICAgICAgICAgICAvLyB0aGUgbWluaW11bSB3aWR0aCB3aGljaCBpcyBzcGVjaWZpZWQgYnkgdGhpcy5fbWluUGl4ZWxXaWR0aFxuICAgICAgICAgICAgbGV0IGxlbiA9IHBlckxldmVsRGF0YS5sZW5ndGg7XG4gICAgICAgICAgICBmb3IgKGxldCBqID0gMDsgaiA8IGxlbjsgaisrKSB7XG4gICAgICAgICAgICAgICAgbGV0IHZhbHVlID0gcGVyTGV2ZWxEYXRhW2pdO1xuXG4gICAgICAgICAgICAgICAgLy8gY2hlY2sgaWYgeW91IG5lZWQgdG8gZG8gYSBzaW1wbGUgbWVyZ2Ugd2l0aCB0aGUgcHJldmlvdXMgaWRlbnRpY2FsIHJlY3RhbmdsZVxuICAgICAgICAgICAgICAgIGlmIChwcmV2VmFsdWUgJiYgcHJldlZhbHVlLnRyYWNlVmFsdWUua2V5ID09PSB2YWx1ZS50cmFjZVZhbHVlLmtleSAmJlxuICAgICAgICAgICAgICAgICAgICBwcmV2VmFsdWUudHJhY2VWYWx1ZS54ICsgcHJldlZhbHVlLnRyYWNlVmFsdWUuZHggPT09IHZhbHVlLnRyYWNlVmFsdWUueCkge1xuICAgICAgICAgICAgICAgICAgICBwcmV2VmFsdWUudHJhY2VWYWx1ZS5keCArPSB2YWx1ZS50cmFjZVZhbHVlLmR4O1xuICAgICAgICAgICAgICAgICAgICBjb250aW51ZTtcbiAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICBzdGFydFhDb29yZCA9IE1hdGguZmxvb3IodGhpcy5feFZhbHVlVG9Db29yZCh2YWx1ZS50cmFjZVZhbHVlLngpKTtcbiAgICAgICAgICAgICAgICAvLyBjaGVjayBpZiB3ZSBhbHJlYWR5IHBhcnRpYWxseSBjb3VudGVkIHRoaXMgc2FtcGxlXG4gICAgICAgICAgICAgICAgaWYgKG1lcmdlQnVja2V0RW5kID4gc3RhcnRYQ29vcmQpIHtcbiAgICAgICAgICAgICAgICAgICAgc3RhcnRYQ29vcmQgPSBtZXJnZUJ1Y2tldEVuZDtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgZW5kWENvb3JkID0gTWF0aC5mbG9vcih0aGlzLl94VmFsdWVUb0Nvb3JkKHZhbHVlLnRyYWNlVmFsdWUueCArIHZhbHVlLnRyYWNlVmFsdWUuZHgpKTtcblxuICAgICAgICAgICAgICAgIGxldCBmY1ZhbHVlOiBJRmxhbWVDaGFydFZhbHVlO1xuICAgICAgICAgICAgICAgIGlmIChlbmRYQ29vcmQgLSBzdGFydFhDb29yZCA+IHRoaXMuX21pblJlY3REZWx0YSkge1xuICAgICAgICAgICAgICAgICAgICAvLyBpZiB0aGlzIHNpbmdsZSB0cmFjZSB2YWx1ZSByZWN0YW5nbGUgaXMgd2lkZSBlbm91Z2ggdG8gYmUgcmVuZGVyZWQgYnkgaXRzZWxmXG4gICAgICAgICAgICAgICAgICAgIGZjVmFsdWUgPSB7XG4gICAgICAgICAgICAgICAgICAgICAgICB0cmFjZVZhbHVlOiB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgeDogeEJ1Y2tldFZhbHVlc1tzdGFydFhDb29yZF0sXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgZHg6IHhCdWNrZXRWYWx1ZXNbZW5kWENvb3JkXSAtIHhCdWNrZXRWYWx1ZXNbc3RhcnRYQ29vcmRdLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGtleTogdmFsdWUudHJhY2VWYWx1ZS5rZXksXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgbmFtZTogdmFsdWUudHJhY2VWYWx1ZS5uYW1lLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRlc2M6IHZhbHVlLnRyYWNlVmFsdWUuZGVzYyxcbiAgICAgICAgICAgICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICAgICAgICAgICAgICBkZWNpbWF0ZWRWYWx1ZXM6IFt2YWx1ZS50cmFjZVZhbHVlXSxcbiAgICAgICAgICAgICAgICAgICAgICAgIGRlcHRoOiB2YWx1ZS5kZXB0aFxuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgLy8gbWlnaHQgaGF2ZSB0byBtZXJnZSB3aXRoIG90aGVyIHJlY3RhbmdsZXNcbiAgICAgICAgICAgICAgICAgICAgbGV0IHN1YnBpeGVsTWFwOiBhbnkgPSB7fTtcbiAgICAgICAgICAgICAgICAgICAgbGV0IHZhbHVlTGlzdDogSVRyYWNlVmFsdWVbXSA9IFtdO1xuXG4gICAgICAgICAgICAgICAgICAgIC8vIHNldCB0aGlzIHNvIHdlIGtub3cgd2hlbiB0byBzdG9wIG1lcmdpbmcgZGF0YSBmb3IgdGhpcyByZWN0YW5nbGVcbiAgICAgICAgICAgICAgICAgICAgbWVyZ2VCdWNrZXRFbmQgPSBzdGFydFhDb29yZCArIHRoaXMuX21pblJlY3REZWx0YTtcblxuICAgICAgICAgICAgICAgICAgICAvLyBhZGQgaW4gdGhlIGluaXRpYWwgd2VpZ2h0XG4gICAgICAgICAgICAgICAgICAgIGlmICh2YWx1ZS50cmFjZVZhbHVlLnggPCB4QnVja2V0VmFsdWVzW3N0YXJ0WENvb3JkXSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgc3VicGl4ZWxNYXBbdmFsdWUudHJhY2VWYWx1ZS5uYW1lXSA9IHZhbHVlLnRyYWNlVmFsdWUueCArIHZhbHVlLnRyYWNlVmFsdWUuZHggLSB4QnVja2V0VmFsdWVzW3N0YXJ0WENvb3JkXTtcbiAgICAgICAgICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHN1YnBpeGVsTWFwW3ZhbHVlLnRyYWNlVmFsdWUubmFtZV0gPSB2YWx1ZS50cmFjZVZhbHVlLmR4O1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgIHZhbHVlTGlzdC5wdXNoKHZhbHVlLnRyYWNlVmFsdWUpO1xuXG4gICAgICAgICAgICAgICAgICAgIC8vIGJlZm9yZSBhZGRpbmcgdGhlIG5leHQgaXRlbSBpdGVyYXRlIHRvIGEgcG9pbnQgd2hlcmUgdGhlIG5leHRcbiAgICAgICAgICAgICAgICAgICAgLy8gdmFsdWUgc3RhcnRzIGluIHRoZSBuZXh0IHBpeGVsIGZvciB0aGUgZ2l2ZW4gZGVwdGhgXG4gICAgICAgICAgICAgICAgICAgIGZvciAoKytqOyBqIDwgbGVuOyArK2opIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHZhbHVlID0gcGVyTGV2ZWxEYXRhW2pdO1xuICAgICAgICAgICAgICAgICAgICAgICAgbGV0IGxvY2FsU3RhcnRYQ29vcmQgPSBNYXRoLmZsb29yKHRoaXMuX3hWYWx1ZVRvQ29vcmQodmFsdWUudHJhY2VWYWx1ZS54KSk7XG5cbiAgICAgICAgICAgICAgICAgICAgICAgIGlmIChsb2NhbFN0YXJ0WENvb3JkID49IG1lcmdlQnVja2V0RW5kKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gYmFjayB1cCB0byB0aGUgbGFzdCBpdGVtIHRoYXQgYnJva2UgdGhlIHN1YnBpeGVsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gaXRlcmF0aW9uIGxvb3Agc28gaXQgY2FuIGJlIGhhbmRsZWQgYnkgdGhlIG91dGVyIGxvb3BcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAtLWo7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICAgICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHZhbHVlTGlzdC5wdXNoKHZhbHVlLnRyYWNlVmFsdWUpO1xuXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gaWYgd2UgaGF2ZSBtdWx0aXBsZSBpdGVtcyBpbiB0aGUgZW5kIHBpeGVsIGFkZCB1cCB0aGVcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyB0aGUgZHVyYXRpb25zIGFuZCBmaW5kIHRoZSBvbmUgd2l0aCB0aGUgbW9zdCB3ZWlnaHRcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZiAoIXN1YnBpeGVsTWFwLmhhc093blByb3BlcnR5KHZhbHVlLnRyYWNlVmFsdWUubmFtZSkpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc3VicGl4ZWxNYXBbdmFsdWUudHJhY2VWYWx1ZS5uYW1lXSA9IDA7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmICh2YWx1ZS50cmFjZVZhbHVlLnggKyB2YWx1ZS50cmFjZVZhbHVlLmR4ID4geEJ1Y2tldFZhbHVlc1ttZXJnZUJ1Y2tldEVuZF0pIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc3VicGl4ZWxNYXBbdmFsdWUudHJhY2VWYWx1ZS5uYW1lXSArPSB4QnVja2V0VmFsdWVzW21lcmdlQnVja2V0RW5kXSAtIHZhbHVlLnRyYWNlVmFsdWUueDtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gYmFjayB1cCB0byB0aGUgbGFzdCBpdGVtIHRoYXQgYnJva2UgdGhlIHN1YnBpeGVsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIGl0ZXJhdGlvbiBsb29wIHNvIGl0IGNhbiBiZSBoYW5kbGVkIGJ5IHRoZSBvdXRlciBsb29wXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC0tajtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc3VicGl4ZWxNYXBbdmFsdWUudHJhY2VWYWx1ZS5uYW1lXSArPSB2YWx1ZS50cmFjZVZhbHVlLmR4O1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgICAgIGxldCBsYXN0VHJhY2VWYWx1ZTogSVRyYWNlVmFsdWUgPSB2YWx1ZUxpc3RbdmFsdWVMaXN0Lmxlbmd0aCAtIDFdO1xuICAgICAgICAgICAgICAgICAgICBpZiAodmFsdWVMaXN0Lmxlbmd0aCA9PT0gMSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgLy8gaWYgd2UgaGF2ZSBqdXN0IG9uZSBpdGVtIGp1c3QgYWRkIGl0IHRvIHRoZSB0cmFjZVxuICAgICAgICAgICAgICAgICAgICAgICAgZmNWYWx1ZSA9IHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB0cmFjZVZhbHVlOiB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHg6IHhCdWNrZXRWYWx1ZXNbc3RhcnRYQ29vcmRdLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkeDogeEJ1Y2tldFZhbHVlc1tlbmRYQ29vcmRdIC0geEJ1Y2tldFZhbHVlc1tzdGFydFhDb29yZF0sXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGtleTogbGFzdFRyYWNlVmFsdWUua2V5LFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBuYW1lOiBsYXN0VHJhY2VWYWx1ZS5uYW1lLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkZXNjOiBsYXN0VHJhY2VWYWx1ZS5kZXNjLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgZGVjaW1hdGVkVmFsdWVzOiB2YWx1ZUxpc3QsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgZGVwdGg6IHZhbHVlLmRlcHRoXG4gICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAvLyBmaW5kIHRoZSBzdWJwaXhlbCB2YWx1ZSB3aXRoIHRoZSBtb3N0IHdlaWdodFxuICAgICAgICAgICAgICAgICAgICAgICAgbGV0IHBpeGVsTmFtZTogc3RyaW5nO1xuICAgICAgICAgICAgICAgICAgICAgICAgbGV0IG1heCA9IDA7XG4gICAgICAgICAgICAgICAgICAgICAgICBmb3IgKGxldCBuYW1lIGluIHN1YnBpeGVsTWFwKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgbGV0IGdyb3VwV2VpZ2h0ID0gc3VicGl4ZWxNYXBbbmFtZV07XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgaWYgKGdyb3VwV2VpZ2h0ID4gbWF4KSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBpeGVsTmFtZSA9IG5hbWU7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1heCA9IGdyb3VwV2VpZ2h0O1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgICAgICAgICAgZmNWYWx1ZSA9IHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB0cmFjZVZhbHVlOiB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHg6IHhCdWNrZXRWYWx1ZXNbc3RhcnRYQ29vcmRdLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkeDogbWVyZ2VCdWNrZXRFbmQgPCB4QnVja2V0VmFsdWVzLmxlbmd0aCA/IHhCdWNrZXRWYWx1ZXNbbWVyZ2VCdWNrZXRFbmRdIC0geEJ1Y2tldFZhbHVlc1tzdGFydFhDb29yZF0gOlxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeEJ1Y2tldFZhbHVlc1tzdGFydFhDb29yZF0gKyBidWNrZXRWYWx1ZVdpZHRoLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBrZXk6ICdtZXJnZWQnLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBuYW1lOiBwaXhlbE5hbWUsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRlc2M6IGxhc3RUcmFjZVZhbHVlLmRlc2MsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBkZWNpbWF0ZWRWYWx1ZXM6IHZhbHVlTGlzdCxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBkZXB0aDogdmFsdWUuZGVwdGhcbiAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgIG1lcmdlZExldmVsRGF0YS5wdXNoKGZjVmFsdWUpO1xuXG4gICAgICAgICAgICAgICAgLy8gdXBkYXRlIHRoZSBsYXN0IHZhbHVlIGZvciB0aGlzIGxldmVsXG4gICAgICAgICAgICAgICAgcHJldlZhbHVlID0gZmNWYWx1ZTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgLy8gbm93IHRoYXQgd2UgaGF2ZSBjb21wdXRlZCByZWN0cyBhbmQgdGhlaXIgdGhlIHN1YnBpeGVsIHZhbHVlc1xuICAgICAgICAgICAgLy8gaWYgYXBwbGljYWJsZSB3ZSBhY3R1YWxseSBnbyB0aHJvdWdoIGFuZCBjbGVhbiB0aGluZ3MgdXAgYW5kIHRoZW5cbiAgICAgICAgICAgIC8vIG1lcmdlIHRoZSByZWN0cyBmb3IgcmVuZGVyaW5nIHBlcmZvcm1hbmNlXG4gICAgICAgICAgICBwcmV2VmFsdWUgPSB1bmRlZmluZWQ7XG5cbiAgICAgICAgICAgIGxldCBsYXN0VHMgPSAwO1xuICAgICAgICAgICAgbGV0IGlzTmV3VmFsdWUgPSB0cnVlO1xuICAgICAgICAgICAgZm9yIChsZXQgaiA9IDA7IGogPCBtZXJnZWRMZXZlbERhdGEubGVuZ3RoOyArK2opIHtcbiAgICAgICAgICAgICAgICBpc05ld1ZhbHVlID0gdHJ1ZTtcbiAgICAgICAgICAgICAgICBsZXQgdmFsdWU6IElGbGFtZUNoYXJ0VmFsdWUgPSBtZXJnZWRMZXZlbERhdGFbal07XG4gICAgICAgICAgICAgICAgaWYgKHZhbHVlLnRyYWNlVmFsdWUuZHggPCBidWNrZXRWYWx1ZVdpZHRoKSB7XG4gICAgICAgICAgICAgICAgICAgIC8vIGZpcnN0IG1ha2UgdGhlIHJlY3RhbmdsZXMgYXQgbGVhc3QgMSBwaXhlbCB3aWRlXG4gICAgICAgICAgICAgICAgICAgIHZhbHVlLnRyYWNlVmFsdWUuZHggPSBidWNrZXRWYWx1ZVdpZHRoO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICBpZiAodGhpcy5fdXNlclBpeGVsRnVuY3Rpb24pIHtcbiAgICAgICAgICAgICAgICAgICAgLy8gbGV0IHRoZSB1c2VyIGNsZWFuIHVwIHRoZSBmbGFtZSBjaGFydCB2YWx1ZSBpZiB0aGV5IHdhbnRcbiAgICAgICAgICAgICAgICAgICAgdmFsdWUgPSB0aGlzLl91c2VyUGl4ZWxGdW5jdGlvbih2YWx1ZSk7XG4gICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgLy8gbm93IGFjdHVhbGx5IG1lcmdlIHRoZSByZWN0c1xuICAgICAgICAgICAgICAgIGlmIChwcmV2VmFsdWUgJiYgcHJldlZhbHVlLnRyYWNlVmFsdWUua2V5ID09PSB2YWx1ZS50cmFjZVZhbHVlLmtleSAmJlxuICAgICAgICAgICAgICAgICAgICBwcmV2VmFsdWUudHJhY2VWYWx1ZS5uYW1lID09PSB2YWx1ZS50cmFjZVZhbHVlLm5hbWUpIHtcblxuICAgICAgICAgICAgICAgICAgICBsYXN0VHMgPSBwcmV2VmFsdWUudHJhY2VWYWx1ZS54ICsgcHJldlZhbHVlLnRyYWNlVmFsdWUuZHg7XG5cbiAgICAgICAgICAgICAgICAgICAgaWYgKGxhc3RUcyA+PSB2YWx1ZS50cmFjZVZhbHVlLngpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHByZXZWYWx1ZS50cmFjZVZhbHVlLmR4ID0gdmFsdWUudHJhY2VWYWx1ZS54ICsgdmFsdWUudHJhY2VWYWx1ZS5keCAtIHByZXZWYWx1ZS50cmFjZVZhbHVlLng7XG4gICAgICAgICAgICAgICAgICAgICAgICBwcmV2VmFsdWUuZGVjaW1hdGVkVmFsdWVzLmNvbmNhdCh2YWx1ZS5kZWNpbWF0ZWRWYWx1ZXMpO1xuICAgICAgICAgICAgICAgICAgICAgICAgaXNOZXdWYWx1ZSA9IGZhbHNlO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIGlmIChpc05ld1ZhbHVlKSB7XG4gICAgICAgICAgICAgICAgICAgIHJldC5wdXNoKHZhbHVlKTtcbiAgICAgICAgICAgICAgICAgICAgcHJldlZhbHVlID0gdmFsdWU7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgIHJldHVybiByZXQ7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogVmFsdWVzIHRvIGJlIGRlY2ltYXRlZFxuICAgICAqXG4gICAgICogQHBhcmFtIHhTdGFydCAtIHN0YXJ0IHRpbWUgb2YgdGhlIHJlZ2lvblxuICAgICAqIEBwYXJhbSB4RW5kIC0gc3RhcnQgdGltZSBvZiB0aGUgcmVnaW9uXG4gICAgICogQHBhcmFtIHZhbHVlcyAtIFZhbHVlcyB0byBiZSBkZWNpbWF0ZWQuXG4gICAgICovXG4gICAgcHVibGljIGRlY2ltYXRlVmFsdWVzKHhTdGFydDogbnVtYmVyLCB4RW5kOiBudW1iZXIsIHZhbHVlczogSUJ1ZmZlcjxJRmxhbWVDaGFydFZhbHVlW10+KTpcbiAgICAgICAgSUZsYW1lQ2hhcnRWYWx1ZVtdIHtcblxuICAgICAgICAvLyB1c2luZyB0aGUgd2hvbGUgdmlld1xuICAgICAgICB0aGlzLl9kYXRhID0gdGhpcy5tZXJnZVJlY3RzKHZhbHVlcy5nZXREYXRhKCkpO1xuICAgICAgICByZXR1cm4gdGhpcy5fZGF0YTtcbiAgICB9XG59O1xuXG4vKipcbiAqIFRha2VzIElUcmFjZVZhbHVlIGRhdGEgYW5kIGZvciBlYWNoIGJ1Y2tldCByZXR1cm5zIGEgcmVzaWRlbmN5IHZhbHVlXG4gKiBieSBJVHJhY2V2YWx1ZS5uYW1lLiBUaGlzIG1lYW5zIHRoZSBzdW0gb2YgYWxsIHZhbHVlcyB3aXRoaW4gYW4gb3V0cHV0IGJ1Y2tldCBpcyAxMDAuXG4gKi9cbmV4cG9ydCBjbGFzcyBUcmFjZVJlc2lkZW5jeURlY2ltYXRvciBpbXBsZW1lbnRzIElUcmFjZVJlc2lkZW5jeURlY2ltYXRvciB7XG4gICAgcHVibGljIHN0YXRpYyBLRVkgPSAnVHJhY2VSZXNpZGVuY3lEZWNpbWF0b3InO1xuICAgIHByb3RlY3RlZCBfZGVjaW1hdGVkVmFsdWVzOiBJWFlWYWx1ZVtdW107XG4gICAgcHJvdGVjdGVkIF9zdGF0ZXM6IHN0cmluZ1tdO1xuXG4gICAgLyoqIHRoaXMgZnVuY3Rpb24gaXMgdXNlZCB0byBtYXAgdGhlIGlucHV0IHh5VmFsdWVzIHRvIHggc2NhbGVkIHZhbHVlcyovXG4gICAgcHJvdGVjdGVkIF94VmFsdWVUb0Nvb3JkOiAodmFsdWU6IGFueSkgPT4gbnVtYmVyO1xuXG4gICAgLyoqIHRoaXMgZnVuY3Rpb24gaXMgdXNlZCB0byBtYXAgdGhlIHJldmVydCB4eVZhbHVlcyBmcm9tIHggc2NhbGVkIHZhbHVlcyovXG4gICAgcHJvdGVjdGVkIF94Q29vcmRUb1ZhbHVlOiAodmFsdWU6IGFueSkgPT4gbnVtYmVyO1xuXG4gICAgLyoqIHRoaXMgZnVuY3Rpb24gaXMgdXNlZCB0byBtYXAgdGhlIGlucHV0IHh5VmFsdWVzIHRvIHkgc2NhbGVkIHZhbHVlcyovXG4gICAgcHJvdGVjdGVkIF95VmFsdWVUb0Nvb3JkOiAodmFsdWU6IGFueSkgPT4gbnVtYmVyO1xuXG4gICAgcHVibGljIGluaXRpYWxpemUoeFZhbHVlVG9Db29yZDogKHZhbHVlOiBhbnkpID0+IG51bWJlcixcbiAgICAgICAgeENvb3JkVG9WYWx1ZTogKHZhbHVlOiBhbnkpID0+IG51bWJlcixcbiAgICAgICAgeVZhbHVlVG9Db29yZDogKHZhbHVlOiBhbnkpID0+IG51bWJlcixcbiAgICAgICAgc3RhdGVzOiBzdHJpbmdbXSkge1xuICAgICAgICB0aGlzLl9kZWNpbWF0ZWRWYWx1ZXMgPSBbXVxuICAgICAgICB0aGlzLl94VmFsdWVUb0Nvb3JkID0geFZhbHVlVG9Db29yZDtcbiAgICAgICAgdGhpcy5feENvb3JkVG9WYWx1ZSA9IHhDb29yZFRvVmFsdWU7XG4gICAgICAgIHRoaXMuX3lWYWx1ZVRvQ29vcmQgPSB5VmFsdWVUb0Nvb3JkO1xuICAgICAgICB0aGlzLl9zdGF0ZXMgPSBzdGF0ZXM7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogUmV0dXJucyB0aGUga2V5IG9mIHRoaXMgZGVjaW1hdG9yXG4gICAgICovXG4gICAgcHVibGljIGdldEtleSgpOiBzdHJpbmcge1xuICAgICAgICByZXR1cm4gVHJhY2VSZXNpZGVuY3lEZWNpbWF0b3IuS0VZO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIHRoZSBuYW1lIG9mIHRoaXMgZGVjaW1hdGlvbiBzY2hlbWVcbiAgICAgKi9cbiAgICBwdWJsaWMgZ2V0TmFtZSgpOiBzdHJpbmcge1xuICAgICAgICByZXR1cm4gJyc7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogUmV0dXJucyB0aGUgZGVjaW1hdGVkIGxpc3Qgb2YgZGF0YVxuICAgICAqL1xuICAgIHB1YmxpYyBnZXRWYWx1ZXMoKTogSVhZVmFsdWVbXVtdIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuX2RlY2ltYXRlZFZhbHVlcztcbiAgICB9XG5cbiAgICAvKipcbiAgICogVmFsdWVzIHRvIGJlIGRlY2ltYXRlZFxuICAgKlxuICAgKiBAcGFyYW0geFN0YXJ0IC0gc3RhcnQgdGltZSBvZiB0aGUgcmVnaW9uXG4gICAqIEBwYXJhbSB4RW5kIC0gc3RhcnQgdGltZSBvZiB0aGUgcmVnaW9uXG4gICAqIEBwYXJhbSB2YWx1ZXMgLSBWYWx1ZXMgdG8gYmUgZGVjaW1hdGVkLlxuICAgKi9cbiAgICBwdWJsaWMgZGVjaW1hdGVWYWx1ZXMoeFN0YXJ0OiBudW1iZXIsIHhFbmQ6IG51bWJlciwgdmFsdWVzOiBJQnVmZmVyPElUcmFjZVZhbHVlPik6IElYWVZhbHVlW11bXSB7XG4gICAgICAgIHRoaXMuX2RlY2ltYXRlZFZhbHVlcyA9IG5ldyBBcnJheSh0aGlzLl9zdGF0ZXMubGVuZ3RoKS5maWxsKDApLm1hcCgoKSA9PiBuZXcgQXJyYXkoKSk7XG5cbiAgICAgICAgbGV0IGdsb2JhbFN0YXJ0QnVja2V0ID0gMDtcbiAgICAgICAgbGV0IGdsb2JhbEVuZEJ1Y2tldCA9IE1hdGguY2VpbCh0aGlzLl94VmFsdWVUb0Nvb3JkKE51bWJlci5NQVhfVkFMVUUpKTtcblxuICAgICAgICBpZiAoZ2xvYmFsRW5kQnVja2V0IDwgZ2xvYmFsU3RhcnRCdWNrZXQpIHtcbiAgICAgICAgICAgIHJldHVybiB1bmRlZmluZWQ7XG4gICAgICAgIH1cblxuICAgICAgICAvLyB0aGlzIGlzIHRvdGFsIHdlaWdodGVkIHN1bSBmb3IgZWFjaCBzdGF0ZSBwZXIgeCwgdGhlbiB1c2VkIHRvIHN0b3JlIHBlcmNlbnRhZ2UgcGVyIHhcbiAgICAgICAgbGV0IHRlbXBWYWx1ZXM6IHsgW2luZGV4OiBzdHJpbmddOiBudW1iZXJbXSB9ID0ge307XG5cbiAgICAgICAgLy8gbWFwIHN0YXRlcyB0byByZXR1cm4gaW5kZXhcbiAgICAgICAgbGV0IHN0YXRlTWFwOiB7IFtpbmRleDogc3RyaW5nXTogbnVtYmVyIH0gPSB7fTtcbiAgICAgICAgdGhpcy5fc3RhdGVzLmZvckVhY2goKHN0YXRlLCBpbmRleCkgPT4ge1xuICAgICAgICAgICAgc3RhdGVNYXBbc3RhdGVdID0gaW5kZXg7XG4gICAgICAgICAgICB0ZW1wVmFsdWVzW3N0YXRlXSA9IEFycmF5LmFwcGx5KG51bGwsIEFycmF5KGdsb2JhbEVuZEJ1Y2tldCkpLlxuICAgICAgICAgICAgICAgIG1hcChOdW1iZXIucHJvdG90eXBlLnZhbHVlT2YsIDApO1xuICAgICAgICB9KVxuXG4gICAgICAgIC8vIHNldCB1cCB0aGUgdmFsdWVzIGZvciBpdGVyYXRpb25cbiAgICAgICAgLy8gZm9yIGEgc2VyaWVzIGdldCB0aGUgd2VpZ2h0ZWQgc3VtIGZvciB0aGUgbnVtYmVyIG9mIGJ1Y2tldHMgeFN0YXJ0IHRvIHhFbmRcbiAgICAgICAgbGV0IHZhbHVlOiBJVHJhY2VWYWx1ZTtcbiAgICAgICAgbGV0IHRyYWNlRW5kWDogbnVtYmVyO1xuICAgICAgICBsZXQgc3RhcnQgPSBmaW5kRmlyc3RJbnNlcnRpb25JZHgodmFsdWVzLCB4U3RhcnQpO1xuICAgICAgICBsZXQgZW5kID0gZmluZExhc3RJbnNlcnRpb25JZHgodmFsdWVzLCB4RW5kKTtcblxuICAgICAgICBpZiAoc3RhcnQgPiAwKSB7XG4gICAgICAgICAgICAtLXN0YXJ0O1xuICAgICAgICB9XG5cbiAgICAgICAgLy8gTk9URTogSSBkbyB0aGlzIHVwIGhlcmUgc28gSSBjYW4gY2hlYXQgYW5kIHVzZSB0aGUgeCB2YWx1ZXMgaGVyZVxuICAgICAgICAvLyBzbyBsYXRlciBJIGRvbid0IGtlZXAgY2FsbGluZyB0aGlzLl94Q29vcmRUb1ZhbHVlXG4gICAgICAgIGxldCB4QnVja2V0VmFsdWVzID0gW107XG4gICAgICAgIGZvciAobGV0IGJ1Y2tldCA9IDA7IGJ1Y2tldCA8PSBnbG9iYWxFbmRCdWNrZXQ7ICsrYnVja2V0KSB7XG4gICAgICAgICAgICB4QnVja2V0VmFsdWVzLnB1c2godGhpcy5feENvb3JkVG9WYWx1ZShidWNrZXQpKTtcbiAgICAgICAgfVxuXG4gICAgICAgIC8vIHRoaXMgaXMgdGhlIGFtb3VudCBvZiB4IHZhbHVlcyB3aXRoaW4gYSBnaXZlbiBidWNrZXRcbiAgICAgICAgbGV0IGJ1Y2tldFNjYWxhciA9IDEgLyAoeEJ1Y2tldFZhbHVlc1tnbG9iYWxTdGFydEJ1Y2tldCArIDFdIC0geEJ1Y2tldFZhbHVlc1tnbG9iYWxTdGFydEJ1Y2tldF0pO1xuXG4gICAgICAgIC8vIGdldCB3ZWlnaHRlZCBzdW0gb2YgdGhlIHZhbHVlcyBmb3IgZWFjaCBidWNrZXRcbiAgICAgICAgLy8gbm90ZSB0aGlzIGlzIGZvcndhcmQgbG9va2luZyBkYXRhIHVubGlrZSBtb3N0IG9mIG91ciBkYXRhIHNvXG4gICAgICAgIC8vIHRoZSBhbGdvcml0aG0gaXMgYSBsaXR0bGUgZGlmZmVyZW50XG4gICAgICAgIGZvciAobGV0IHJhd0RhdGFJZHggPSBzdGFydDsgcmF3RGF0YUlkeCA8IGVuZDsgKytyYXdEYXRhSWR4KSB7XG4gICAgICAgICAgICB2YWx1ZSA9IHZhbHVlcy5nZXQocmF3RGF0YUlkeCk7XG4gICAgICAgICAgICB0cmFjZUVuZFggPSB2YWx1ZS54ICsgdmFsdWUuZHg7XG5cbiAgICAgICAgICAgIGxldCBzdGFydEJ1Y2tldCA9IE1hdGguZmxvb3IodGhpcy5feFZhbHVlVG9Db29yZCh2YWx1ZS54KSk7XG4gICAgICAgICAgICBsZXQgZW5kQnVja2V0ID0gTWF0aC5mbG9vcih0aGlzLl94VmFsdWVUb0Nvb3JkKHRyYWNlRW5kWCkpO1xuXG4gICAgICAgICAgICBpZiAoc3RhcnRCdWNrZXQgPT09IGVuZEJ1Y2tldCkge1xuICAgICAgICAgICAgICAgIHRlbXBWYWx1ZXNbdmFsdWUubmFtZV1bc3RhcnRCdWNrZXRdICs9IHZhbHVlLmR4ICogYnVja2V0U2NhbGFyO1xuICAgICAgICAgICAgICAgIC8vIFRPRE8gY29uc2lkZXIgd2Ugc2hvdWxkL2NhbiBmaXggdGhpcyBjb3JuZXIgY2FzZVxuXG4gICAgICAgICAgICAgICAgLy8gQ29kZSBiZWxvdyBpcyB0ZWNobmljYWxseSBtb3JlIGNvcnJlY3QgYXMgaXQgaGFuZGxlcyBzb21lIGVkZ2UgY2FzZXNcbiAgICAgICAgICAgICAgICAvLyBidXQgaXQncyBhYm91dCAzeCBzbG93ZXI/XG4gICAgICAgICAgICAgICAgLy8gaWYgKHhTdGFydCA9PT0gdW5kZWZpbmVkIHx8ICh2YWx1ZS54ID4geFN0YXJ0ICYmIHRyYWNlRW5kWCA8IHhFbmQpKSB7XG4gICAgICAgICAgICAgICAgLy8gICAgIC8vIGhlcmUgaXQncyBhbGwgaW4gdGhlIGV4aXN0aW5nIGJ1Y2tldFxuICAgICAgICAgICAgICAgIC8vICAgICB0ZW1wVmFsdWVzW3ZhbHVlLm5hbWVdW3N0YXJ0QnVja2V0XSArPSB2YWx1ZS5keCAqIGJ1Y2tldFNjYWxhcjtcbiAgICAgICAgICAgICAgICAvLyB9IGVsc2UgaWYgKHRyYWNlRW5kWCA+IHhTdGFydCkge1xuICAgICAgICAgICAgICAgIC8vICAgICBpZiAodHJhY2VFbmRYIDwgeEVuZCkge1xuICAgICAgICAgICAgICAgIC8vICAgICAgICAgLy8gaGVyZSB0aGUgYmFjayBoYWxmIGlzIGluIHRoZSBidWNrZXRcbiAgICAgICAgICAgICAgICAvLyAgICAgICAgIHRlbXBWYWx1ZXNbdmFsdWUubmFtZV1bc3RhcnRCdWNrZXRdICs9ICh0cmFjZUVuZFggLSB4U3RhcnQpICogYnVja2V0U2NhbGFyO1xuICAgICAgICAgICAgICAgIC8vICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgIC8vICAgICAgICAgLy8gaGVyZSB0aGUgZnJvbnQgaGFsZiBpcyBpbiB0aGUgYnVja2V0XG4gICAgICAgICAgICAgICAgLy8gICAgICAgICB0ZW1wVmFsdWVzW3ZhbHVlLm5hbWVdW3N0YXJ0QnVja2V0XSArPSAoeEVuZCAtIHZhbHVlLngpICogYnVja2V0U2NhbGFyO1xuICAgICAgICAgICAgICAgIC8vICAgICB9XG4gICAgICAgICAgICAgICAgLy8gfVxuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICAvLyBhZGQgaW4gc3RhcnQgYnVja2V0IGFtb3VudFxuICAgICAgICAgICAgICAgIGxldCBzdGFydFggPSB4U3RhcnQgPyBNYXRoLm1heCh4U3RhcnQsIHZhbHVlLngpIDogdmFsdWUueDtcbiAgICAgICAgICAgICAgICBsZXQgZW5kU3RhcnRCdWNrZXQgPSB4QnVja2V0VmFsdWVzW3N0YXJ0QnVja2V0ICsgMV07XG4gICAgICAgICAgICAgICAgdGVtcFZhbHVlc1t2YWx1ZS5uYW1lXVtzdGFydEJ1Y2tldF0gKz0gKGVuZFN0YXJ0QnVja2V0IC0gc3RhcnRYKSAqIGJ1Y2tldFNjYWxhcjtcblxuICAgICAgICAgICAgICAgIC8vIGFkZCBpbiBhbGwgdGhlIGJ1Y2tldCB2YWx1ZXMgaW4gYmV0d2VlblxuICAgICAgICAgICAgICAgIGZvciAobGV0IGN1cnJCdWNrZXQgPSBzdGFydEJ1Y2tldCArIDE7IGN1cnJCdWNrZXQgPCBlbmRCdWNrZXQ7ICsrY3VyckJ1Y2tldCkge1xuICAgICAgICAgICAgICAgICAgICB0ZW1wVmFsdWVzW3ZhbHVlLm5hbWVdW2N1cnJCdWNrZXRdICs9IDE7XG4gICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgLy8gYWRkIGluIGVuZCBidWNrZXQgYW1vdW50XG4gICAgICAgICAgICAgICAgbGV0IGVuZFggPSB4RW5kID8gTWF0aC5taW4oeEVuZCwgdHJhY2VFbmRYKSA6IHRyYWNlRW5kWDtcbiAgICAgICAgICAgICAgICBsZXQgc3RhcnRFbmRCdWNrZXQgPSB4QnVja2V0VmFsdWVzW2VuZEJ1Y2tldF07XG4gICAgICAgICAgICAgICAgdGVtcFZhbHVlc1t2YWx1ZS5uYW1lXVtlbmRCdWNrZXRdICs9IChlbmRYIC0gc3RhcnRFbmRCdWNrZXQpICogYnVja2V0U2NhbGFyO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG5cbiAgICAgICAgLy8gY3JlYXRlIGFuIGFycmF5IHRoYXQgaXMgdXNlZCB3aGVuIHRoaXMgc3RhdGUgd2Fzbid0IHNlZW4gYXRcbiAgICAgICAgLy8gYWxsIGluIHRoZSB0aW1lIHJlZ2lvbi5cbiAgICAgICAgbGV0IGVtcHR5QXJyYXkgPSBbXTtcbiAgICAgICAgZm9yIChsZXQgYnVja2V0ID0gMDsgYnVja2V0IDwgZ2xvYmFsRW5kQnVja2V0OyArK2J1Y2tldCkge1xuICAgICAgICAgICAgZW1wdHlBcnJheVtidWNrZXRdID0ge1xuICAgICAgICAgICAgICAgIHg6IHhCdWNrZXRWYWx1ZXNbYnVja2V0XSxcbiAgICAgICAgICAgICAgICB5OiAwXG4gICAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICBmb3IgKGxldCBzdGF0ZUlkeCA9IDA7IHN0YXRlSWR4IDwgdGhpcy5fc3RhdGVzLmxlbmd0aDsgKytzdGF0ZUlkeCkge1xuICAgICAgICAgICAgbGV0IGJ1Y2tldHMgPSB0ZW1wVmFsdWVzW3RoaXMuX3N0YXRlc1tzdGF0ZUlkeF1dO1xuICAgICAgICAgICAgaWYgKGJ1Y2tldHMpIHtcbiAgICAgICAgICAgICAgICBmb3IgKGxldCBidWNrZXQgPSAwOyBidWNrZXQgPCBidWNrZXRzLmxlbmd0aDsgKytidWNrZXQpIHtcbiAgICAgICAgICAgICAgICAgICAgbGV0IHkgPSB0ZW1wVmFsdWVzW3RoaXMuX3N0YXRlc1tzdGF0ZUlkeF1dW2J1Y2tldF0gP1xuICAgICAgICAgICAgICAgICAgICAgICAgdGVtcFZhbHVlc1t0aGlzLl9zdGF0ZXNbc3RhdGVJZHhdXVtidWNrZXRdIDogMDtcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5fZGVjaW1hdGVkVmFsdWVzW3N0YXRlSWR4XVtidWNrZXRdID0ge1xuICAgICAgICAgICAgICAgICAgICAgICAgeDogeEJ1Y2tldFZhbHVlc1tidWNrZXRdLFxuICAgICAgICAgICAgICAgICAgICAgICAgeTogeSAqIDEwMFxuICAgICAgICAgICAgICAgICAgICB9O1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgdGhpcy5fZGVjaW1hdGVkVmFsdWVzW3N0YXRlSWR4XSA9IGVtcHR5QXJyYXk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICByZXR1cm4gdGhpcy5fZGVjaW1hdGVkVmFsdWVzO1xuICAgIH1cbn07XG5cbi8qKlxuKiBUYWtlcyBJVHJhY2VWYWx1ZSBkYXRhIGFuZCBmb3IgZWFjaCBidWNrZXQgcmV0dXJucyBhIHN1bSBieSBJVHJhY2V2YWx1ZS5uYW1lLlxuKiBUaGlzIG1lYW5zIHRoZSBzdW0gb2YgYWxsIHZhbHVlcyB3aXRoaW4gYW4gb3V0cHV0IGJ1Y2tldCBpcyAxMDAuXG4qL1xuZXhwb3J0IGNsYXNzIFRyYWNlU3RhdGVEZWNpbWF0b3IgaW1wbGVtZW50cyBJVHJhY2VTdGF0ZURlY2ltYXRvciB7XG4gICAgcHVibGljIHN0YXRpYyBLRVkgPSAnVHJhY2VTdGF0ZURlY2ltYXRvcic7XG4gICAgcHJvdGVjdGVkIF9kZWNpbWF0ZWRWYWx1ZXM6IElORVdTRGVjaW1hdGlvblZhbHVlW107XG4gICAgcHJvdGVjdGVkIF9zdGF0ZXM6IHN0cmluZ1tdO1xuXG4gICAgLyoqIHRoaXMgZnVuY3Rpb24gaXMgdXNlZCB0byBtYXAgdGhlIGlucHV0IHh5VmFsdWVzIHRvIHggc2NhbGVkIHZhbHVlcyovXG4gICAgcHJvdGVjdGVkIF94VmFsdWVUb0Nvb3JkOiAodmFsdWU6IGFueSkgPT4gbnVtYmVyO1xuXG4gICAgLyoqIHRoaXMgZnVuY3Rpb24gaXMgdXNlZCB0byBtYXAgdGhlIHJldmVydCB4eVZhbHVlcyBmcm9tIHggc2NhbGVkIHZhbHVlcyovXG4gICAgcHJvdGVjdGVkIF94Q29vcmRUb1ZhbHVlOiAodmFsdWU6IGFueSkgPT4gbnVtYmVyO1xuXG4gICAgLyoqIHRoaXMgZnVuY3Rpb24gaXMgdXNlZCB0byBtYXAgdGhlIGlucHV0IHh5VmFsdWVzIHRvIHkgc2NhbGVkIHZhbHVlcyovXG4gICAgcHJvdGVjdGVkIF95VmFsdWVUb0Nvb3JkOiAodmFsdWU6IGFueSkgPT4gbnVtYmVyO1xuXG4gICAgcHVibGljIGluaXRpYWxpemUoeFZhbHVlVG9Db29yZDogKHZhbHVlOiBhbnkpID0+IG51bWJlcixcbiAgICAgICAgeENvb3JkVG9WYWx1ZTogKHZhbHVlOiBhbnkpID0+IG51bWJlcixcbiAgICAgICAgeVZhbHVlVG9Db29yZDogKHZhbHVlOiBhbnkpID0+IG51bWJlcixcbiAgICAgICAgc3RhdGVzOiBzdHJpbmdbXSkge1xuICAgICAgICB0aGlzLl9kZWNpbWF0ZWRWYWx1ZXMgPSBbXVxuICAgICAgICB0aGlzLl94VmFsdWVUb0Nvb3JkID0geFZhbHVlVG9Db29yZDtcbiAgICAgICAgdGhpcy5feENvb3JkVG9WYWx1ZSA9IHhDb29yZFRvVmFsdWU7XG4gICAgICAgIHRoaXMuX3lWYWx1ZVRvQ29vcmQgPSB5VmFsdWVUb0Nvb3JkO1xuICAgICAgICB0aGlzLl9zdGF0ZXMgPSBzdGF0ZXM7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogUmV0dXJucyB0aGUga2V5IG9mIHRoaXMgZGVjaW1hdG9yXG4gICAgICovXG4gICAgcHVibGljIGdldEtleSgpOiBzdHJpbmcge1xuICAgICAgICByZXR1cm4gVHJhY2VTdGF0ZURlY2ltYXRvci5LRVk7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogdGhlIG5hbWUgb2YgdGhpcyBkZWNpbWF0aW9uIHNjaGVtZVxuICAgICAqL1xuICAgIHB1YmxpYyBnZXROYW1lKCk6IHN0cmluZyB7XG4gICAgICAgIHJldHVybiAnJztcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBSZXR1cm5zIHRoZSBkZWNpbWF0ZWQgbGlzdCBvZiBkYXRhXG4gICAgICovXG4gICAgcHVibGljIGdldFZhbHVlcygpOiBJTkVXU0RlY2ltYXRpb25WYWx1ZVtdIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuX2RlY2ltYXRlZFZhbHVlcztcbiAgICB9XG5cbiAgICAvKipcbiAgICogVmFsdWVzIHRvIGJlIGRlY2ltYXRlZFxuICAgKlxuICAgKiBAcGFyYW0geFN0YXJ0IC0gc3RhcnQgdGltZSBvZiB0aGUgcmVnaW9uXG4gICAqIEBwYXJhbSB4RW5kIC0gc3RhcnQgdGltZSBvZiB0aGUgcmVnaW9uXG4gICAqIEBwYXJhbSB2YWx1ZXMgLSBWYWx1ZXMgdG8gYmUgZGVjaW1hdGVkLlxuICAgKi9cbiAgICBwdWJsaWMgZGVjaW1hdGVWYWx1ZXMoeFN0YXJ0OiBudW1iZXIsIHhFbmQ6IG51bWJlciwgdmFsdWVzOiBJQnVmZmVyPElUcmFjZVZhbHVlPik6IElORVdTRGVjaW1hdGlvblZhbHVlW10ge1xuICAgICAgICBsZXQgZ2xvYmFsU3RhcnRCdWNrZXQgPSAwO1xuICAgICAgICBsZXQgZ2xvYmFsRW5kQnVja2V0ID0gTWF0aC5jZWlsKHRoaXMuX3hWYWx1ZVRvQ29vcmQoTnVtYmVyLk1BWF9WQUxVRSkpO1xuXG4gICAgICAgIGlmIChnbG9iYWxFbmRCdWNrZXQgPCBnbG9iYWxTdGFydEJ1Y2tldCkge1xuICAgICAgICAgICAgcmV0dXJuIHVuZGVmaW5lZDtcbiAgICAgICAgfVxuXG4gICAgICAgIC8vIHNldCB1cCB0aGUgdmFsdWVzIGZvciBpdGVyYXRpb25cbiAgICAgICAgLy8gZm9yIGEgc2VyaWVzIGdldCB0aGUgd2VpZ2h0ZWQgc3VtIGZvciB0aGUgbnVtYmVyIG9mIGJ1Y2tldHMgeFN0YXJ0IHRvIHhFbmRcbiAgICAgICAgbGV0IHZhbHVlOiBJVHJhY2VWYWx1ZTtcbiAgICAgICAgbGV0IHRyYWNlRW5kWDogbnVtYmVyO1xuICAgICAgICBsZXQgc3RhcnQgPSBmaW5kRmlyc3RJbnNlcnRpb25JZHgodmFsdWVzLCB4U3RhcnQpO1xuICAgICAgICBsZXQgZW5kID0gZmluZExhc3RJbnNlcnRpb25JZHgodmFsdWVzLCB4RW5kKTtcblxuICAgICAgICBpZiAoc3RhcnQgPiAwKSB7XG4gICAgICAgICAgICAtLXN0YXJ0O1xuICAgICAgICB9XG5cbiAgICAgICAgLy8gTk9URTogSSBkbyB0aGlzIHVwIGhlcmUgc28gSSBjYW4gY2hlYXQgYW5kIHVzZSB0aGUgeCB2YWx1ZXMgaGVyZVxuICAgICAgICAvLyBzbyBsYXRlciBJIGRvbid0IGtlZXAgY2FsbGluZyB0aGlzLl94Q29vcmRUb1ZhbHVlXG4gICAgICAgIHRoaXMuX2RlY2ltYXRlZFZhbHVlcyA9IFtdO1xuICAgICAgICBmb3IgKGxldCBidWNrZXQgPSAwOyBidWNrZXQgPD0gZ2xvYmFsRW5kQnVja2V0OyArK2J1Y2tldCkge1xuICAgICAgICAgICAgdGhpcy5fZGVjaW1hdGVkVmFsdWVzW2J1Y2tldF0gPSBuZXcgTkVXU0RlY2ltYXRpb25WYWx1ZSh0aGlzLl94Q29vcmRUb1ZhbHVlKGJ1Y2tldCkpO1xuICAgICAgICB9XG5cbiAgICAgICAgbGV0IHN0YXRlczogeyBbaW5kZXg6IHN0cmluZ106IG51bWJlciB9ID0ge307XG4gICAgICAgIHRoaXMuX3N0YXRlcy5mb3JFYWNoKChzdGF0ZSwgaSkgPT4ge1xuICAgICAgICAgICAgc3RhdGVzW3N0YXRlXSA9IGk7XG4gICAgICAgIH0pXG5cbiAgICAgICAgLy8gc3RvcmUgdGhlIGVudHJ5L2V4aXQvbWluL21heCBvZiBlYWNoIGJ1Y2tldFxuICAgICAgICAvLyBtaW4gYW5kIG1heCBhcmUgYmFzZWQgb24gdGhlIHN0YXRlIGluZGV4XG4gICAgICAgIGZvciAobGV0IHJhd0RhdGFJZHggPSBzdGFydDsgcmF3RGF0YUlkeCA8IGVuZDsgKytyYXdEYXRhSWR4KSB7XG4gICAgICAgICAgICB2YWx1ZSA9IHZhbHVlcy5nZXQocmF3RGF0YUlkeCk7XG4gICAgICAgICAgICB0cmFjZUVuZFggPSB2YWx1ZS54ICsgdmFsdWUuZHg7XG5cbiAgICAgICAgICAgIGxldCBzdGFydEJ1Y2tldCA9IE1hdGguZmxvb3IodGhpcy5feFZhbHVlVG9Db29yZCh2YWx1ZS54KSk7XG4gICAgICAgICAgICBsZXQgZW5kQnVja2V0ID0gTWF0aC5mbG9vcih0aGlzLl94VmFsdWVUb0Nvb3JkKHRyYWNlRW5kWCkpO1xuXG4gICAgICAgICAgICBpZiAoIXRoaXMuX2RlY2ltYXRlZFZhbHVlc1tzdGFydEJ1Y2tldF0uZW50cnkpIHtcbiAgICAgICAgICAgICAgICB0aGlzLl9kZWNpbWF0ZWRWYWx1ZXNbc3RhcnRCdWNrZXRdLmVudHJ5ID0gc3RhdGVzW3ZhbHVlLm5hbWVdO1xuICAgICAgICAgICAgICAgIHRoaXMuX2RlY2ltYXRlZFZhbHVlc1tzdGFydEJ1Y2tldF0uZXhpdCA9IHN0YXRlc1t2YWx1ZS5uYW1lXTtcbiAgICAgICAgICAgICAgICB0aGlzLl9kZWNpbWF0ZWRWYWx1ZXNbc3RhcnRCdWNrZXRdLm1pbiA9IHN0YXRlc1t2YWx1ZS5uYW1lXTtcbiAgICAgICAgICAgICAgICB0aGlzLl9kZWNpbWF0ZWRWYWx1ZXNbc3RhcnRCdWNrZXRdLm1heCA9IHN0YXRlc1t2YWx1ZS5uYW1lXTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGlmIChzdGFydEJ1Y2tldCA9PT0gZW5kQnVja2V0KSB7XG4gICAgICAgICAgICAgICAgdGhpcy5fZGVjaW1hdGVkVmFsdWVzW3N0YXJ0QnVja2V0XS5leGl0ID0gc3RhdGVzW3ZhbHVlLm5hbWVdO1xuICAgICAgICAgICAgICAgIHRoaXMuX2RlY2ltYXRlZFZhbHVlc1tzdGFydEJ1Y2tldF0ubWluID1cbiAgICAgICAgICAgICAgICAgICAgTWF0aC5taW4odGhpcy5fZGVjaW1hdGVkVmFsdWVzW3N0YXJ0QnVja2V0XS5taW4sIHN0YXRlc1t2YWx1ZS5uYW1lXSk7XG4gICAgICAgICAgICAgICAgdGhpcy5fZGVjaW1hdGVkVmFsdWVzW3N0YXJ0QnVja2V0XS5tYXggPVxuICAgICAgICAgICAgICAgICAgICBNYXRoLm1heCh0aGlzLl9kZWNpbWF0ZWRWYWx1ZXNbc3RhcnRCdWNrZXRdLm1heCwgc3RhdGVzW3ZhbHVlLm5hbWVdKTtcbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgLy8gc3RhcnQgYnVja2V0IGV4aXRcbiAgICAgICAgICAgICAgICB0aGlzLl9kZWNpbWF0ZWRWYWx1ZXNbc3RhcnRCdWNrZXRdLmV4aXQgPSBzdGF0ZXNbdmFsdWUubmFtZV07XG4gICAgICAgICAgICAgICAgdGhpcy5fZGVjaW1hdGVkVmFsdWVzW3N0YXJ0QnVja2V0XS5taW4gPVxuICAgICAgICAgICAgICAgICAgICBNYXRoLm1pbih0aGlzLl9kZWNpbWF0ZWRWYWx1ZXNbc3RhcnRCdWNrZXRdLm1pbiwgc3RhdGVzW3ZhbHVlLm5hbWVdKTtcbiAgICAgICAgICAgICAgICB0aGlzLl9kZWNpbWF0ZWRWYWx1ZXNbc3RhcnRCdWNrZXRdLm1heCA9XG4gICAgICAgICAgICAgICAgICAgIE1hdGgubWF4KHRoaXMuX2RlY2ltYXRlZFZhbHVlc1tzdGFydEJ1Y2tldF0ubWF4LCBzdGF0ZXNbdmFsdWUubmFtZV0pO1xuXG4gICAgICAgICAgICAgICAgLy8gYWRkIGluIGFsbCB0aGUgYnVja2V0IHZhbHVlcyBpbiBiZXR3ZWVuXG4gICAgICAgICAgICAgICAgZm9yIChsZXQgY3VyckJ1Y2tldCA9IHN0YXJ0QnVja2V0ICsgMTsgY3VyckJ1Y2tldCA8PSBlbmRCdWNrZXQ7ICsrY3VyckJ1Y2tldCkge1xuICAgICAgICAgICAgICAgICAgICB0aGlzLl9kZWNpbWF0ZWRWYWx1ZXNbY3VyckJ1Y2tldF0uZW50cnkgPSBzdGF0ZXNbdmFsdWUubmFtZV07XG4gICAgICAgICAgICAgICAgICAgIHRoaXMuX2RlY2ltYXRlZFZhbHVlc1tjdXJyQnVja2V0XS5leGl0ID0gc3RhdGVzW3ZhbHVlLm5hbWVdO1xuICAgICAgICAgICAgICAgICAgICB0aGlzLl9kZWNpbWF0ZWRWYWx1ZXNbY3VyckJ1Y2tldF0ubWluID0gc3RhdGVzW3ZhbHVlLm5hbWVdO1xuICAgICAgICAgICAgICAgICAgICB0aGlzLl9kZWNpbWF0ZWRWYWx1ZXNbY3VyckJ1Y2tldF0ubWF4ID0gc3RhdGVzW3ZhbHVlLm5hbWVdO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuXG4gICAgICAgIC8vIGNvbnZlcnQgc3RhdGUgaW5kZXggdG8gYWN0dWFsIHN0YXRlIG5hbWVzIGZvciByZW5kZXJpbmdcbiAgICAgICAgZm9yIChsZXQgaSA9IDA7IGkgPCB0aGlzLl9kZWNpbWF0ZWRWYWx1ZXMubGVuZ3RoOyArK2kpIHtcbiAgICAgICAgICAgIGxldCBuZXdzVmFsdWUgPSB0aGlzLl9kZWNpbWF0ZWRWYWx1ZXNbaV07XG4gICAgICAgICAgICBsZXQgZXhpdCA9IG5ld3NWYWx1ZS5leGl0O1xuICAgICAgICAgICAgbmV3c1ZhbHVlLmVudHJ5ID0gdGhpcy5fc3RhdGVzW25ld3NWYWx1ZS5lbnRyeV07XG4gICAgICAgICAgICBuZXdzVmFsdWUuZXhpdCA9IHRoaXMuX3N0YXRlc1tleGl0XTtcbiAgICAgICAgICAgIG5ld3NWYWx1ZS55ID0gdGhpcy5fc3RhdGVzW2V4aXRdO1xuICAgICAgICAgICAgbmV3c1ZhbHVlLm1pbiA9IHRoaXMuX3N0YXRlc1tuZXdzVmFsdWUubWluXTtcbiAgICAgICAgICAgIG5ld3NWYWx1ZS5tYXggPSB0aGlzLl9zdGF0ZXNbbmV3c1ZhbHVlLm1heF07XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIHRoaXMuX2RlY2ltYXRlZFZhbHVlcztcbiAgICB9XG59O1xuXG4vKipcbiAqIEZvciBhIG1hcmtlciBsYXllciBqdXN0IHJlbW92ZXMgbWFya2VycyB0aGF0IGhhdmUgdGhlIHNhbWUgWCB2YWx1ZVxuICovXG5leHBvcnQgY2xhc3MgU2ltcGxlTWFya2VyRGVjaW1hdG9yIGltcGxlbWVudHMgSURlY2ltYXRvciB7XG4gICAgcHVibGljIHN0YXRpYyBLRVkgPSAnU2ltcGxlTWFya2VyRGVjaW1hdG9yJztcbiAgICBwcm90ZWN0ZWQgX2RhdGE6IElUcmFjZVZhbHVlW107XG5cbiAgICAvKiogdGhpcyBmdW5jdGlvbiBpcyB1c2VkIHRvIG1hcCB0aGUgaW5wdXQgeHlWYWx1ZXMgdG8geCBzY2FsZWQgdmFsdWVzKi9cbiAgICBwcm90ZWN0ZWQgX3hWYWx1ZVRvQ29vcmQ6ICh2YWx1ZTogYW55KSA9PiBudW1iZXI7XG5cbiAgICAvKiogdGhpcyBmdW5jdGlvbiBpcyB1c2VkIHRvIG1hcCB0aGUgcmV2ZXJ0IHh5VmFsdWVzIGZyb20geCBzY2FsZWQgdmFsdWVzKi9cbiAgICBwcm90ZWN0ZWQgX3hDb29yZFRvVmFsdWU6ICh2YWx1ZTogYW55KSA9PiBudW1iZXI7XG5cbiAgICAvKiogdGhpcyBmdW5jdGlvbiBpcyB1c2VkIHRvIG1hcCB0aGUgaW5wdXQgeHlWYWx1ZXMgdG8geSBzY2FsZWQgdmFsdWVzKi9cbiAgICBwcm90ZWN0ZWQgX3lWYWx1ZVRvQ29vcmQ6ICh2YWx1ZTogYW55KSA9PiBudW1iZXI7XG5cbiAgICBwdWJsaWMgaW5pdGlhbGl6ZSh4VmFsdWVUb0Nvb3JkOiAodmFsdWU6IGFueSkgPT4gbnVtYmVyLFxuICAgICAgICB4Q29vcmRUb1ZhbHVlOiAodmFsdWU6IGFueSkgPT4gbnVtYmVyLFxuICAgICAgICB5VmFsdWVUb0Nvb3JkOiAodmFsdWU6IGFueSkgPT4gbnVtYmVyKSB7XG4gICAgICAgIHRoaXMuX2RhdGEgPSBbXVxuICAgICAgICB0aGlzLl94VmFsdWVUb0Nvb3JkID0geFZhbHVlVG9Db29yZDtcbiAgICAgICAgdGhpcy5feENvb3JkVG9WYWx1ZSA9IHhDb29yZFRvVmFsdWU7XG4gICAgICAgIHRoaXMuX3lWYWx1ZVRvQ29vcmQgPSB5VmFsdWVUb0Nvb3JkO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIFJldHVybnMgdGhlIGtleSBvZiB0aGlzIGRlY2ltYXRvclxuICAgICAqL1xuICAgIHB1YmxpYyBnZXRLZXkoKTogc3RyaW5nIHtcbiAgICAgICAgcmV0dXJuIFNpbXBsZU1hcmtlckRlY2ltYXRvci5LRVk7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogdGhlIG5hbWUgb2YgdGhpcyBkZWNpbWF0aW9uIHNjaGVtZVxuICAgICAqL1xuICAgIHB1YmxpYyBnZXROYW1lKCk6IHN0cmluZyB7XG4gICAgICAgIHJldHVybiAnJztcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBSZXR1cm5zIHRoZSBkZWNpbWF0ZWQgbGlzdCBvZiBkYXRhXG4gICAgICovXG4gICAgcHVibGljIGdldFZhbHVlcygpOiBJVHJhY2VWYWx1ZVtdIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuX2RhdGE7XG4gICAgfVxuXG4gICAgcHVibGljIG1lcmdlTWFya2Vycyh2YWx1ZXM6IElUcmFjZVZhbHVlW10pOiBJVHJhY2VWYWx1ZVtdIHtcbiAgICAgICAgbGV0IHJldDogSVRyYWNlVmFsdWVbXSA9IFtdO1xuXG4gICAgICAgIGxldCBsYXN0Q29vcmQgPSAtTnVtYmVyLk1BWF9WQUxVRTtcbiAgICAgICAgZm9yIChsZXQgaSA9IDA7IGkgPCB2YWx1ZXMubGVuZ3RoOyArK2kpIHtcbiAgICAgICAgICAgIGxldCB2YWx1ZSA9IHZhbHVlc1tpXTtcbiAgICAgICAgICAgIGxldCBjb29yZCA9IHRoaXMuX3hWYWx1ZVRvQ29vcmQodmFsdWUueCk7XG4gICAgICAgICAgICBpZiAoY29vcmQgIT09IGxhc3RDb29yZCkge1xuICAgICAgICAgICAgICAgIHJldC5wdXNoKHZhbHVlKTtcbiAgICAgICAgICAgICAgICBsYXN0Q29vcmQgPSBjb29yZDtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gcmV0O1xuICAgIH1cbiAgICAvKipcbiAgICAgKiBWYWx1ZXMgdG8gYmUgZGVjaW1hdGVkXG4gICAgICpcbiAgICAgKiBAcGFyYW0geFN0YXJ0IC0gc3RhcnQgdGltZSBvZiB0aGUgcmVnaW9uXG4gICAgICogQHBhcmFtIHhFbmQgLSBzdGFydCB0aW1lIG9mIHRoZSByZWdpb25cbiAgICAgKiBAcGFyYW0gdmFsdWVzIC0gVmFsdWVzIHRvIGJlIGRlY2ltYXRlZC5cbiAgICAgKi9cbiAgICBwdWJsaWMgZGVjaW1hdGVWYWx1ZXMoeFN0YXJ0OiBudW1iZXIsIHhFbmQ6IG51bWJlciwgdmFsdWVzOiBJQnVmZmVyPElUcmFjZVZhbHVlPik6XG4gICAgICAgIElUcmFjZVZhbHVlW10ge1xuXG4gICAgICAgIGxldCBhbGxEYXRhID0gdmFsdWVzLmdldERhdGEoKTtcblxuICAgICAgICAvLyB1c2luZyB0aGUgd2hvbGUgdmlld1xuICAgICAgICBpZiAoeFN0YXJ0ICE9PSB1bmRlZmluZWQgJiYgeEVuZCAhPT0gdW5kZWZpbmVkKSB7XG4gICAgICAgICAgICBsZXQgZmlsdGVyZWREYXRhOiBJVHJhY2VWYWx1ZVtdID0gW107XG4gICAgICAgICAgICBmb3IgKGxldCBpID0gMDsgaSA8IGFsbERhdGEubGVuZ3RoOyArK2kpIHtcbiAgICAgICAgICAgICAgICBsZXQgdmFsdWUgPSBhbGxEYXRhW2ldO1xuICAgICAgICAgICAgICAgIGlmICh2YWx1ZS54IDwgeEVuZCAmJiB2YWx1ZS54ID4geFN0YXJ0KSB7XG4gICAgICAgICAgICAgICAgICAgIGZpbHRlcmVkRGF0YS5wdXNoKHZhbHVlKTtcbiAgICAgICAgICAgICAgICB9IGVsc2UgaWYgKHZhbHVlLmR4ICYmIHZhbHVlLnggKyB2YWx1ZS5keCA8IHhFbmQgJiZcbiAgICAgICAgICAgICAgICAgICAgdmFsdWUueCArIHZhbHVlLmR4ID4geFN0YXJ0KSB7XG4gICAgICAgICAgICAgICAgICAgIGZpbHRlcmVkRGF0YS5wdXNoKHZhbHVlKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIHRoaXMuX2RhdGEgPSB0aGlzLm1lcmdlTWFya2VycyhmaWx0ZXJlZERhdGEpO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgdGhpcy5fZGF0YSA9IHRoaXMubWVyZ2VNYXJrZXJzKGFsbERhdGEpO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiB0aGlzLl9kYXRhO1xuICAgIH1cbn07XG5cbi8qKiAqL1xuXG5cbmV4cG9ydCBjbGFzcyBYWUhlYXRNYXBEZWNpbWF0b3IgaW1wbGVtZW50cyBJWFlTdGFja2VkRGVjaW1hdG9yIHtcbiAgICBwdWJsaWMgc3RhdGljIEtFWSA9ICdYWUhlYXRNYXBEZWNpbWF0b3InO1xuXG4gICAgLyoqIHRoaXMgZnVuY3Rpb24gaXMgdXNlZCB0byBtYXAgdGhlIGlucHV0IHh5VmFsdWVzIHRvIHggc2NhbGVkIHZhbHVlcyovXG4gICAgcHJvdGVjdGVkIF94VmFsdWVUb0Nvb3JkOiAodmFsdWU6IGFueSkgPT4gbnVtYmVyO1xuXG4gICAgLyoqIHRoaXMgZnVuY3Rpb24gaXMgdXNlZCB0byBtYXAgdGhlIHJldmVydCB4eVZhbHVlcyBmcm9tIHggc2NhbGVkIHZhbHVlcyovXG4gICAgcHJvdGVjdGVkIF94Q29vcmRUb1ZhbHVlOiAodmFsdWU6IGFueSkgPT4gbnVtYmVyO1xuXG4gICAgLyoqIHRoaXMgZnVuY3Rpb24gaXMgdXNlZCB0byBtYXAgdGhlIGlucHV0IHh5VmFsdWVzIHRvIHkgc2NhbGVkIHZhbHVlcyovXG4gICAgcHJvdGVjdGVkIF95VmFsdWVUb0Nvb3JkOiAodmFsdWU6IGFueSkgPT4gbnVtYmVyO1xuXG4gICAgLyoqIHRoZSBsaXN0IG9mIHZhbHVlcyBpbiB0aGUgYnVja2V0ICovXG4gICAgcHJvdGVjdGVkIF9kZWNpbWF0ZWRWYWx1ZXM6IElYWVZhbHVlW11bXTtcblxuICAgIGNvbnN0cnVjdG9yKCkge1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIGNvbnN0cnVjdCBhIGdlbmVyaWMgZGVjaW1hdG9yIHVzaW5nIGEgY3VzdG9tIHVzZXIgZnVuY3Rpb25cbiAgICAgKlxuICAgICAqIEBwYXJhbSB4VmFsdWVUb0Nvb3JkIGNvbnZlcnRzIHRoZSB4IHZhbHVlIHRvIGEgR1VJIHggY29vcmRpbmF0ZVxuICAgICAqIEBwYXJhbSB5VmFsdWVUb0Nvb3JkIGNvbnZlcnRzIHRoZSB5IHZhbHVlIHRvIGEgR1VJIHkgY29vcmRpbmF0ZVxuICAgICAqIEBwYXJhbSBkZWNpbWF0aW9uRnVuYyBjb252ZXJ0IGEgbGlzdCBvZiBkYXRhIHRvIGEgZm9yIHJlbmRlcmluZyBzbWFsbGVyIGxpc3RcbiAgICAgKi9cbiAgICBpbml0aWFsaXplKHhWYWx1ZVRvQ29vcmQ6ICh2YWx1ZTogYW55KSA9PiBudW1iZXIsXG4gICAgICAgIHhDb29yZFRvVmFsdWU6ICh2YWx1ZTogYW55KSA9PiBudW1iZXIsXG4gICAgICAgIHlWYWx1ZVRvQ29vcmQ6ICh2YWx1ZTogYW55KSA9PiBudW1iZXIpIHtcblxuICAgICAgICB0aGlzLl94VmFsdWVUb0Nvb3JkID0geFZhbHVlVG9Db29yZDtcbiAgICAgICAgdGhpcy5feENvb3JkVG9WYWx1ZSA9IHhDb29yZFRvVmFsdWU7XG4gICAgICAgIHRoaXMuX3lWYWx1ZVRvQ29vcmQgPSB5VmFsdWVUb0Nvb3JkO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIFJldHVybnMgdGhlIGtleSBvZiB0aGlzIGRlY2ltYXRvclxuICAgICAqL1xuICAgIHB1YmxpYyBnZXRLZXkoKTogc3RyaW5nIHtcbiAgICAgICAgcmV0dXJuIFN1bW1lZFZhbHVlTXVsdGlYWVNlcmllc0RlY2ltYXRvci5LRVk7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogUmV0dXJucyB0aGUgZGVjaW1hdGVkIGxpc3Qgb2YgYnVja2V0c1xuICAgICAqL1xuICAgIHB1YmxpYyBnZXROYW1lKCk6IHN0cmluZyB7XG4gICAgICAgIHJldHVybiAnJztcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBSZXR1cm5zIHRoZSBkZWNpbWF0ZWQgbGlzdCBvZiBidWNrZXRzXG4gICAgICovXG4gICAgcHVibGljIGdldFZhbHVlcygpOiBJWFlWYWx1ZVtdW10ge1xuICAgICAgICByZXR1cm4gdGhpcy5fZGVjaW1hdGVkVmFsdWVzO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIFZhbHVlcyB0byBiZSBkZWNpbWF0ZWRcbiAgICAgKlxuICAgICAqIEBwYXJhbSB4U3RhcnQgLSBzdGFydCB0aW1lIG9mIHRoZSByZWdpb25cbiAgICAgKiBAcGFyYW0geEVuZCAtIHN0YXJ0IHRpbWUgb2YgdGhlIHJlZ2lvblxuICAgICAqIEBwYXJhbSB2YWx1ZXMgLSBWYWx1ZXMgdG8gYmUgZGVjaW1hdGVkLlxuICAgICAqL1xuICAgIHB1YmxpYyBkZWNpbWF0ZVZhbHVlcyh4U3RhcnQ6IG51bWJlciwgeEVuZDogbnVtYmVyLCB2YWx1ZXM6IElCdWZmZXI8SVhZVmFsdWU+W10pOiBJWFlWYWx1ZVtdW10ge1xuICAgICAgICB0aGlzLl9kZWNpbWF0ZWRWYWx1ZXMgPSBbXTtcblxuICAgICAgICAvLyBmaXJzdCB0aGlzIGlzIHRvdGFsIHdlaWdodGVkIHN1bSBwZXIgeCwgdGhlbiB1c2VkIHRvIHN0b3JlIHBlcmNlbnRhZ2UgcGVyIHhcbiAgICAgICAgbGV0IHRlbXBWYWx1ZXM6IG51bWJlcltdW10gPSBbXTtcblxuICAgICAgICBsZXQgZ2xvYmFsU3RhcnRCdWNrZXQgPSAwO1xuICAgICAgICBsZXQgZ2xvYmFsRW5kQnVja2V0ID0gTWF0aC5jZWlsKHRoaXMuX3hWYWx1ZVRvQ29vcmQoTnVtYmVyLk1BWF9WQUxVRSkpO1xuXG4gICAgICAgIGlmIChnbG9iYWxFbmRCdWNrZXQgPCBnbG9iYWxTdGFydEJ1Y2tldCkge1xuICAgICAgICAgICAgcmV0dXJuIHVuZGVmaW5lZDtcbiAgICAgICAgfVxuXG4gICAgICAgIC8vIE5PVEU6IEkgZG8gdGhpcyB1cCBoZXJlIHNvIEkgY2FuIGNoZWF0IGFuZCB1c2UgdGhlIHggdmFsdWVzIGhlcmVcbiAgICAgICAgLy8gc28gbGF0ZXIgSSBkb24ndCBrZWVwIGNhbGxpbmcgX3hDb29yZFRvVmFsdWVcbiAgICAgICAgbGV0IHhCdWNrZXRWYWx1ZXMgPSBbXTtcbiAgICAgICAgZm9yIChsZXQgYnVja2V0ID0gMDsgYnVja2V0IDw9IGdsb2JhbEVuZEJ1Y2tldCArIDE7ICsrYnVja2V0KSB7XG4gICAgICAgICAgICB4QnVja2V0VmFsdWVzLnB1c2godGhpcy5feENvb3JkVG9WYWx1ZShidWNrZXQpKTtcbiAgICAgICAgfVxuXG4gICAgICAgIC8vIGZvciBhIHNlcmllcyBnZXQgdGhlIHdlaWdodGVkIHN1bSBmb3IgdGhlIG51bWJlciBvZiBidWNrZXRzIHhTdGFydCB0byB4RW5kXG4gICAgICAgIGZvciAobGV0IHN0YXRlSWR4ID0gMDsgc3RhdGVJZHggPCB2YWx1ZXMubGVuZ3RoOyArK3N0YXRlSWR4KSB7XG4gICAgICAgICAgICBsZXQgcGVyU3RhdGVEYXRhID0gdmFsdWVzW3N0YXRlSWR4XTtcbiAgICAgICAgICAgIGxldCB2YWx1ZTogSVhZVmFsdWU7XG4gICAgICAgICAgICBsZXQgbmV4dFZhbHVlOiBJWFlWYWx1ZTtcbiAgICAgICAgICAgIGxldCBzdGFydCA9IGZpbmRGaXJzdEluc2VydGlvbklkeCh2YWx1ZXNbc3RhdGVJZHhdLCB4U3RhcnQpO1xuICAgICAgICAgICAgbGV0IGVuZCA9IGZpbmRMYXN0SW5zZXJ0aW9uSWR4KHZhbHVlc1tzdGF0ZUlkeF0sIHhFbmQpO1xuXG4gICAgICAgICAgICBpZiAoc3RhcnQgPiAwKSB7XG4gICAgICAgICAgICAgICAgLS1zdGFydDtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIC8vIHRoZSBsYXN0IGVsZW1lbnQgd291bGQgYmUgY2F1Z2h0IGJ5IHRoZSBhbGdvcml0aG0gYWxyZWFkeVxuICAgICAgICAgICAgaWYgKGVuZCA9PT0gcGVyU3RhdGVEYXRhLmxlbmd0aCgpKSB7XG4gICAgICAgICAgICAgICAgLS1lbmQ7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIC8vIHBhZCBlbmRCdWNrZXQgKyAxIHNvIHdlIGdldCBkYXRhIHBhc3QgdGhlIGxhc3QgcG9pbnQgaW4gdGhlIGJ1Y2tldFxuICAgICAgICAgICAgLy8gc28gd2UgY2FuIGdyYXBoIHRvIHRoZSBmaXJzdCB2YWx1ZSBpbiB0aGUgbmV4dCBidWNrZXRcbiAgICAgICAgICAgIHRlbXBWYWx1ZXNbc3RhdGVJZHhdID0gQXJyYXkuYXBwbHkobnVsbCwgQXJyYXkoZ2xvYmFsRW5kQnVja2V0KSkuXG4gICAgICAgICAgICAgICAgbWFwKE51bWJlci5wcm90b3R5cGUudmFsdWVPZiwgMCk7XG5cbiAgICAgICAgICAgIC8vIGdldCB3ZWlnaHRlZCBzdW0gb2YgdGhlIHZhbHVlcyBmb3IgZWFjaCBidWNrZXRcbiAgICAgICAgICAgIGZvciAobGV0IHJhd0RhdGFJZHggPSBzdGFydDsgcmF3RGF0YUlkeCA8IGVuZDsgKytyYXdEYXRhSWR4KSB7XG4gICAgICAgICAgICAgICAgdmFsdWUgPSBwZXJTdGF0ZURhdGEuZ2V0KHJhd0RhdGFJZHgpO1xuICAgICAgICAgICAgICAgIG5leHRWYWx1ZSA9IHBlclN0YXRlRGF0YS5nZXQocmF3RGF0YUlkeCArIDEpO1xuXG4gICAgICAgICAgICAgICAgbGV0IHN0YXJ0QnVja2V0ID0gTWF0aC5mbG9vcih0aGlzLl94VmFsdWVUb0Nvb3JkKHZhbHVlLngpKTtcbiAgICAgICAgICAgICAgICBsZXQgZW5kQnVja2V0ID0gTWF0aC5mbG9vcih0aGlzLl94VmFsdWVUb0Nvb3JkKG5leHRWYWx1ZS54KSk7XG5cbiAgICAgICAgICAgICAgICBsZXQgdG90YWxYID0gKG5leHRWYWx1ZS54IC0gdmFsdWUueCk7XG4gICAgICAgICAgICAgICAgbGV0IHZhbHVlUGVyWCA9IHRvdGFsWCA9PT0gMCA/IDAgOiBuZXh0VmFsdWUueSAvIHRvdGFsWDtcbiAgICAgICAgICAgICAgICBpZiAoc3RhcnRCdWNrZXQgPT09IGVuZEJ1Y2tldCkge1xuICAgICAgICAgICAgICAgICAgICBpZiAoeFN0YXJ0ID09PSB1bmRlZmluZWQgfHwgKHZhbHVlLnggPiB4U3RhcnQgJiYgbmV4dFZhbHVlLnggPCB4RW5kKSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgLy8gaGVyZSBpdCdzIGFsbCBpbiB0aGUgZXhpc3RpbmcgYnVja2V0XG4gICAgICAgICAgICAgICAgICAgICAgICB0ZW1wVmFsdWVzW3N0YXRlSWR4XVtzdGFydEJ1Y2tldF0gKz0gdmFsdWVQZXJYO1xuICAgICAgICAgICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICAgICAgbGV0IGJ1Y2tldFNjYWxhciA9IDEgLyAoeEJ1Y2tldFZhbHVlc1tzdGFydEJ1Y2tldCArIDFdIC0geEJ1Y2tldFZhbHVlc1tzdGFydEJ1Y2tldF0pO1xuICAgICAgICAgICAgICAgICAgICAgICAgaWYgKG5leHRWYWx1ZS54IDwgeEVuZCkge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIGhlcmUgdGhlIGJhY2sgaGFsZiBpcyBpbiB0aGUgYnVja2V0XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgdGVtcFZhbHVlc1tzdGF0ZUlkeF1bc3RhcnRCdWNrZXRdICs9XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIChuZXh0VmFsdWUueCAtIHhCdWNrZXRWYWx1ZXNbc3RhcnRCdWNrZXRdKSAqIHZhbHVlUGVyWCAqIGJ1Y2tldFNjYWxhcjtcbiAgICAgICAgICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gaGVyZSB0aGUgZnJvbnQgaGFsZiBpcyBpbiB0aGUgYnVja2V0XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgdGVtcFZhbHVlc1tzdGF0ZUlkeF1bc3RhcnRCdWNrZXRdICs9XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICh4QnVja2V0VmFsdWVzW3N0YXJ0QnVja2V0ICsgMV0gLSB2YWx1ZS54KSAqIHZhbHVlUGVyWCAqIGJ1Y2tldFNjYWxhcjtcbiAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgIGxldCBidWNrZXRTY2FsYXIgPSAxIC8gKHhCdWNrZXRWYWx1ZXNbc3RhcnRCdWNrZXQgKyAxXSAtIHhCdWNrZXRWYWx1ZXNbc3RhcnRCdWNrZXRdKTtcbiAgICAgICAgICAgICAgICAgICAgbGV0IHN0YXJ0WCA9IHhTdGFydCA/IE1hdGgubWF4KHhTdGFydCwgdmFsdWUueCkgOiB2YWx1ZS54O1xuICAgICAgICAgICAgICAgICAgICBsZXQgZW5kU3RhcnRCdWNrZXQgPSB4QnVja2V0VmFsdWVzW3N0YXJ0QnVja2V0ICsgMV07XG4gICAgICAgICAgICAgICAgICAgIHRlbXBWYWx1ZXNbc3RhdGVJZHhdW3N0YXJ0QnVja2V0XSArPVxuICAgICAgICAgICAgICAgICAgICAgICAgKGVuZFN0YXJ0QnVja2V0IC0gc3RhcnRYKSAqIHZhbHVlUGVyWCAqIGJ1Y2tldFNjYWxhcjtcblxuICAgICAgICAgICAgICAgICAgICAvLyBhZGQgaW4gYWxsIHRoZSBidWNrZXQgdmFsdWVzIGluIGJldHdlZW5cbiAgICAgICAgICAgICAgICAgICAgZm9yIChsZXQgY3VyckJ1Y2tldCA9IHN0YXJ0QnVja2V0ICsgMTsgY3VyckJ1Y2tldCA8IGVuZEJ1Y2tldDsgKytjdXJyQnVja2V0KSB7XG4gICAgICAgICAgICAgICAgICAgICAgICB0ZW1wVmFsdWVzW3N0YXRlSWR4XVtjdXJyQnVja2V0XSArPSB2YWx1ZVBlclg7XG4gICAgICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgICAgICAvLyBhZGQgaW4gZW5kIGJ1Y2tldCBhbW91bnRcbiAgICAgICAgICAgICAgICAgICAgYnVja2V0U2NhbGFyID0gMSAvICh4QnVja2V0VmFsdWVzW2VuZEJ1Y2tldF0gLSB4QnVja2V0VmFsdWVzW2VuZEJ1Y2tldCAtIDFdKTtcbiAgICAgICAgICAgICAgICAgICAgbGV0IGVuZFggPSB4RW5kID8gTWF0aC5taW4oeEVuZCwgbmV4dFZhbHVlLngpIDogbmV4dFZhbHVlLng7XG4gICAgICAgICAgICAgICAgICAgIGxldCBzdGFydEVuZEJ1Y2tldCA9IHhCdWNrZXRWYWx1ZXNbZW5kQnVja2V0XTtcbiAgICAgICAgICAgICAgICAgICAgdGVtcFZhbHVlc1tzdGF0ZUlkeF1bZW5kQnVja2V0XSArPVxuICAgICAgICAgICAgICAgICAgICAgICAgKGVuZFggLSBzdGFydEVuZEJ1Y2tldCkgKiB2YWx1ZVBlclggKiBidWNrZXRTY2FsYXI7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICB0aGlzLl9kZWNpbWF0ZWRWYWx1ZXNbc3RhdGVJZHhdID0gW107XG5cbiAgICAgICAgICAgIGxldCBidWNrZXRzID0gdGVtcFZhbHVlc1tzdGF0ZUlkeF07XG4gICAgICAgICAgICBmb3IgKGxldCBidWNrZXQgPSAwOyBidWNrZXQgPCBidWNrZXRzLmxlbmd0aDsgKytidWNrZXQpIHtcbiAgICAgICAgICAgICAgICB0aGlzLl9kZWNpbWF0ZWRWYWx1ZXNbc3RhdGVJZHhdW2J1Y2tldF0gPSB7XG4gICAgICAgICAgICAgICAgICAgIHg6IHhCdWNrZXRWYWx1ZXNbYnVja2V0XSxcbiAgICAgICAgICAgICAgICAgICAgeTogdGVtcFZhbHVlc1tzdGF0ZUlkeF1bYnVja2V0XSA/IHRlbXBWYWx1ZXNbc3RhdGVJZHhdW2J1Y2tldF0gOiAwXG4gICAgICAgICAgICAgICAgfTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuXG4gICAgICAgIHJldHVybiB0aGlzLl9kZWNpbWF0ZWRWYWx1ZXM7XG4gICAgfVxufTtcblxubGV0IGRlY2ltYXRvckxpc3QgPSBbXG4gICAgbmV3IFJlc2lkZW5jeURlY2ltYXRvcigpLCBuZXcgTWluUG9pbnREZWNpbWF0b3IoKSxcbiAgICBuZXcgQXZnUG9pbnREZWNpbWF0b3IoKSwgbmV3IE1heFBvaW50RGVjaW1hdG9yKCksIG5ldyBBdmdDb250aW51b3VzRGVjaW1hdG9yKCksXG4gICAgbmV3IEZsYW1lQ2hhcnRNZXJnZVJlY3REZWNpbWF0b3IoKSwgbmV3IEZsYW1lQ2hhcnRSZWN0TGltaXREZWNpbWF0b3IoKSxcbiAgICBuZXcgTkVXU1BvaW50RGVjaW1hdG9yKCksIG5ldyBORVdTU3RhdGVEZWNpbWF0b3IoKSwgbmV3IFNpbXBsZU1hcmtlckRlY2ltYXRvcigpLFxuICAgIG5ldyBYWVBvaW50RGVjaW1hdG9yKCksIG5ldyBTdW1tZWRWYWx1ZVhZU2VyaWVzRGVjaW1hdG9yKCksXG4gICAgbmV3IFN1bW1lZFZhbHVlTXVsdGlYWVNlcmllc0RlY2ltYXRvcigpLCBuZXcgVHJhY2VSZXNpZGVuY3lEZWNpbWF0b3IoKVxuXTtcblxuZXhwb3J0IGxldCBJbnRlcm5hbERlY2ltYXRvck1hcDogeyBbaW5kZXg6IHN0cmluZ106IElEZWNpbWF0b3IgfSA9IHt9O1xuXG5kZWNpbWF0b3JMaXN0LmZvckVhY2goZnVuY3Rpb24gKGRlY2ltYXRvcjogYW55KSB7XG4gICAgSW50ZXJuYWxEZWNpbWF0b3JNYXBbZGVjaW1hdG9yLmdldEtleSgpXSA9IGRlY2ltYXRvcjtcbn0pO1xuIl0sIm1hcHBpbmdzIjoiOztBQVNBO0FBQ0E7QUFFQTtBQUVBO0FBb0JBO0FBQUE7QUFDQTtBQXdDQTtBQXRDQTtBQUdBO0FBRUE7QUFDQTtBQUNBO0FBRUE7QUFDQTtBQUNBO0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFFQTs7Ozs7O0FBTUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFBQTtBQUNBO0FBQ0E7QUFFQTtBQUNBO0FBQ0E7QUF6Q0E7QUEyQ0E7OztBQUdBO0FBQ0E7QUF1QkE7QUFDQTtBQUNBO0FBRUE7Ozs7OztBQU1BO0FBQ0E7QUFJQTtBQUNBO0FBQ0E7QUFDQTtBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUVBOzs7Ozs7QUFNQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUVBO0FBQ0E7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFBQTtBQUNBO0FBQ0E7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBRUE7QUFDQTtBQUNBO0FBS0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFJQTtBQUVBO0FBQ0E7QUFDQTtBQWhJQTtBQWtJQTtBQUNBO0FBRUE7QUFDQTtBQUVBO0FBQ0E7QUFDQTtBQUdBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQXpCQTtBQUNBO0FBeUJBO0FBRUE7QUFHQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUVBO0FBQ0E7QUFDQTtBQUVBO0FBQ0E7QUFFQTtBQUNBO0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBUkE7QUFDQTtBQVFBO0FBRUE7QUFDQTtBQUVBO0FBQ0E7QUFFQTtBQUNBO0FBQ0E7QUFHQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUF6QkE7QUFDQTtBQXlCQTtBQUVBOzs7Ozs7O0FBT0E7QUFDQTtBQUVBO0FBQ0E7QUFFQTtBQUNBO0FBQ0E7QUFHQTtBQUNBO0FBRUE7QUFDQTtBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBekJBO0FBQ0E7QUEwQkE7OztBQUdBO0FBQ0E7QUF1QkE7QUFDQTtBQUNBO0FBRUE7Ozs7OztBQU1BO0FBQ0E7QUFJQTtBQUNBO0FBQ0E7QUFDQTtBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUVBOzs7Ozs7QUFNQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUVBO0FBQ0E7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFBQTtBQUNBO0FBQ0E7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUVBO0FBQ0E7QUFDQTtBQUtBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFFQTtBQUNBO0FBSUE7QUFDQTtBQUNBO0FBQ0E7QUEvSEE7QUFpSUE7QUFDQTtBQUVBO0FBQ0E7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFSQTtBQUNBO0FBUUE7QUFFQTs7QUFFQTtBQUNBO0FBSUE7QUFDQTtBQUNBO0FBRUE7QUFDQTtBQUVBO0FBQ0E7QUFDQTtBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBRUE7QUFDQTtBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFBQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUFBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUVBO0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUVBO0FBQ0E7QUF0R0E7QUF3R0E7QUFDQTtBQWVBO0FBQ0E7QUFFQTs7Ozs7O0FBTUE7QUFDQTtBQUlBO0FBQ0E7QUFDQTtBQUNBO0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBRUE7Ozs7OztBQU1BO0FBQ0E7QUFFQTtBQUVBO0FBQ0E7O0FBbkVBO0FBQ0E7QUFtRUE7QUFFQTs7QUFFQTtBQUNBO0FBR0E7QUFDQTtBQUNBO0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUVBOzs7Ozs7QUFNQTtBQUNBO0FBRUE7QUFHQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFFQTtBQUNBOztBQXJEQTtBQUNBO0FBcURBO0FBRUE7QUFDQTtBQWVBO0FBQ0E7QUFFQTs7Ozs7O0FBTUE7QUFDQTtBQUlBO0FBQ0E7QUFDQTtBQUNBO0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBRUE7Ozs7OztBQU1BO0FBQ0E7QUFFQTtBQUVBO0FBQ0E7O0FBbkVBO0FBQ0E7QUFxRUE7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBTUE7Ozs7QUFJQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFmQTtBQWlCQTs7Ozs7OztBQU9BO0FBQ0E7QUFnQkE7QUFHQTtBQUNBO0FBQ0E7QUFDQTtBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBRUE7QUFDQTtBQUNBO0FBRUE7Ozs7QUFJQTtBQUNBO0FBQ0E7QUFDQTtBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFFQTtBQUNBO0FBRUE7Ozs7OztBQU1BO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFyRUE7QUF1RUE7O0FBRUE7QUFDQTtBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFFQTs7Ozs7QUFLQTtBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUVBO0FBQ0E7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFFQTs7Ozs7O0FBTUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUVBO0FBQ0E7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBRUE7QUFDQTtBQUNBO0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFFQTtBQUNBO0FBQUE7QUFDQTtBQUNBO0FBQ0E7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUVBO0FBQ0E7QUFDQTtBQXhHQTtBQUNBO0FBeUdBOztBQUVBO0FBQ0E7QUFPQTtBQUNBO0FBTkE7QUFDQTtBQU1BO0FBQ0E7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUVBO0FBQ0E7QUFDQTtBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBRUE7QUFDQTtBQUFBO0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBRUE7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBRUE7QUFDQTtBQUFBO0FBQ0E7QUFDQTtBQUNBO0FBRUE7QUFDQTtBQUNBO0FBQUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUFBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUVBO0FBQ0E7QUFFQTtBQUNBO0FBRUE7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUFBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBRUE7QUFFQTs7Ozs7O0FBTUE7QUFDQTtBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUVBO0FBQ0E7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFFQTtBQUNBO0FBQ0E7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFFQTtBQUNBO0FBRUE7QUFDQTtBQUFBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFFQTtBQUNBOztBQXJNQTtBQUNBO0FBcU1BO0FBRUE7QUFjQTtBQUdBO0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUVBOzs7Ozs7QUFNQTtBQUNBO0FBR0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFFQTtBQUNBO0FBRUE7QUFDQTs7QUFsRkE7QUFDQTtBQWtGQTtBQUVBOzs7QUFHQTtBQUNBO0FBQUE7QUFJQTtBQXVSQTtBQTNRQTtBQUdBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFFQTs7Ozs7Ozs7QUFRQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBRUE7QUFDQTtBQUNBO0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBRUE7QUFDQTtBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUVBO0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQUE7QUFDQTtBQUNBO0FBQ0E7QUFFQTtBQUNBO0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFBQTtBQUNBO0FBQ0E7QUFDQTtBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFBQTtBQUNBO0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUFBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBRUE7QUFFQTtBQUNBO0FBQ0E7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBRUE7QUFDQTtBQUNBO0FBRUE7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBRUE7Ozs7OztBQU1BO0FBQ0E7QUFHQTtBQUNBO0FBQ0E7QUFDQTs7QUExUkE7QUFDQTtBQTBSQTtBQUVBOzs7QUFHQTtBQUNBO0FBY0E7QUFJQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFFQTs7Ozs7O0FBTUE7QUFDQTtBQUNBO0FBRUE7QUFDQTtBQUVBO0FBQ0E7QUFDQTtBQUVBO0FBQ0E7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUVBO0FBQ0E7QUFDQTtBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUVBO0FBQ0E7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFFQTtBQUNBO0FBRUE7QUFDQTtBQUNBO0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQUE7QUFDQTtBQUNBO0FBQ0E7QUFFQTtBQUNBOztBQXhLQTtBQUNBO0FBd0tBO0FBRUE7OztBQUdBO0FBQ0E7QUFjQTtBQUlBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUVBOzs7Ozs7QUFNQTtBQUNBO0FBQ0E7QUFDQTtBQUVBO0FBQ0E7QUFDQTtBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUVBO0FBQ0E7QUFDQTtBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUVBO0FBQ0E7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUFBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQXRJQTtBQUNBO0FBc0lBO0FBRUE7O0FBRUE7QUFDQTtBQWFBO0FBR0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUVBO0FBQ0E7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7Ozs7OztBQU1BO0FBQ0E7QUFHQTtBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFBQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBRUE7QUFDQTtBQUFBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBdkZBO0FBQ0E7QUF1RkE7QUFFQTtBQUdBO0FBZUE7QUFDQTtBQUVBOzs7Ozs7QUFNQTtBQUNBO0FBSUE7QUFDQTtBQUNBO0FBQ0E7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFFQTs7Ozs7O0FBTUE7QUFDQTtBQUNBO0FBRUE7QUFDQTtBQUVBO0FBQ0E7QUFFQTtBQUNBO0FBQ0E7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUVBO0FBQ0E7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUFBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFBQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFFQTtBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFFQTtBQUNBOztBQWxLQTtBQUNBO0FBa0tBO0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUVBO0FBRUE7QUFDQTtBQUNBOyIsInNvdXJjZVJvb3QiOiIifQ==\n//# sourceURL=webpack-internal:///./src/core/cartesian/decimator/decimator.ts\n");

/***/ }),

/***/ "./src/core/cartesian/decimator/worker.ts":
/*!************************************************!*\
  !*** ./src/core/cartesian/decimator/worker.ts ***!
  \************************************************/
/*! no static exports found */
/***/ (function(module, exports, __webpack_require__) {

"use strict";
eval("\nObject.defineProperty(exports, \"__esModule\", { value: true });\nconst axis_1 = __webpack_require__(/*! ../../../interface/chart/axis */ \"./src/interface/chart/axis.ts\");\nconst utilities_1 = __webpack_require__(/*! ../../utilities */ \"./src/core/utilities.ts\");\nconst decimator_1 = __webpack_require__(/*! ./decimator */ \"./src/core/cartesian/decimator/decimator.ts\");\nconst d3 = __webpack_require__(/*! d3 */ \"d3\");\n// Worker.ts\nconst ctx = self;\n// Respond to message from parent thread\nctx.addEventListener(\"message\", (message) => {\n    let xScale;\n    let yScale;\n    let def = message.data;\n    if (def.xAxis.axisDesc.scaleType === axis_1.AxisType.Ordinal) {\n        xScale = d3.scaleBand().range([0, def.xRange]).padding(0.1)\n            .align(0.5).domain(def.xDomain);\n    }\n    else {\n        if (def.xAxis.axisDesc.scaleType === axis_1.AxisType.Linear) {\n            xScale = d3.scaleLinear().domain(def.xDomain).clamp(true);\n        }\n        else if (def.xAxis.axisDesc.scaleType === axis_1.AxisType.Logarithmic) {\n            xScale = d3.scaleLog().domain(def.xDomain).clamp(true);\n        }\n        xScale.range([0, def.xRange]);\n    }\n    if (def.yAxis) {\n        if (def.yAxis.axisDesc.scaleType === axis_1.AxisType.Ordinal) {\n            yScale = d3.scaleBand().range([0, def.yRange]).padding(0.1)\n                .align(0.5).domain(def.yDomain);\n        }\n        else {\n            if (def.yAxis.axisDesc.scaleType === axis_1.AxisType.Linear) {\n                yScale = d3.scaleLinear().domain(def.yDomain).clamp(true);\n            }\n            else if (def.yAxis.axisDesc.scaleType === axis_1.AxisType.Logarithmic) {\n                yScale = d3.scaleLog().domain(def.yDomain).clamp(true);\n            }\n            yScale.range([def.yRange, 0]);\n        }\n    }\n    let decimator = decimator_1.InternalDecimatorMap[def.decimatorName];\n    decimator.initialize(xScale, xScale.invert, yScale, def.names);\n    // ugly hardcode for now\n    let values;\n    if (!def.names) {\n        values = new utilities_1.SimpleBuffer(def.values);\n    }\n    else {\n        values = [];\n        for (let i = 0; i < def.values.length; ++i) {\n            values[i] = new utilities_1.SimpleBuffer(def.values[i]);\n        }\n    }\n    let data = decimator.decimateValues(def.xStart, def.xEnd, values);\n    ctx.postMessage(data, undefined);\n});\n//# sourceURL=[module]\n//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiLi9zcmMvY29yZS9jYXJ0ZXNpYW4vZGVjaW1hdG9yL3dvcmtlci50cy5qcyIsInNvdXJjZXMiOlsid2VicGFjazovL1VXVC8uL3NyYy9jb3JlL2NhcnRlc2lhbi9kZWNpbWF0b3Ivd29ya2VyLnRzPzVjZTAiXSwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgQXhpc1R5cGUgfSBmcm9tICcuLi8uLi8uLi9pbnRlcmZhY2UvY2hhcnQvYXhpcyc7XG5pbXBvcnQgeyBTaW1wbGVCdWZmZXIgfSBmcm9tICcuLi8uLi91dGlsaXRpZXMnO1xuaW1wb3J0IHsgSW50ZXJuYWxEZWNpbWF0b3JNYXAgfSBmcm9tICcuL2RlY2ltYXRvcic7XG5pbXBvcnQgKiBhcyBkMyBmcm9tICdkMyc7XG5cbi8vIFdvcmtlci50c1xuY29uc3QgY3R4OiBXb3JrZXIgPSBzZWxmIGFzIGFueTtcblxuLy8gUmVzcG9uZCB0byBtZXNzYWdlIGZyb20gcGFyZW50IHRocmVhZFxuY3R4LmFkZEV2ZW50TGlzdGVuZXIoXCJtZXNzYWdlXCIsIChtZXNzYWdlKSA9PiB7XG4gICAgbGV0IHhTY2FsZTogYW55O1xuICAgIGxldCB5U2NhbGU6IGFueTtcbiAgICBsZXQgZGVmID0gbWVzc2FnZS5kYXRhO1xuICAgIGlmIChkZWYueEF4aXMuYXhpc0Rlc2Muc2NhbGVUeXBlID09PSBBeGlzVHlwZS5PcmRpbmFsKSB7XG4gICAgICAgIHhTY2FsZSA9IGQzLnNjYWxlQmFuZCgpLnJhbmdlKFswLCBkZWYueFJhbmdlXSkucGFkZGluZygwLjEpXG4gICAgICAgICAgICAuYWxpZ24oMC41KS5kb21haW4oZGVmLnhEb21haW4pO1xuICAgIH0gZWxzZSB7XG4gICAgICAgIGlmIChkZWYueEF4aXMuYXhpc0Rlc2Muc2NhbGVUeXBlID09PSBBeGlzVHlwZS5MaW5lYXIpIHtcbiAgICAgICAgICAgIHhTY2FsZSA9IGQzLnNjYWxlTGluZWFyKCkuZG9tYWluKGRlZi54RG9tYWluKS5jbGFtcCh0cnVlKTtcbiAgICAgICAgfSBlbHNlIGlmIChkZWYueEF4aXMuYXhpc0Rlc2Muc2NhbGVUeXBlID09PSBBeGlzVHlwZS5Mb2dhcml0aG1pYykge1xuICAgICAgICAgICAgeFNjYWxlID0gZDMuc2NhbGVMb2coKS5kb21haW4oZGVmLnhEb21haW4pLmNsYW1wKHRydWUpO1xuICAgICAgICB9XG5cbiAgICAgICAgeFNjYWxlLnJhbmdlKFswLCBkZWYueFJhbmdlXSk7XG4gICAgfVxuXG4gICAgaWYgKGRlZi55QXhpcykge1xuICAgICAgICBpZiAoZGVmLnlBeGlzLmF4aXNEZXNjLnNjYWxlVHlwZSA9PT0gQXhpc1R5cGUuT3JkaW5hbCkge1xuICAgICAgICAgICAgeVNjYWxlID0gZDMuc2NhbGVCYW5kKCkucmFuZ2UoWzAsIGRlZi55UmFuZ2VdKS5wYWRkaW5nKDAuMSlcbiAgICAgICAgICAgICAgICAuYWxpZ24oMC41KS5kb21haW4oZGVmLnlEb21haW4pO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgaWYgKGRlZi55QXhpcy5heGlzRGVzYy5zY2FsZVR5cGUgPT09IEF4aXNUeXBlLkxpbmVhcikge1xuICAgICAgICAgICAgICAgIHlTY2FsZSA9IGQzLnNjYWxlTGluZWFyKCkuZG9tYWluKGRlZi55RG9tYWluKS5jbGFtcCh0cnVlKTtcbiAgICAgICAgICAgIH0gZWxzZSBpZiAoZGVmLnlBeGlzLmF4aXNEZXNjLnNjYWxlVHlwZSA9PT0gQXhpc1R5cGUuTG9nYXJpdGhtaWMpIHtcbiAgICAgICAgICAgICAgICB5U2NhbGUgPSBkMy5zY2FsZUxvZygpLmRvbWFpbihkZWYueURvbWFpbikuY2xhbXAodHJ1ZSk7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIHlTY2FsZS5yYW5nZShbZGVmLnlSYW5nZSwgMF0pO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgbGV0IGRlY2ltYXRvcjogYW55ID0gSW50ZXJuYWxEZWNpbWF0b3JNYXBbZGVmLmRlY2ltYXRvck5hbWVdO1xuICAgIGRlY2ltYXRvci5pbml0aWFsaXplKHhTY2FsZSwgeFNjYWxlLmludmVydCwgeVNjYWxlLCBkZWYubmFtZXMpO1xuXG4gICAgLy8gdWdseSBoYXJkY29kZSBmb3Igbm93XG4gICAgbGV0IHZhbHVlczogYW55O1xuICAgIGlmICghZGVmLm5hbWVzKSB7XG4gICAgICAgIHZhbHVlcyA9IG5ldyBTaW1wbGVCdWZmZXIoZGVmLnZhbHVlcyk7XG4gICAgfSBlbHNlIHtcbiAgICAgICAgdmFsdWVzID0gW107XG4gICAgICAgIGZvciAobGV0IGkgPSAwOyBpIDwgZGVmLnZhbHVlcy5sZW5ndGg7ICsraSkge1xuICAgICAgICAgICAgdmFsdWVzW2ldID0gbmV3IFNpbXBsZUJ1ZmZlcihkZWYudmFsdWVzW2ldKTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIGxldCBkYXRhID0gZGVjaW1hdG9yLmRlY2ltYXRlVmFsdWVzKGRlZi54U3RhcnQsIGRlZi54RW5kLCB2YWx1ZXMpO1xuICAgIGN0eC5wb3N0TWVzc2FnZShkYXRhLCB1bmRlZmluZWQpO1xufSk7Il0sIm1hcHBpbmdzIjoiOztBQUFBO0FBQ0E7QUFDQTtBQUNBO0FBRUE7QUFDQTtBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUFBO0FBQ0E7QUFDQTtBQUNBO0FBQUE7QUFDQTtBQUNBO0FBRUE7QUFDQTtBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFBQTtBQUNBO0FBQ0E7QUFDQTtBQUFBO0FBQ0E7QUFDQTtBQUVBO0FBQ0E7QUFDQTtBQUVBO0FBQ0E7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBRUE7QUFDQTtBQUNBOyIsInNvdXJjZVJvb3QiOiIifQ==\n//# sourceURL=webpack-internal:///./src/core/cartesian/decimator/worker.ts\n");

/***/ }),

/***/ "./src/core/data.ts":
/*!**************************!*\
  !*** ./src/core/data.ts ***!
  \**************************/
/*! no static exports found */
/***/ (function(module, exports, __webpack_require__) {

"use strict";
eval("\nObject.defineProperty(exports, \"__esModule\", { value: true });\n/**\n* XYValue\n*\n* Class for simple data that will be rendered as part of a chart\n*/\nclass XYValue {\n    /**\n     * Creates a XYValue instance\n     *\n     * @param x the independent axis coordinate\n     * @param y the dependent axis coordinate\n     */\n    constructor(x, y) {\n        this.x = x;\n        this.y = y;\n    }\n} // XYValue\nexports.XYValue = XYValue;\n/**\n * MinMaxValue\n *\n * Class for candlestick data that will be rendered as part of a chart\n */\nclass MinMaxValue {\n    /**\n     * Creates a MinMaxValue instance\n     *\n     * @param key - the axis co-ordinate which will be x co-ordinate\n     * @param min - the minimum value of metric for the axis co-ordinate\n     * @param max - the maximum value of metric for the axis co-ordinate\n     * @param misc - a misc value of metric for the axis co-ordinate\n     */\n    constructor(x, min, max, misc) {\n        this.x = x;\n        this.min = min;\n        this.max = max;\n        this.y = misc;\n    }\n} // MinMaxValue\nexports.MinMaxValue = MinMaxValue;\n/**\n * CandlestickValue\n *\n * Class for candlestick data that will be rendered as part of a chart\n */\nclass CandlestickValue {\n    /**\n     * Creates a CandlestickValue instance\n     *\n     * @param x - the axis co-ordinate which will be x co-ordinate\n     * @param min - the minimum value of metric for the axis co-ordinate\n     * @param max - the maximum value of metric for the axis co-ordinate\n     * @param entry - the entry value of metric for the axis co-ordinate\n     * @param exit - the exit value of metric for the axis co-ordinate\n     */\n    constructor(x, min, max, entry, exit) {\n        this.x = x;\n        this.min = min;\n        this.max = max;\n        this.entry = entry;\n        this.exit = exit;\n    }\n} // CandlestickValue\nexports.CandlestickValue = CandlestickValue;\n/**\n * SummaryValue class\n */\nclass SummaryValue {\n    /**\n     * SummaryValue class\n     *\n     * @param primaryKey - key for the data\n     * @param value - value for this key\n     * @param secondaryKey - optional secondary key for the data\n     */\n    constructor(key, value = {}) {\n        this.key = key;\n        this.data = value;\n    }\n    /**\n     * Value getter\n     *\n     * @returns add a value to this key\n     */\n    addValue(key, value) {\n        let data = this.data;\n        if (data.hasOwnProperty(key)) {\n            data[key] += value;\n        }\n        else {\n            data[key] = value;\n        }\n        return this;\n    }\n} // class SummaryValue\nexports.SummaryValue = SummaryValue;\n//# sourceURL=[module]\n//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiLi9zcmMvY29yZS9kYXRhLnRzLmpzIiwic291cmNlcyI6WyJ3ZWJwYWNrOi8vVVdULy4vc3JjL2NvcmUvZGF0YS50cz8yMGY3Il0sInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7XG4gICAgSVhZVmFsdWUsIElTdW1tYXJ5VmFsdWUsIElNaW5NYXhWYWx1ZSwgSUNhbmRsZXN0aWNrVmFsdWVcbn0gZnJvbSAnLi4vaW50ZXJmYWNlL2NoYXJ0L3Nlcmllcy1kYXRhJztcblxuLyoqXG4qIFhZVmFsdWVcbipcbiogQ2xhc3MgZm9yIHNpbXBsZSBkYXRhIHRoYXQgd2lsbCBiZSByZW5kZXJlZCBhcyBwYXJ0IG9mIGEgY2hhcnRcbiovXG5leHBvcnQgY2xhc3MgWFlWYWx1ZSBpbXBsZW1lbnRzIElYWVZhbHVlIHtcbiAgICAvKiogU3BlY2lmaWVzIHRoZSBpbmRlcGVuZGVudCBheGlzIGNvLW9yZGluYXRlICovXG4gICAgcHVibGljIHg6IGFueTtcbiAgICAvKiogU3BlY2lmaWVzIHRoZSBkZXBlbmRlbnQgYXhpcyBjby1vcmRpbmF0ZSAqL1xuICAgIHB1YmxpYyB5OiBhbnk7XG5cbiAgICAvKipcbiAgICAgKiBDcmVhdGVzIGEgWFlWYWx1ZSBpbnN0YW5jZVxuICAgICAqXG4gICAgICogQHBhcmFtIHggdGhlIGluZGVwZW5kZW50IGF4aXMgY29vcmRpbmF0ZVxuICAgICAqIEBwYXJhbSB5IHRoZSBkZXBlbmRlbnQgYXhpcyBjb29yZGluYXRlXG4gICAgICovXG4gICAgY29uc3RydWN0b3IoeDogYW55LCB5OiBhbnkpIHtcbiAgICAgICAgdGhpcy54ID0geDtcbiAgICAgICAgdGhpcy55ID0geTtcbiAgICB9XG59ICAgLy8gWFlWYWx1ZVxuXG4vKipcbiAqIE1pbk1heFZhbHVlXG4gKlxuICogQ2xhc3MgZm9yIGNhbmRsZXN0aWNrIGRhdGEgdGhhdCB3aWxsIGJlIHJlbmRlcmVkIGFzIHBhcnQgb2YgYSBjaGFydFxuICovXG5leHBvcnQgY2xhc3MgTWluTWF4VmFsdWUgaW1wbGVtZW50cyBJTWluTWF4VmFsdWUge1xuICAgIC8qKiBTcGVjaWZpZXMgdGhlIGF4aXMgY28tb3JkaW5hdGUgKi9cbiAgICBwdWJsaWMgeDogYW55O1xuICAgIC8qKiBTcGVjaWZpZXMgdGhlIG1pbmltdW0gdmFsdWUgb2YgbWV0cmljIGZvciB0aGUgYXhpcyBjby1vcmRpbmF0ZSAqL1xuICAgIHB1YmxpYyBtaW46IG51bWJlcjtcbiAgICAvKiogU3BlY2lmaWVzIHRoZSBtYXhpbXVtIHZhbHVlIG9mIG1ldHJpYyBmb3IgdGhlIGF4aXMgY28tb3JkaW5hdGUgKi9cbiAgICBwdWJsaWMgbWF4OiBudW1iZXI7XG4gICAgLyoqIFNwZWNpZmllcyB0aGUgbWlzYyB2YWx1ZSBvZiBtZXRyaWMgZm9yIHRoZSBheGlzIGNvLW9yZGluYXRlICovXG4gICAgcHVibGljIHk6IG51bWJlcjtcblxuICAgIC8qKlxuICAgICAqIENyZWF0ZXMgYSBNaW5NYXhWYWx1ZSBpbnN0YW5jZVxuICAgICAqXG4gICAgICogQHBhcmFtIGtleSAtIHRoZSBheGlzIGNvLW9yZGluYXRlIHdoaWNoIHdpbGwgYmUgeCBjby1vcmRpbmF0ZVxuICAgICAqIEBwYXJhbSBtaW4gLSB0aGUgbWluaW11bSB2YWx1ZSBvZiBtZXRyaWMgZm9yIHRoZSBheGlzIGNvLW9yZGluYXRlXG4gICAgICogQHBhcmFtIG1heCAtIHRoZSBtYXhpbXVtIHZhbHVlIG9mIG1ldHJpYyBmb3IgdGhlIGF4aXMgY28tb3JkaW5hdGVcbiAgICAgKiBAcGFyYW0gbWlzYyAtIGEgbWlzYyB2YWx1ZSBvZiBtZXRyaWMgZm9yIHRoZSBheGlzIGNvLW9yZGluYXRlXG4gICAgICovXG4gICAgY29uc3RydWN0b3IoeDogYW55LCBtaW46IG51bWJlciwgbWF4OiBudW1iZXIsIG1pc2M6IG51bWJlcikge1xuICAgICAgICB0aGlzLnggPSB4O1xuICAgICAgICB0aGlzLm1pbiA9IG1pbjtcbiAgICAgICAgdGhpcy5tYXggPSBtYXg7XG4gICAgICAgIHRoaXMueSA9IG1pc2M7XG4gICAgfVxufSAgIC8vIE1pbk1heFZhbHVlXG5cbi8qKlxuICogQ2FuZGxlc3RpY2tWYWx1ZVxuICpcbiAqIENsYXNzIGZvciBjYW5kbGVzdGljayBkYXRhIHRoYXQgd2lsbCBiZSByZW5kZXJlZCBhcyBwYXJ0IG9mIGEgY2hhcnRcbiAqL1xuZXhwb3J0IGNsYXNzIENhbmRsZXN0aWNrVmFsdWUgaW1wbGVtZW50cyBJQ2FuZGxlc3RpY2tWYWx1ZSB7XG4gICAgLyoqIFNwZWNpZmllcyB0aGUgYXhpcyBjby1vcmRpbmF0ZSAqL1xuICAgIHB1YmxpYyB4OiBhbnk7XG4gICAgLyoqIFNwZWNpZmllcyB0aGUgbWluaW11bSB2YWx1ZSBvZiBtZXRyaWMgZm9yIHRoZSBheGlzIGNvLW9yZGluYXRlICovXG4gICAgcHVibGljIG1pbjogYW55O1xuICAgIC8qKiBTcGVjaWZpZXMgdGhlIG1heGltdW0gdmFsdWUgb2YgbWV0cmljIGZvciB0aGUgYXhpcyBjby1vcmRpbmF0ZSAqL1xuICAgIHB1YmxpYyBtYXg6IGFueTtcbiAgICAvKiogU3BlY2lmaWVzIHRoZSBlbnRyeSB2YWx1ZSBvZiBtZXRyaWMgZm9yIHRoZSBheGlzIGNvLW9yZGluYXRlICovXG4gICAgcHVibGljIGVudHJ5OiBhbnk7XG4gICAgLyoqIFNwZWNpZmllcyB0aGUgZXhpdCB2YWx1ZSBvZiBtZXRyaWMgZm9yIHRoZSBheGlzIGNvLW9yZGluYXRlICovXG4gICAgcHVibGljIGV4aXQ6IGFueTtcblxuICAgIC8qKlxuICAgICAqIENyZWF0ZXMgYSBDYW5kbGVzdGlja1ZhbHVlIGluc3RhbmNlXG4gICAgICpcbiAgICAgKiBAcGFyYW0geCAtIHRoZSBheGlzIGNvLW9yZGluYXRlIHdoaWNoIHdpbGwgYmUgeCBjby1vcmRpbmF0ZVxuICAgICAqIEBwYXJhbSBtaW4gLSB0aGUgbWluaW11bSB2YWx1ZSBvZiBtZXRyaWMgZm9yIHRoZSBheGlzIGNvLW9yZGluYXRlXG4gICAgICogQHBhcmFtIG1heCAtIHRoZSBtYXhpbXVtIHZhbHVlIG9mIG1ldHJpYyBmb3IgdGhlIGF4aXMgY28tb3JkaW5hdGVcbiAgICAgKiBAcGFyYW0gZW50cnkgLSB0aGUgZW50cnkgdmFsdWUgb2YgbWV0cmljIGZvciB0aGUgYXhpcyBjby1vcmRpbmF0ZVxuICAgICAqIEBwYXJhbSBleGl0IC0gdGhlIGV4aXQgdmFsdWUgb2YgbWV0cmljIGZvciB0aGUgYXhpcyBjby1vcmRpbmF0ZVxuICAgICAqL1xuICAgIGNvbnN0cnVjdG9yKHg6IGFueSwgbWluOiBudW1iZXIsIG1heDogbnVtYmVyLCBlbnRyeTogbnVtYmVyLCBleGl0OiBudW1iZXIpIHtcbiAgICAgICAgdGhpcy54ID0geDtcbiAgICAgICAgdGhpcy5taW4gPSBtaW47XG4gICAgICAgIHRoaXMubWF4ID0gbWF4O1xuICAgICAgICB0aGlzLmVudHJ5ID0gZW50cnk7XG4gICAgICAgIHRoaXMuZXhpdCA9IGV4aXQ7XG4gICAgfVxufSAgIC8vIENhbmRsZXN0aWNrVmFsdWVcblxuLyoqXG4gKiBTdW1tYXJ5VmFsdWUgY2xhc3NcbiAqL1xuZXhwb3J0IGNsYXNzIFN1bW1hcnlWYWx1ZSBpbXBsZW1lbnRzIElTdW1tYXJ5VmFsdWUge1xuICAgIC8qKiB0aGUgZGVzY3JpcHRpb24gb2YgdGhpcyB2YWx1ZSAqL1xuICAgIHB1YmxpYyBrZXk6IHN0cmluZztcblxuICAgIC8qKiB0aGUgZGVzY3JpcHRpb24gb2YgdGhpcyB2YWx1ZSAqL1xuICAgIHB1YmxpYyBkYXRhOiB7IFtpbmRleDogc3RyaW5nXTogbnVtYmVyIH07XG5cbiAgICAvKipcbiAgICAgKiBTdW1tYXJ5VmFsdWUgY2xhc3NcbiAgICAgKlxuICAgICAqIEBwYXJhbSBwcmltYXJ5S2V5IC0ga2V5IGZvciB0aGUgZGF0YVxuICAgICAqIEBwYXJhbSB2YWx1ZSAtIHZhbHVlIGZvciB0aGlzIGtleVxuICAgICAqIEBwYXJhbSBzZWNvbmRhcnlLZXkgLSBvcHRpb25hbCBzZWNvbmRhcnkga2V5IGZvciB0aGUgZGF0YVxuICAgICAqL1xuICAgIGNvbnN0cnVjdG9yKGtleTogc3RyaW5nLFxuICAgICAgICB2YWx1ZTogeyBbaW5kZXg6IHN0cmluZ106IG51bWJlciB9ID0ge30pIHtcbiAgICAgICAgdGhpcy5rZXkgPSBrZXk7XG4gICAgICAgIHRoaXMuZGF0YSA9IHZhbHVlO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIFZhbHVlIGdldHRlclxuICAgICAqXG4gICAgICogQHJldHVybnMgYWRkIGEgdmFsdWUgdG8gdGhpcyBrZXlcbiAgICAgKi9cbiAgICBwdWJsaWMgYWRkVmFsdWUoa2V5OiBzdHJpbmcsIHZhbHVlOiBudW1iZXIpOiBTdW1tYXJ5VmFsdWUge1xuICAgICAgICBsZXQgZGF0YTogYW55ID0gdGhpcy5kYXRhO1xuXG4gICAgICAgIGlmIChkYXRhLmhhc093blByb3BlcnR5KGtleSkpIHtcbiAgICAgICAgICAgIGRhdGFba2V5XSArPSB2YWx1ZTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIGRhdGFba2V5XSA9IHZhbHVlO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiB0aGlzO1xuICAgIH1cbn0gLy8gY2xhc3MgU3VtbWFyeVZhbHVlIl0sIm1hcHBpbmdzIjoiOztBQUlBOzs7O0FBSUE7QUFDQTtBQU1BOzs7OztBQUtBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQWhCQTtBQWtCQTs7OztBQUlBO0FBQ0E7QUFVQTs7Ozs7OztBQU9BO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUF4QkE7QUEwQkE7Ozs7QUFJQTtBQUNBO0FBWUE7Ozs7Ozs7O0FBUUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBNUJBO0FBOEJBOztBQUVBO0FBQ0E7QUFPQTs7Ozs7O0FBTUE7QUFDQTtBQUVBO0FBQ0E7QUFDQTtBQUVBOzs7O0FBSUE7QUFDQTtBQUNBO0FBRUE7QUFDQTtBQUNBO0FBQUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBbkNBOyIsInNvdXJjZVJvb3QiOiIifQ==\n//# sourceURL=webpack-internal:///./src/core/data.ts\n");

/***/ }),

/***/ "./src/core/utilities.ts":
/*!*******************************!*\
  !*** ./src/core/utilities.ts ***!
  \*******************************/
/*! no static exports found */
/***/ (function(module, exports, __webpack_require__) {

"use strict";
eval("\nObject.defineProperty(exports, \"__esModule\", { value: true });\nfunction getSelectionName(className) {\n    if (typeof (className) === 'number') {\n        return 'n' + className;\n    }\n    if (!className) {\n        return '';\n    }\n    if (className.length > 0 && !isNaN(Number(className[0]))) {\n        className = 'z' + className;\n    }\n    className = className.replace(/[\\*\\%\\#\\[\\]\\/\\>\\<\\s\\+\\(\\)\\;\\@\\:\\?\\\"=.,]/g, '-');\n    return className;\n}\nexports.getSelectionName = getSelectionName;\nfunction removeFromList(value, arr) {\n    if (value) {\n        let index = arr.indexOf(value);\n        if (index !== -1) {\n            arr.splice(index, 1);\n        }\n    }\n}\nexports.removeFromList = removeFromList;\n/** taken from d3-array */\nfunction ascending(a, b) {\n    return a < b ? -1 : a > b ? 1 : a >= b ? 0 : NaN;\n}\n/** taken from d3-array */\nfunction ascendingComparator(f) {\n    return function (d, x) {\n        return ascending(f(d), x);\n    };\n}\n/** modified from d3-array */\nfunction bisect(compare) {\n    if (!compare)\n        compare = ascending;\n    if (compare.length === 1)\n        compare = ascendingComparator(compare);\n    return {\n        left: function (a, x, lo, hi) {\n            if (lo == null)\n                lo = 0;\n            if (hi == null)\n                hi = a.length;\n            while (lo < hi) {\n                var mid = lo + hi >>> 1;\n                if (compare(a[mid], x) < 0)\n                    lo = mid + 1;\n                else\n                    hi = mid;\n            }\n            return lo;\n        },\n        right: function (a, x, lo, hi) {\n            if (lo == null)\n                lo = 0;\n            if (hi == null)\n                hi = a.length;\n            while (lo < hi) {\n                var mid = lo + hi >>> 1;\n                if (compare(a[mid], x) > 0)\n                    hi = mid;\n                else\n                    lo = mid + 1;\n            }\n            return lo;\n        }\n    };\n}\nexports.bisect = bisect;\n/** puts all raw data into buckets based on thresholds and values */\nfunction bucketData(values, thresholds, accessor) {\n    let findRight = bisect().right;\n    let buckets = [];\n    // need one less bucket than thresholds\n    for (let i = 0; i < thresholds.length - 1; ++i) {\n        buckets[i] = [];\n    }\n    let min = thresholds[0];\n    let max = thresholds[thresholds.length - 1];\n    let usedThresholds = thresholds.slice(1);\n    for (let i = 0; i < values.length; ++i) {\n        let compareValue = accessor(values[i]);\n        if (compareValue < min || compareValue > max) {\n            continue;\n        }\n        let valueIdx = findRight(usedThresholds, compareValue);\n        buckets[valueIdx].push(values[i]);\n    }\n    // name the return buckets\n    let ret = {};\n    for (let i = 0; i < thresholds.length - 1; ++i) {\n        let bucketName = thresholds[i] + '-' + thresholds[i + 1];\n        ret[bucketName] = buckets[i];\n    }\n    return ret;\n}\nexports.bucketData = bucketData;\nfunction copy(obj) {\n    let ret = {};\n    for (let key in obj) {\n        ret[key] = obj[key];\n    }\n    return ret;\n}\nexports.copy = copy;\nfunction merge(obj1, obj2) {\n    for (let key in obj2) {\n        obj1[key] = obj2[key];\n    }\n}\nexports.merge = merge;\nfunction convertTraceToTrees(input) {\n    let roots = [];\n    let stack = []; // used to represent the current stack state\n    let nodeStack = []; // used to represent the current stack state\n    for (let i = 0; i < input.length; i++) {\n        let value = input[i];\n        let parent = stack[stack.length - 1];\n        // pop stuff off the stack\n        while (stack.length && value.x > parent.x + parent.dx) {\n            --stack.length;\n            --nodeStack.length;\n            parent = stack[stack.length - 1];\n        }\n        let parentNode = nodeStack[nodeStack.length - 1];\n        let node = {\n            key: value.key,\n            value: value.dx,\n            children: [],\n            parent: parentNode\n        };\n        if (value.name) {\n            node.name = value.name;\n        }\n        if (parentNode) {\n            parentNode.children.push(node);\n        }\n        else {\n            roots.push(node);\n        }\n        stack.push(value);\n        nodeStack.push(node);\n    }\n    return roots;\n}\nexports.convertTraceToTrees = convertTraceToTrees;\nclass SimpleBuffer {\n    constructor(data) {\n        if (data) {\n            this._data = data;\n        }\n        else {\n            this._data = [];\n        }\n    }\n    push(d) {\n        this._data.push(d);\n    }\n    get(index) {\n        return this._data[index];\n    }\n    length() {\n        return this._data.length;\n    }\n    getData() {\n        return this._data;\n    }\n}\nexports.SimpleBuffer = SimpleBuffer;\nclass RingBuffer {\n    constructor(size) {\n        this._data = new Array(size);\n        this._startIdx = 0;\n        this._count = 0;\n        this._isRotating = false;\n    }\n    /** add a new value to the buffer */\n    push(d) {\n        if (this._isRotating) {\n            // the buffer is rotating\n            this._data[this._startIdx] = d;\n            ++this._startIdx;\n            if (this._startIdx === this._count) {\n                this._startIdx = 0;\n            }\n            this._isRotating = true;\n        }\n        else if (this._count === this._data.length - 1) {\n            // here the buffer will start rotating as the buffer is full\n            this._data[this._count] = d;\n            ++this._count;\n            this._isRotating = true;\n        }\n        else {\n            // here the buffer has not been filled yet\n            this._data[this._count] = d;\n            ++this._count;\n        }\n    }\n    /** return the value offset index from the start index\n     * @param index the offset from the start of the buffer\n     */\n    get(index) {\n        if (this._isRotating) {\n            // the buffer is rotating\n            index = index + this._startIdx;\n            if (index >= this._count) {\n                index = index - this._count;\n            }\n        }\n        return this._data[index];\n    }\n    /** get the number of items in the buffer */\n    length() {\n        return this._count;\n    }\n    getData() {\n        if (this._isRotating) {\n            // the buffer is rotating\n            let ret = [];\n            for (let i = this._startIdx; i < this._data.length; ++i) {\n                ret.push(this._data[i]);\n            }\n            for (let i = 0; i < this._startIdx; ++i) {\n                ret.push(this._data[i]);\n            }\n            return ret;\n        }\n        return this._data;\n    }\n}\nexports.RingBuffer = RingBuffer;\nfunction bisectBuffer(compare) {\n    if (!compare)\n        compare = ascending;\n    if (compare.length === 1)\n        compare = ascendingComparator(compare);\n    return {\n        left: function (a, x, lo, hi) {\n            if (lo == null)\n                lo = 0;\n            if (hi == null)\n                hi = a.length();\n            while (lo < hi) {\n                var mid = lo + hi >>> 1;\n                if (compare(a.get(mid), x) < 0)\n                    lo = mid + 1;\n                else\n                    hi = mid;\n            }\n            return lo;\n        },\n        right: function (a, x, lo, hi) {\n            if (lo == null)\n                lo = 0;\n            if (hi == null)\n                hi = a.length();\n            while (lo < hi) {\n                var mid = lo + hi >>> 1;\n                if (compare(a.get(mid), x) > 0)\n                    hi = mid;\n                else\n                    lo = mid + 1;\n            }\n            return lo;\n        }\n    };\n}\nexports.bisectBuffer = bisectBuffer;\nfunction transposeKeys(data) {\n    // this is used to map the keys to their indicies in the output summary data\n    let keyIdxMapping = {};\n    function transposeHelper(output, parentKeys, value, level) {\n        let myKeys = [];\n        for (let i = 0; i < parentKeys.length; ++i) {\n            myKeys[i] = parentKeys[i];\n        }\n        myKeys.push(value.key);\n        if (Array.isArray(value.data)) {\n            for (let i = 0; i < value.data.length; ++i) {\n                transposeHelper(output, myKeys, value.data[i], level + 1);\n            }\n        }\n        else {\n            let currSummaryArray = output;\n            for (let keyIdx = myKeys.length - 1; keyIdx >= 0; --keyIdx) {\n                let key = myKeys[keyIdx];\n                let dataIdx;\n                if (!keyIdxMapping.hasOwnProperty(key)) {\n                    dataIdx = currSummaryArray.length;\n                    keyIdxMapping[key] = dataIdx;\n                }\n                else {\n                    dataIdx = keyIdxMapping[key];\n                }\n                // create the summary data if it doesn't exist yet\n                if (!currSummaryArray[dataIdx]) {\n                    currSummaryArray[dataIdx] = { key: key, data: [] };\n                }\n                // if we are the leaf add the data, else just move to the next level\n                if (keyIdx === 0) {\n                    currSummaryArray[dataIdx].data = value.data;\n                }\n                else {\n                    currSummaryArray = currSummaryArray[dataIdx].data;\n                }\n            }\n        }\n    }\n    let output = [];\n    for (let i = 0; i < data.length; ++i) {\n        transposeHelper(output, [], data[i], 0);\n    }\n    return output;\n}\nexports.transposeKeys = transposeKeys;\nfunction runFunctionOnLeaf(node, func) {\n    if (node && node.children && node.children.length > 0) {\n        for (let i = 0; i < node.children.length; ++i) {\n            runFunctionOnLeaf(node.children[i], func);\n        }\n    }\n    else {\n        func(node);\n    }\n}\nexports.runFunctionOnLeaf = runFunctionOnLeaf;\nfunction isOverlapping(rect1, rect2) {\n    return rect1.x <= rect2.right && rect1.right >= rect2.x &&\n        rect1.y <= rect2.bottom && rect1.bottom >= rect2.y;\n}\nexports.isOverlapping = isOverlapping;\n//# sourceURL=[module]\n//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiLi9zcmMvY29yZS91dGlsaXRpZXMudHMuanMiLCJzb3VyY2VzIjpbIndlYnBhY2s6Ly9VV1QvLi9zcmMvY29yZS91dGlsaXRpZXMudHM/NmNhNCJdLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBJVHJlZU5vZGUsIElUcmFjZVZhbHVlLCBJU3VtbWFyeVZhbHVlIH0gZnJvbSAnLi4vaW50ZXJmYWNlL2NoYXJ0L3Nlcmllcy1kYXRhJztcbmltcG9ydCB7IElCdWZmZXIsIElDaGVja2JveFRyZWVOb2RlLCBJUmVjdCB9IGZyb20gJy4uL2ludGVyZmFjZS91aS1iYXNlJztcblxuZXhwb3J0IGZ1bmN0aW9uIGdldFNlbGVjdGlvbk5hbWUoY2xhc3NOYW1lOiBzdHJpbmcpIHtcbiAgICBpZiAodHlwZW9mIChjbGFzc05hbWUpID09PSAnbnVtYmVyJykge1xuICAgICAgICByZXR1cm4gJ24nICsgY2xhc3NOYW1lO1xuICAgIH1cbiAgICBpZiAoIWNsYXNzTmFtZSkge1xuICAgICAgICByZXR1cm4gJyc7XG4gICAgfVxuICAgIGlmIChjbGFzc05hbWUubGVuZ3RoID4gMCAmJiAhaXNOYU4oTnVtYmVyKGNsYXNzTmFtZVswXSkpKSB7XG4gICAgICAgIGNsYXNzTmFtZSA9ICd6JyArIGNsYXNzTmFtZTtcbiAgICB9XG4gICAgY2xhc3NOYW1lID0gY2xhc3NOYW1lLnJlcGxhY2UoL1tcXCpcXCVcXCNcXFtcXF1cXC9cXD5cXDxcXHNcXCtcXChcXClcXDtcXEBcXDpcXD9cXFwiPS4sXS9nLCAnLScpO1xuICAgIHJldHVybiBjbGFzc05hbWU7XG59XG5cbmV4cG9ydCBmdW5jdGlvbiByZW1vdmVGcm9tTGlzdCh2YWx1ZTogYW55LCBhcnI6IGFueVtdKSB7XG4gICAgaWYgKHZhbHVlKSB7XG4gICAgICAgIGxldCBpbmRleCA9IGFyci5pbmRleE9mKHZhbHVlKTtcbiAgICAgICAgaWYgKGluZGV4ICE9PSAtMSkge1xuICAgICAgICAgICAgYXJyLnNwbGljZShpbmRleCwgMSk7XG4gICAgICAgIH1cbiAgICB9XG59XG5cbi8qKiB0YWtlbiBmcm9tIGQzLWFycmF5ICovXG5mdW5jdGlvbiBhc2NlbmRpbmcoYTogYW55LCBiOiBhbnkpOiBudW1iZXIge1xuICAgIHJldHVybiBhIDwgYiA/IC0xIDogYSA+IGIgPyAxIDogYSA+PSBiID8gMCA6IE5hTjtcbn1cblxuLyoqIHRha2VuIGZyb20gZDMtYXJyYXkgKi9cbmZ1bmN0aW9uIGFzY2VuZGluZ0NvbXBhcmF0b3IoZjogKGQ6IGFueSkgPT4gbnVtYmVyKTogKGE6IGFueSwgYjogYW55KSA9PiBudW1iZXIge1xuICAgIHJldHVybiBmdW5jdGlvbiAoZDogYW55LCB4OiBhbnkpOiBudW1iZXIge1xuICAgICAgICByZXR1cm4gYXNjZW5kaW5nKGYoZCksIHgpO1xuICAgIH07XG59XG5cbi8qKiBtb2RpZmllZCBmcm9tIGQzLWFycmF5ICovXG5leHBvcnQgZnVuY3Rpb24gYmlzZWN0KGNvbXBhcmU/OiBhbnkpOiBhbnkge1xuICAgIGlmICghY29tcGFyZSkgY29tcGFyZSA9IGFzY2VuZGluZztcbiAgICBpZiAoY29tcGFyZS5sZW5ndGggPT09IDEpIGNvbXBhcmUgPSBhc2NlbmRpbmdDb21wYXJhdG9yKGNvbXBhcmUpO1xuICAgIHJldHVybiB7XG4gICAgICAgIGxlZnQ6IGZ1bmN0aW9uIChhOiBhbnlbXSwgeDogYW55LCBsbzogbnVtYmVyLCBoaTogbnVtYmVyKSB7XG4gICAgICAgICAgICBpZiAobG8gPT0gbnVsbCkgbG8gPSAwO1xuICAgICAgICAgICAgaWYgKGhpID09IG51bGwpIGhpID0gYS5sZW5ndGg7XG4gICAgICAgICAgICB3aGlsZSAobG8gPCBoaSkge1xuICAgICAgICAgICAgICAgIHZhciBtaWQgPSBsbyArIGhpID4+PiAxO1xuICAgICAgICAgICAgICAgIGlmIChjb21wYXJlKGFbbWlkXSwgeCkgPCAwKSBsbyA9IG1pZCArIDE7XG4gICAgICAgICAgICAgICAgZWxzZSBoaSA9IG1pZDtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHJldHVybiBsbztcbiAgICAgICAgfSxcbiAgICAgICAgcmlnaHQ6IGZ1bmN0aW9uIChhOiBhbnlbXSwgeDogbnVtYmVyLCBsbzogbnVtYmVyLCBoaTogbnVtYmVyKSB7XG4gICAgICAgICAgICBpZiAobG8gPT0gbnVsbCkgbG8gPSAwO1xuICAgICAgICAgICAgaWYgKGhpID09IG51bGwpIGhpID0gYS5sZW5ndGg7XG4gICAgICAgICAgICB3aGlsZSAobG8gPCBoaSkge1xuICAgICAgICAgICAgICAgIHZhciBtaWQgPSBsbyArIGhpID4+PiAxO1xuICAgICAgICAgICAgICAgIGlmIChjb21wYXJlKGFbbWlkXSwgeCkgPiAwKSBoaSA9IG1pZDtcbiAgICAgICAgICAgICAgICBlbHNlIGxvID0gbWlkICsgMTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHJldHVybiBsbztcbiAgICAgICAgfVxuICAgIH07XG59XG5cbi8qKiBwdXRzIGFsbCByYXcgZGF0YSBpbnRvIGJ1Y2tldHMgYmFzZWQgb24gdGhyZXNob2xkcyBhbmQgdmFsdWVzICovXG5leHBvcnQgZnVuY3Rpb24gYnVja2V0RGF0YSh2YWx1ZXM6IGFueVtdLCB0aHJlc2hvbGRzOiBudW1iZXJbXSxcbiAgICBhY2Nlc3NvcjogKGQ6IGFueSkgPT4gbnVtYmVyKTogeyBbaW5kZXg6IHN0cmluZ106IGFueVtdIH0ge1xuXG4gICAgbGV0IGZpbmRSaWdodCA9IGJpc2VjdCgpLnJpZ2h0O1xuXG4gICAgbGV0IGJ1Y2tldHM6IGFueVtdW10gPSBbXTtcbiAgICAvLyBuZWVkIG9uZSBsZXNzIGJ1Y2tldCB0aGFuIHRocmVzaG9sZHNcbiAgICBmb3IgKGxldCBpID0gMDsgaSA8IHRocmVzaG9sZHMubGVuZ3RoIC0gMTsgKytpKSB7XG4gICAgICAgIGJ1Y2tldHNbaV0gPSBbXTtcbiAgICB9XG5cbiAgICBsZXQgbWluID0gdGhyZXNob2xkc1swXTtcbiAgICBsZXQgbWF4ID0gdGhyZXNob2xkc1t0aHJlc2hvbGRzLmxlbmd0aCAtIDFdO1xuXG4gICAgbGV0IHVzZWRUaHJlc2hvbGRzID0gdGhyZXNob2xkcy5zbGljZSgxKTtcbiAgICBmb3IgKGxldCBpID0gMDsgaSA8IHZhbHVlcy5sZW5ndGg7ICsraSkge1xuICAgICAgICBsZXQgY29tcGFyZVZhbHVlID0gYWNjZXNzb3IodmFsdWVzW2ldKTtcbiAgICAgICAgaWYgKGNvbXBhcmVWYWx1ZSA8IG1pbiB8fCBjb21wYXJlVmFsdWUgPiBtYXgpIHtcbiAgICAgICAgICAgIGNvbnRpbnVlO1xuICAgICAgICB9XG5cbiAgICAgICAgbGV0IHZhbHVlSWR4ID0gZmluZFJpZ2h0KHVzZWRUaHJlc2hvbGRzLCBjb21wYXJlVmFsdWUpO1xuICAgICAgICBidWNrZXRzW3ZhbHVlSWR4XS5wdXNoKHZhbHVlc1tpXSk7XG4gICAgfVxuXG4gICAgLy8gbmFtZSB0aGUgcmV0dXJuIGJ1Y2tldHNcbiAgICBsZXQgcmV0OiB7IFtpbmRleDogc3RyaW5nXTogYW55W10gfSA9IHt9O1xuICAgIGZvciAobGV0IGkgPSAwOyBpIDwgdGhyZXNob2xkcy5sZW5ndGggLSAxOyArK2kpIHtcbiAgICAgICAgbGV0IGJ1Y2tldE5hbWU6IHN0cmluZyA9IHRocmVzaG9sZHNbaV0gKyAnLScgKyB0aHJlc2hvbGRzW2kgKyAxXTtcbiAgICAgICAgcmV0W2J1Y2tldE5hbWVdID0gYnVja2V0c1tpXTtcbiAgICB9XG5cbiAgICByZXR1cm4gcmV0O1xufVxuXG5leHBvcnQgZnVuY3Rpb24gY29weShvYmo6IGFueSk6IE9iamVjdCB7XG4gICAgbGV0IHJldDogYW55ID0ge307XG4gICAgZm9yIChsZXQga2V5IGluIG9iaikge1xuICAgICAgICByZXRba2V5XSA9IG9ialtrZXldO1xuICAgIH1cbiAgICByZXR1cm4gcmV0O1xufVxuZXhwb3J0IGZ1bmN0aW9uIG1lcmdlKG9iajE6IGFueSwgb2JqMjogYW55KTogdm9pZCB7XG4gICAgZm9yIChsZXQga2V5IGluIG9iajIpIHtcbiAgICAgICAgb2JqMVtrZXldID0gb2JqMltrZXldO1xuICAgIH1cbn1cblxuZXhwb3J0IGZ1bmN0aW9uIGNvbnZlcnRUcmFjZVRvVHJlZXMoaW5wdXQ6IElUcmFjZVZhbHVlW10pOiBJVHJlZU5vZGVbXSB7XG4gICAgbGV0IHJvb3RzOiBJVHJlZU5vZGVbXSA9IFtdO1xuXG4gICAgbGV0IHN0YWNrOiBJVHJhY2VWYWx1ZVtdID0gW107IC8vIHVzZWQgdG8gcmVwcmVzZW50IHRoZSBjdXJyZW50IHN0YWNrIHN0YXRlXG4gICAgbGV0IG5vZGVTdGFjazogSVRyZWVOb2RlW10gPSBbXTsgLy8gdXNlZCB0byByZXByZXNlbnQgdGhlIGN1cnJlbnQgc3RhY2sgc3RhdGVcbiAgICBmb3IgKGxldCBpID0gMDsgaSA8IGlucHV0Lmxlbmd0aDsgaSsrKSB7XG4gICAgICAgIGxldCB2YWx1ZSA9IGlucHV0W2ldO1xuICAgICAgICBsZXQgcGFyZW50ID0gc3RhY2tbc3RhY2subGVuZ3RoIC0gMV07XG5cbiAgICAgICAgLy8gcG9wIHN0dWZmIG9mZiB0aGUgc3RhY2tcbiAgICAgICAgd2hpbGUgKHN0YWNrLmxlbmd0aCAmJiB2YWx1ZS54ID4gcGFyZW50LnggKyBwYXJlbnQuZHgpIHtcbiAgICAgICAgICAgIC0tc3RhY2subGVuZ3RoO1xuICAgICAgICAgICAgLS1ub2RlU3RhY2subGVuZ3RoO1xuICAgICAgICAgICAgcGFyZW50ID0gc3RhY2tbc3RhY2subGVuZ3RoIC0gMV07XG4gICAgICAgIH1cblxuICAgICAgICBsZXQgcGFyZW50Tm9kZSA9IG5vZGVTdGFja1tub2RlU3RhY2subGVuZ3RoIC0gMV07XG4gICAgICAgIGxldCBub2RlOiBJVHJlZU5vZGUgPSB7XG4gICAgICAgICAgICBrZXk6IHZhbHVlLmtleSxcbiAgICAgICAgICAgIHZhbHVlOiB2YWx1ZS5keCxcbiAgICAgICAgICAgIGNoaWxkcmVuOiBbXSxcbiAgICAgICAgICAgIHBhcmVudDogcGFyZW50Tm9kZVxuICAgICAgICB9O1xuXG4gICAgICAgIGlmICh2YWx1ZS5uYW1lKSB7XG4gICAgICAgICAgICBub2RlLm5hbWUgPSB2YWx1ZS5uYW1lO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKHBhcmVudE5vZGUpIHtcbiAgICAgICAgICAgIHBhcmVudE5vZGUuY2hpbGRyZW4ucHVzaChub2RlKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIHJvb3RzLnB1c2gobm9kZSk7XG4gICAgICAgIH1cblxuICAgICAgICBzdGFjay5wdXNoKHZhbHVlKTtcbiAgICAgICAgbm9kZVN0YWNrLnB1c2gobm9kZSk7XG4gICAgfVxuXG4gICAgcmV0dXJuIHJvb3RzO1xufVxuXG5leHBvcnQgY2xhc3MgU2ltcGxlQnVmZmVyPERhdGFUeXBlPiBpbXBsZW1lbnRzIElCdWZmZXI8RGF0YVR5cGU+IHtcbiAgICBwcml2YXRlIF9kYXRhOiBEYXRhVHlwZVtdO1xuXG4gICAgY29uc3RydWN0b3IoZGF0YT86IERhdGFUeXBlW10pIHtcbiAgICAgICAgaWYgKGRhdGEpIHtcbiAgICAgICAgICAgIHRoaXMuX2RhdGEgPSBkYXRhO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgdGhpcy5fZGF0YSA9IFtdO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgcHVibGljIHB1c2goZDogRGF0YVR5cGUpIHtcbiAgICAgICAgdGhpcy5fZGF0YS5wdXNoKGQpO1xuICAgIH1cblxuICAgIHB1YmxpYyBnZXQoaW5kZXg6IG51bWJlcik6IERhdGFUeXBlIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuX2RhdGFbaW5kZXhdO1xuICAgIH1cblxuICAgIHB1YmxpYyBsZW5ndGgoKTogbnVtYmVyIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuX2RhdGEubGVuZ3RoO1xuICAgIH1cblxuICAgIHB1YmxpYyBnZXREYXRhKCk6IERhdGFUeXBlW10ge1xuICAgICAgICByZXR1cm4gdGhpcy5fZGF0YTtcbiAgICB9XG59XG5cbmV4cG9ydCBjbGFzcyBSaW5nQnVmZmVyPERhdGFUeXBlPiBpbXBsZW1lbnRzIElCdWZmZXI8RGF0YVR5cGU+IHtcbiAgICBwcml2YXRlIF9kYXRhOiBEYXRhVHlwZVtdO1xuICAgIHByaXZhdGUgX3N0YXJ0SWR4OiBudW1iZXI7XG4gICAgcHJpdmF0ZSBfY291bnQ6IG51bWJlcjtcbiAgICBwcml2YXRlIF9pc1JvdGF0aW5nOiBib29sZWFuO1xuXG4gICAgY29uc3RydWN0b3Ioc2l6ZTogbnVtYmVyKSB7XG4gICAgICAgIHRoaXMuX2RhdGEgPSBuZXcgQXJyYXkoc2l6ZSk7XG4gICAgICAgIHRoaXMuX3N0YXJ0SWR4ID0gMDtcbiAgICAgICAgdGhpcy5fY291bnQgPSAwO1xuICAgICAgICB0aGlzLl9pc1JvdGF0aW5nID0gZmFsc2U7XG4gICAgfVxuXG4gICAgLyoqIGFkZCBhIG5ldyB2YWx1ZSB0byB0aGUgYnVmZmVyICovXG4gICAgcHVibGljIHB1c2goZDogRGF0YVR5cGUpIHtcbiAgICAgICAgaWYgKHRoaXMuX2lzUm90YXRpbmcpIHtcbiAgICAgICAgICAgIC8vIHRoZSBidWZmZXIgaXMgcm90YXRpbmdcbiAgICAgICAgICAgIHRoaXMuX2RhdGFbdGhpcy5fc3RhcnRJZHhdID0gZDtcbiAgICAgICAgICAgICsrdGhpcy5fc3RhcnRJZHg7XG5cbiAgICAgICAgICAgIGlmICh0aGlzLl9zdGFydElkeCA9PT0gdGhpcy5fY291bnQpIHtcbiAgICAgICAgICAgICAgICB0aGlzLl9zdGFydElkeCA9IDA7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIHRoaXMuX2lzUm90YXRpbmcgPSB0cnVlO1xuICAgICAgICB9IGVsc2UgaWYgKHRoaXMuX2NvdW50ID09PSB0aGlzLl9kYXRhLmxlbmd0aCAtIDEpIHtcbiAgICAgICAgICAgIC8vIGhlcmUgdGhlIGJ1ZmZlciB3aWxsIHN0YXJ0IHJvdGF0aW5nIGFzIHRoZSBidWZmZXIgaXMgZnVsbFxuICAgICAgICAgICAgdGhpcy5fZGF0YVt0aGlzLl9jb3VudF0gPSBkO1xuICAgICAgICAgICAgKyt0aGlzLl9jb3VudDtcbiAgICAgICAgICAgIHRoaXMuX2lzUm90YXRpbmcgPSB0cnVlO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgLy8gaGVyZSB0aGUgYnVmZmVyIGhhcyBub3QgYmVlbiBmaWxsZWQgeWV0XG4gICAgICAgICAgICB0aGlzLl9kYXRhW3RoaXMuX2NvdW50XSA9IGQ7XG4gICAgICAgICAgICArK3RoaXMuX2NvdW50O1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgLyoqIHJldHVybiB0aGUgdmFsdWUgb2Zmc2V0IGluZGV4IGZyb20gdGhlIHN0YXJ0IGluZGV4XG4gICAgICogQHBhcmFtIGluZGV4IHRoZSBvZmZzZXQgZnJvbSB0aGUgc3RhcnQgb2YgdGhlIGJ1ZmZlclxuICAgICAqL1xuICAgIHB1YmxpYyBnZXQoaW5kZXg6IG51bWJlcik6IERhdGFUeXBlIHtcbiAgICAgICAgaWYgKHRoaXMuX2lzUm90YXRpbmcpIHtcbiAgICAgICAgICAgIC8vIHRoZSBidWZmZXIgaXMgcm90YXRpbmdcbiAgICAgICAgICAgIGluZGV4ID0gaW5kZXggKyB0aGlzLl9zdGFydElkeDtcbiAgICAgICAgICAgIGlmIChpbmRleCA+PSB0aGlzLl9jb3VudCkge1xuICAgICAgICAgICAgICAgIGluZGV4ID0gaW5kZXggLSB0aGlzLl9jb3VudDtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gdGhpcy5fZGF0YVtpbmRleF07XG4gICAgfVxuXG4gICAgLyoqIGdldCB0aGUgbnVtYmVyIG9mIGl0ZW1zIGluIHRoZSBidWZmZXIgKi9cbiAgICBwdWJsaWMgbGVuZ3RoKCkge1xuICAgICAgICByZXR1cm4gdGhpcy5fY291bnQ7XG4gICAgfVxuXG4gICAgcHVibGljIGdldERhdGEoKTogRGF0YVR5cGVbXSB7XG4gICAgICAgIGlmICh0aGlzLl9pc1JvdGF0aW5nKSB7XG4gICAgICAgICAgICAvLyB0aGUgYnVmZmVyIGlzIHJvdGF0aW5nXG4gICAgICAgICAgICBsZXQgcmV0ID0gW107XG4gICAgICAgICAgICBmb3IgKGxldCBpID0gdGhpcy5fc3RhcnRJZHg7IGkgPCB0aGlzLl9kYXRhLmxlbmd0aDsgKytpKSB7XG4gICAgICAgICAgICAgICAgcmV0LnB1c2godGhpcy5fZGF0YVtpXSk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBmb3IgKGxldCBpID0gMDsgaSA8IHRoaXMuX3N0YXJ0SWR4OyArK2kpIHtcbiAgICAgICAgICAgICAgICByZXQucHVzaCh0aGlzLl9kYXRhW2ldKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHJldHVybiByZXQ7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIHRoaXMuX2RhdGE7XG4gICAgfVxufVxuXG5leHBvcnQgZnVuY3Rpb24gYmlzZWN0QnVmZmVyKGNvbXBhcmU/OiBhbnkpOiBhbnkge1xuICAgIGlmICghY29tcGFyZSkgY29tcGFyZSA9IGFzY2VuZGluZztcbiAgICBpZiAoY29tcGFyZS5sZW5ndGggPT09IDEpIGNvbXBhcmUgPSBhc2NlbmRpbmdDb21wYXJhdG9yKGNvbXBhcmUpO1xuICAgIHJldHVybiB7XG4gICAgICAgIGxlZnQ6IGZ1bmN0aW9uIChhOiBJQnVmZmVyPGFueT4sIHg6IGFueSwgbG86IG51bWJlciwgaGk6IG51bWJlcikge1xuICAgICAgICAgICAgaWYgKGxvID09IG51bGwpIGxvID0gMDtcbiAgICAgICAgICAgIGlmIChoaSA9PSBudWxsKSBoaSA9IGEubGVuZ3RoKCk7XG4gICAgICAgICAgICB3aGlsZSAobG8gPCBoaSkge1xuICAgICAgICAgICAgICAgIHZhciBtaWQgPSBsbyArIGhpID4+PiAxO1xuICAgICAgICAgICAgICAgIGlmIChjb21wYXJlKGEuZ2V0KG1pZCksIHgpIDwgMCkgbG8gPSBtaWQgKyAxO1xuICAgICAgICAgICAgICAgIGVsc2UgaGkgPSBtaWQ7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICByZXR1cm4gbG87XG4gICAgICAgIH0sXG4gICAgICAgIHJpZ2h0OiBmdW5jdGlvbiAoYTogSUJ1ZmZlcjxhbnk+LCB4OiBudW1iZXIsIGxvOiBudW1iZXIsIGhpOiBudW1iZXIpIHtcbiAgICAgICAgICAgIGlmIChsbyA9PSBudWxsKSBsbyA9IDA7XG4gICAgICAgICAgICBpZiAoaGkgPT0gbnVsbCkgaGkgPSBhLmxlbmd0aCgpO1xuICAgICAgICAgICAgd2hpbGUgKGxvIDwgaGkpIHtcbiAgICAgICAgICAgICAgICB2YXIgbWlkID0gbG8gKyBoaSA+Pj4gMTtcbiAgICAgICAgICAgICAgICBpZiAoY29tcGFyZShhLmdldChtaWQpLCB4KSA+IDApIGhpID0gbWlkO1xuICAgICAgICAgICAgICAgIGVsc2UgbG8gPSBtaWQgKyAxO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgcmV0dXJuIGxvO1xuICAgICAgICB9XG4gICAgfTtcbn1cblxuXG5leHBvcnQgZnVuY3Rpb24gdHJhbnNwb3NlS2V5cyhkYXRhOiBJU3VtbWFyeVZhbHVlW10pOiBJU3VtbWFyeVZhbHVlW10ge1xuXG4gICAgLy8gdGhpcyBpcyB1c2VkIHRvIG1hcCB0aGUga2V5cyB0byB0aGVpciBpbmRpY2llcyBpbiB0aGUgb3V0cHV0IHN1bW1hcnkgZGF0YVxuICAgIGxldCBrZXlJZHhNYXBwaW5nOiB7IFtpbmRleDogc3RyaW5nXTogbnVtYmVyIH0gPSB7fTtcblxuICAgIGZ1bmN0aW9uIHRyYW5zcG9zZUhlbHBlcihvdXRwdXQ6IElTdW1tYXJ5VmFsdWVbXSwgcGFyZW50S2V5czogc3RyaW5nW10sXG4gICAgICAgIHZhbHVlOiBJU3VtbWFyeVZhbHVlLCBsZXZlbDogbnVtYmVyKSB7XG5cbiAgICAgICAgbGV0IG15S2V5cyA9IFtdO1xuICAgICAgICBmb3IgKGxldCBpID0gMDsgaSA8IHBhcmVudEtleXMubGVuZ3RoOyArK2kpIHtcbiAgICAgICAgICAgIG15S2V5c1tpXSA9IHBhcmVudEtleXNbaV07XG4gICAgICAgIH1cbiAgICAgICAgbXlLZXlzLnB1c2godmFsdWUua2V5KTtcblxuICAgICAgICBpZiAoQXJyYXkuaXNBcnJheSh2YWx1ZS5kYXRhKSkge1xuICAgICAgICAgICAgZm9yIChsZXQgaSA9IDA7IGkgPCB2YWx1ZS5kYXRhLmxlbmd0aDsgKytpKSB7XG4gICAgICAgICAgICAgICAgdHJhbnNwb3NlSGVscGVyKG91dHB1dCwgbXlLZXlzLCB2YWx1ZS5kYXRhW2ldLCBsZXZlbCArIDEpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgbGV0IGN1cnJTdW1tYXJ5QXJyYXkgPSBvdXRwdXQ7XG4gICAgICAgICAgICBmb3IgKGxldCBrZXlJZHggPSBteUtleXMubGVuZ3RoIC0gMTsga2V5SWR4ID49IDA7IC0ta2V5SWR4KSB7XG4gICAgICAgICAgICAgICAgbGV0IGtleSA9IG15S2V5c1trZXlJZHhdO1xuICAgICAgICAgICAgICAgIGxldCBkYXRhSWR4OiBudW1iZXI7XG4gICAgICAgICAgICAgICAgaWYgKCFrZXlJZHhNYXBwaW5nLmhhc093blByb3BlcnR5KGtleSkpIHtcbiAgICAgICAgICAgICAgICAgICAgZGF0YUlkeCA9IGN1cnJTdW1tYXJ5QXJyYXkubGVuZ3RoO1xuICAgICAgICAgICAgICAgICAgICBrZXlJZHhNYXBwaW5nW2tleV0gPSBkYXRhSWR4O1xuICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgIGRhdGFJZHggPSBrZXlJZHhNYXBwaW5nW2tleV07XG4gICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgLy8gY3JlYXRlIHRoZSBzdW1tYXJ5IGRhdGEgaWYgaXQgZG9lc24ndCBleGlzdCB5ZXRcbiAgICAgICAgICAgICAgICBpZiAoIWN1cnJTdW1tYXJ5QXJyYXlbZGF0YUlkeF0pIHtcbiAgICAgICAgICAgICAgICAgICAgY3VyclN1bW1hcnlBcnJheVtkYXRhSWR4XSA9IHsga2V5OiBrZXksIGRhdGE6IFtdIH07XG4gICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgLy8gaWYgd2UgYXJlIHRoZSBsZWFmIGFkZCB0aGUgZGF0YSwgZWxzZSBqdXN0IG1vdmUgdG8gdGhlIG5leHQgbGV2ZWxcbiAgICAgICAgICAgICAgICBpZiAoa2V5SWR4ID09PSAwKSB7XG4gICAgICAgICAgICAgICAgICAgIGN1cnJTdW1tYXJ5QXJyYXlbZGF0YUlkeF0uZGF0YSA9IHZhbHVlLmRhdGE7XG4gICAgICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgY3VyclN1bW1hcnlBcnJheSA9IGN1cnJTdW1tYXJ5QXJyYXlbZGF0YUlkeF0uZGF0YSBhcyBJU3VtbWFyeVZhbHVlW107XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgfVxuXG4gICAgbGV0IG91dHB1dDogSVN1bW1hcnlWYWx1ZVtdID0gW107XG4gICAgZm9yIChsZXQgaSA9IDA7IGkgPCBkYXRhLmxlbmd0aDsgKytpKSB7XG4gICAgICAgIHRyYW5zcG9zZUhlbHBlcihvdXRwdXQsIFtdLCBkYXRhW2ldLCAwKTtcbiAgICB9XG4gICAgcmV0dXJuIG91dHB1dDtcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIHJ1bkZ1bmN0aW9uT25MZWFmKG5vZGU6IElDaGVja2JveFRyZWVOb2RlLFxuICAgIGZ1bmM6IChsZWFmTm9kZTogSUNoZWNrYm94VHJlZU5vZGUpID0+IHZvaWRcbikge1xuICAgIGlmIChub2RlICYmIG5vZGUuY2hpbGRyZW4gJiYgbm9kZS5jaGlsZHJlbi5sZW5ndGggPiAwKSB7XG4gICAgICAgIGZvciAobGV0IGkgPSAwOyBpIDwgbm9kZS5jaGlsZHJlbi5sZW5ndGg7ICsraSkge1xuICAgICAgICAgICAgcnVuRnVuY3Rpb25PbkxlYWYobm9kZS5jaGlsZHJlbltpXSwgZnVuYyk7XG4gICAgICAgIH1cbiAgICB9IGVsc2Uge1xuICAgICAgICBmdW5jKG5vZGUpO1xuICAgIH1cbn1cblxuZXhwb3J0IGZ1bmN0aW9uIGlzT3ZlcmxhcHBpbmcocmVjdDE6IElSZWN0LCByZWN0MjogSVJlY3QpIHtcbiAgICByZXR1cm4gcmVjdDEueCA8PSByZWN0Mi5yaWdodCAmJiByZWN0MS5yaWdodCA+PSByZWN0Mi54ICYmXG4gICAgICAgIHJlY3QxLnkgPD0gcmVjdDIuYm90dG9tICYmIHJlY3QxLmJvdHRvbSA+PSByZWN0Mi55O1xufVxuIl0sIm1hcHBpbmdzIjoiOztBQUdBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBWkE7QUFjQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBUEE7QUFTQTtBQUNBO0FBQ0E7QUFDQTtBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUVBO0FBQ0E7QUFDQTtBQUFBO0FBQ0E7QUFBQTtBQUNBO0FBQ0E7QUFDQTtBQUFBO0FBQ0E7QUFBQTtBQUNBO0FBQ0E7QUFDQTtBQUFBOztBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUFBO0FBQ0E7QUFBQTtBQUNBO0FBQ0E7QUFDQTtBQUFBOztBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQXpCQTtBQTJCQTtBQUNBO0FBR0E7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBRUE7QUFDQTtBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUVBO0FBQ0E7QUFDQTtBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUVBO0FBQ0E7QUFqQ0E7QUFtQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFOQTtBQU9BO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFKQTtBQU1BO0FBQ0E7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFFQTtBQUNBO0FBQ0E7QUFFQTtBQUNBO0FBQ0E7QUFBQTtBQUNBO0FBQ0E7QUFFQTtBQUNBO0FBQ0E7QUFFQTtBQUNBO0FBdkNBO0FBeUNBO0FBR0E7QUFDQTtBQUNBO0FBQ0E7QUFBQTtBQUNBO0FBQ0E7QUFDQTtBQUVBO0FBQ0E7QUFDQTtBQUVBO0FBQ0E7QUFDQTtBQUVBO0FBQ0E7QUFDQTtBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBMUJBO0FBNEJBO0FBTUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBRUE7QUFDQTtBQUNBO0FBRUE7QUFDQTtBQUFBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUFBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQXRFQTtBQXdFQTtBQUNBO0FBQUE7QUFDQTtBQUFBO0FBQ0E7QUFDQTtBQUNBO0FBQUE7QUFDQTtBQUFBO0FBQ0E7QUFDQTtBQUNBO0FBQUE7O0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQUE7QUFDQTtBQUFBO0FBQ0E7QUFDQTtBQUNBO0FBQUE7O0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBekJBO0FBNEJBO0FBRUE7QUFDQTtBQUVBO0FBR0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFBQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFBQTtBQUNBO0FBQ0E7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBbERBO0FBb0RBO0FBR0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUFBO0FBQ0E7QUFDQTtBQUNBO0FBVkE7QUFZQTtBQUNBO0FBQ0E7QUFDQTtBQUhBOyIsInNvdXJjZVJvb3QiOiIifQ==\n//# sourceURL=webpack-internal:///./src/core/utilities.ts\n");

/***/ }),

/***/ "./src/interface/chart/axis.ts":
/*!*************************************!*\
  !*** ./src/interface/chart/axis.ts ***!
  \*************************************/
/*! no static exports found */
/***/ (function(module, exports, __webpack_require__) {

"use strict";
eval("\nObject.defineProperty(exports, \"__esModule\", { value: true });\n/**\n * defines what type of axis scaling to use\n *\n * @enum {number}\n */\nvar AxisType;\n(function (AxisType) {\n    /** continuous axis of data with a linear scale */\n    AxisType[AxisType[\"Linear\"] = 0] = \"Linear\";\n    /** continuous axis of data with a logarithmic (base 10) scale */\n    AxisType[AxisType[\"Logarithmic\"] = 1] = \"Logarithmic\";\n    /** axis of data with discrete values that are enumerated or derived from the data */\n    AxisType[AxisType[\"Ordinal\"] = 2] = \"Ordinal\";\n})(AxisType = exports.AxisType || (exports.AxisType = {})); // enum AxisType\n//# sourceURL=[module]\n//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiLi9zcmMvaW50ZXJmYWNlL2NoYXJ0L2F4aXMudHMuanMiLCJzb3VyY2VzIjpbIndlYnBhY2s6Ly9VV1QvLi9zcmMvaW50ZXJmYWNlL2NoYXJ0L2F4aXMudHM/ZDgzMyJdLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQge1xuICAgIEFsaWdubWVudCwgSUNzcywgSU9wdGlvbnMsIElSYW5nZSwgVUlUeXBlLFxuICAgIFVJRWxlbWVudE1hbmFnZXIsIFVJUmVuZGVyZXIsIFVJRWxlbWVudFxufSBmcm9tICcuLi91aS1iYXNlJztcblxuZXhwb3J0IGludGVyZmFjZSBJU2NhbGFyIHtcbiAgICAvKiogdGhlIG11bHRpcGxpZXIgdXNlZCBvbiB0aGUgYmFzZSBzY2FsZSB0byBnZXQgdGhpcyBzY2FsZSAqL1xuICAgIHNjYWxhcjogbnVtYmVyO1xuXG4gICAgLyoqIHRoZSB1bml0cyBmb3IgdGhpcyBzY2FsZSAqL1xuICAgIHVuaXRzOiBzdHJpbmc7XG5cbiAgICAvKiogdGhlIG1heGltdW0gcmFuZ2UgZm9yIHRoaXMgc2NhbGUuICBGb3IgZXhhbXBsZSBpZiB0aGlzIGlzIC4xLFxuICAgICAqIGFueSB2YWx1ZSBhYm92ZSAuMSB3aWxsIHVzZSB0aGUgbmV4dCBzY2FsZSBhbmQgYW55IHZhbHVlIGJlbG93IC4xXG4gICAgICogd2lsbCB1c2UgdGhpcyBzY2FsZSAodW50aWwgdGhlIG5leHQgbG93ZXIgc2NhbGUpXG4gICAgKi9cbiAgICBtYXhSYW5nZTogbnVtYmVyO1xufVxuXG5leHBvcnQgaW50ZXJmYWNlIElTY2FsaW5nSW5mbyB7XG4gICAgLyoqIHRoZSBiYXNlIHNjYWxlIGZvciB0aGUgYXhpcyAqL1xuICAgIGJhc2VTY2FsZTogSVNjYWxhcjtcblxuICAgIC8qKiB0aGUgbGlzdCBvZiBzY2FsYXJzIGZvciB0aGUgYXhpcyAqL1xuICAgIHNjYWxhcnM/OiBJU2NhbGFyW107XG59XG5cbi8qKlxuICogZGVmaW5lcyB3aGF0IHR5cGUgb2YgYXhpcyBzY2FsaW5nIHRvIHVzZVxuICpcbiAqIEBlbnVtIHtudW1iZXJ9XG4gKi9cbmV4cG9ydCBlbnVtIEF4aXNUeXBlIHtcbiAgICAvKiogY29udGludW91cyBheGlzIG9mIGRhdGEgd2l0aCBhIGxpbmVhciBzY2FsZSAqL1xuICAgIExpbmVhcixcbiAgICAvKiogY29udGludW91cyBheGlzIG9mIGRhdGEgd2l0aCBhIGxvZ2FyaXRobWljIChiYXNlIDEwKSBzY2FsZSAqL1xuICAgIExvZ2FyaXRobWljLFxuICAgIC8qKiBheGlzIG9mIGRhdGEgd2l0aCBkaXNjcmV0ZSB2YWx1ZXMgdGhhdCBhcmUgZW51bWVyYXRlZCBvciBkZXJpdmVkIGZyb20gdGhlIGRhdGEgKi9cbiAgICBPcmRpbmFsXG59ICAgLy8gZW51bSBBeGlzVHlwZVxuXG5cbi8qKiBpbnRlcmZhY2UgdGhhdCBkZXNjcmliZXMgdGhlIGRhdGEgcmVwcmVzZW50ZWQgaW4gYW4gYXhpcyAqL1xuZXhwb3J0IGludGVyZmFjZSBJQXhpc0Rlc2NyaXB0aW9uIHtcbiAgICBzY2FsZVR5cGU6IEF4aXNUeXBlO1xuICAgIC8qKiB3aGF0IHNjYWxpbmcgYW5kIHRleHQgdG8gc2hvdyBmb3IgdGhlIHVuaXRzICovXG4gICAgc2NhbGluZ0luZm8/OiBJU2NhbGluZ0luZm87XG4gICAgLyoqIGhvdyBtYW55IGRlY2ltYWxzIHRvIHNob3cgZm9yIHRoZSB1bml0cyAqL1xuICAgIHByZWNpc2lvbj86IG51bWJlcjtcbiAgICAvKiogdGV4dCB0byBkZWZpbmUgd2hhdCB0aGlzIGF4aXMgcmVwcmVzZW50cyAqL1xuICAgIGxhYmVsPzogc3RyaW5nO1xuICAgIC8qKiAgdXNlZCBmb3IgdGhlIE9yZGluYWwgc2NhbGluZyB0eXBlIHRvIGRlZmluZSB0aGUga2V5cyAqL1xuICAgIGtleXM/OiBhbnlbXTtcbiAgICAvKiogdXNlZCBmb3IgYSBjb250aW51b3VzIGF4aXMgdG8gZGVmaW5lIHdoYXQgcmFuZ2UgdGhlIGF4aXMgc2hvdWxkIHNob3cgKi9cbiAgICByYW5nZT86IElSYW5nZTtcbn1cblxuLyoqIG9wdGlvbnMgdG8gcGFzcyB0byB0aGUgYXhpcyB0byBjaGFuZ2UgaG93IGl0IGlzIHJlbmRlcmVkICovXG5leHBvcnQgaW50ZXJmYWNlIElBeGlzT3B0aW9ucyBleHRlbmRzIElPcHRpb25zIHtcbiAgICAvKiogY2hhbmdlIHRoZSBudW1iZXIgb2YgdGlja3MgdG8gc2hvdyBvbiB0aGlzIGF4aXMgd2hlbiByZW5kZXJpbmcgKi9cbiAgICB0aWNrQ291bnQ/OiBudW1iZXI7XG4gICAgLyoqIGNoYW5nZSB0aGUgc2l6ZSBvZiB0aWNrcyB0aGF0IGFyZSBub3QgdGhlIHR3byBvdXRzaWRlIHRpY2tzICovXG4gICAgdGlja1NpemVJbm5lcj86IG51bWJlcjtcbiAgICAvKiogY2hhbmdlIHRoZSBzaXplIG9mIHRoZSB0d28gb3V0c2lkZSB0aWNrcyAqL1xuICAgIHRpY2tTaXplT3V0ZXI/OiBudW1iZXI7XG4gICAgLyoqIG1hcCB0aWNrIHN0cmluZyB0byBhbm90aGVyIHZhbHVlICovXG4gICAgdGlja01hcHBpbmdGdW5jPzogKHZhbHVlOiBhbnkpID0+IHN0cmluZztcbiAgICAvKiogcm90YXRlIHRoZSB0ZXh0IG9mIHRoZSBheGlzICovXG4gICAgcm90YXRlVGV4dD86IGJvb2xlYW47XG4gICAgLyoqIHBlcmNlbnRhZ2UgdG8gcm90YXRlIHRoZSB0ZXh0IG9mIHRoZSBheGlzICovXG4gICAgcm90YXRlVGV4dERlZ3JlZXM/OiBudW1iZXI7XG4gICAgLyoqIGVuYWJsZSBicnVzaCBzZWxlY3Rpb24gaW4gb3JkaW5hbCBjYXNlIHdoaWNoIGlzIGF0eXBpY2FsICovXG4gICAgZW5hYmxlT3JkaW5hbEJydXNoU2VsZWN0aW9uPzogYm9vbGVhbjtcbiAgICAvKiogdHJ5IHRvIHNldCByYW5nZSBmcm9tIDAgdG8gdGhlIHZhbHVlIGlmIHBvc3NpYmxlICovXG4gICAgZW5hYmxlWmVyb09mZnNldD86IGJvb2xlYW47XG59XG5cbi8qKiB0aGUgY29tYmluYXRpb24gb2YgYXhpcyBkZWZpbml0aW9uIGFuZCByZW5kZXJpbmcgaW5mb3JtYXRpb24gbmVlZGVkXG4gKiB0byByZW5kZXIgdGhpcyBheGlzXG4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgSUF4aXMgZXh0ZW5kcyBVSUVsZW1lbnQge1xuICAgIHJlbmRlcmVyPzogVUlSZW5kZXJlcjtcbiAgICBtYW5hZ2VyPzogVUlFbGVtZW50TWFuYWdlcjtcblxuICAgIC8qKiBkZWZpbmVzIHdoYXQgZGF0YSB0byByZXByZXNlbnQgaW4gdGhlIGF4aXMgKi9cbiAgICBheGlzRGVzYzogSUF4aXNEZXNjcmlwdGlvbjtcbiAgICAvKiogZGVmaW5lcyB3aGV0aGVyIGFuIGF4aXMgaXMgdG9wL2JvdHRvbS9sZWZ0L3JpZ2h0ICovXG4gICAgYWxpZ25tZW50OiBBbGlnbm1lbnQ7XG4gICAgLyoqIHVzZWQgZm9yIFkgYXhpcyBpZiB5b3Ugd2FudCB0aGUgcmFuZ2UgdG8gYXV0b3NjYWxlIGFzIHlvdSB6b29tIGluIGFuZCBvdXQgKi9cbiAgICBlbmFibGVEeW5hbWljUmFuZ2U/OiBib29sZWFuO1xuICAgIC8qKiBhbnkgbWlzYyBvcHRpb25zIHRvIGNvbmZpZ3VyZSB0aGUgYXhpcyAqL1xuICAgIG9wdGlvbnM/OiBJQXhpc09wdGlvbnMsXG4gICAgLyoqIGFuIGF4aXMgbWF5IGJlIGhpZGRlbiBpZiBpdCBpcyBqdXN0IGJlaW5nIHVzZWQgdG8gc2NhbGUgdGhlIGRhdGEgKi9cbiAgICBoaWRkZW4/OiBib29sZWFuO1xuICAgIC8qKiBhbnkgc3BlY2lhbCBDU1MgdG8gaGFyZGNvZGUgZm9yIHRoaXMgYXhpcyAqL1xuICAgIGNzcz86IElDc3M7XG59XG5cbi8qKiBBbiBheGlzIHRoYXQgaGFzIGJlZW4gcmVuZGVyICovXG5leHBvcnQgaW50ZXJmYWNlIElSZW5kZXJlZEF4aXMge1xuICAgIC8qKiByZXR1cm5zIGEgZnVuY3Rpb24gdGhhdCBjb252ZXJ0cyBhIHZhbHVlIGludG8gdGhlIHBpeGVsIHNjYWxlZCB2YWx1ZSAqL1xuICAgIGdldFNjYWxlKCk6ICh2YWx1ZTogYW55KSA9PiBudW1iZXI7XG5cbiAgICAvKiogcmV0dXJucyB0aGUgbnVtYmVyIG9mIHBpeGVscyBmb3IgdGhpcyBheGlzICovXG4gICAgZ2V0UmFuZ2VQaXhlbHMoKTogbnVtYmVyO1xufSJdLCJtYXBwaW5ncyI6Ijs7QUEyQkE7Ozs7QUFJQTtBQUNBO0FBQUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTsiLCJzb3VyY2VSb290IjoiIn0=\n//# sourceURL=webpack-internal:///./src/interface/chart/axis.ts\n");

/***/ }),

/***/ "d3":
/*!*********************!*\
  !*** external "d3" ***!
  \*********************/
/*! no static exports found */
/***/ (function(module, exports) {

eval("module.exports = __WEBPACK_EXTERNAL_MODULE_d3__;//# sourceURL=[module]\n//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZDMuanMiLCJzb3VyY2VzIjpbIndlYnBhY2s6Ly9VV1QvZXh0ZXJuYWwgXCJkM1wiPzQzNjMiXSwic291cmNlc0NvbnRlbnQiOlsibW9kdWxlLmV4cG9ydHMgPSBfX1dFQlBBQ0tfRVhURVJOQUxfTU9EVUxFX2QzX187Il0sIm1hcHBpbmdzIjoiQUFBQSIsInNvdXJjZVJvb3QiOiIifQ==\n//# sourceURL=webpack-internal:///d3\n");

/***/ })

/******/ });
});