ui-widget-toolkit
Version:
UI widgets built on top of D3, Pixi.js and ag-grid-community
171 lines • 240 kB
JavaScript
(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");
/***/ })
/******/ });
});